diff --git a/examples/DeobfuscatorSample.java b/examples/DeobfuscatorSample.java index ab5e3dce2..054f912ba 100644 --- a/examples/DeobfuscatorSample.java +++ b/examples/DeobfuscatorSample.java @@ -3,26 +3,44 @@ import com.jpexs.decompiler.flash.abc.ABC; import com.jpexs.decompiler.flash.abc.types.MethodBody; import com.jpexs.decompiler.flash.action.ActionList; import com.jpexs.decompiler.flash.helpers.SWFDecompilerListener; +import com.jpexs.decompiler.flash.tags.base.ASMSource; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; public class DeobfuscatorSample implements SWFDecompilerListener { @Override public byte[] proxyFileCatched(byte[] data) { + System.out.println("proxyFileCatched"); + return null; } @Override public void actionListParsed(ActionList actions, SWF swf) { + System.out.println("actionListParsed"); } @Override public void swfParsed(SWF swf) { + System.out.println("swfParsed"); + Map asms = swf.getASMs(); + for (ASMSource asm : asms.values()) { + try { + asm.getActions(); + } catch (InterruptedException ex) { + Logger.getLogger(DeobfuscatorSample.class.getName()).log(Level.SEVERE, null, ex); + } + } } @Override public void abcParsed(ABC abc, SWF swf) { + System.out.println("abcParsed"); } @Override public void methodBodyParsed(MethodBody body, SWF swf) { + System.out.println("methodBodyParsed"); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/AppResources.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/AppResources.java index 495332285..c738fe511 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/AppResources.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/AppResources.java @@ -24,7 +24,7 @@ import java.util.ResourceBundle; */ public class AppResources { - private static final ResourceBundle resourceBundle = ResourceBundle.getBundle("com.jpexs.decompiler.flash.gui.locales.AppResources"); + private static final ResourceBundle resourceBundle = ResourceBundle.getBundle("com.jpexs.decompiler.flash.locales.AppResources"); public static String translate(String key) { return resourceBundle.getString(key); 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 3da716237..5ff5d6bdd 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java @@ -1185,6 +1185,31 @@ public final class SWF implements TreeItem, Timelined { return ret; } + public Map getASMs() { + List list = createASTagList(tags, this); + Map asms = new HashMap<>(); + getASMs("", list, asms); + return asms; + } + + private static void getASMs(String path, List nodes, Map result) { + for (TreeNode n : nodes) { + String subPath = path + "/" + n.toString(); + if (n.getItem() instanceof ASMSource) { + //cacheScript((ASMSource) n.tag); + String npath = subPath; + int ppos = 1; + while (result.containsKey(npath)) { + ppos++; + npath = subPath + "[" + ppos + "]"; + } + result.put(npath, (ASMSource) n.getItem()); + } + + getASMs(subPath, n.subNodes, result); + } + } + public static void getTagsFromTreeNodes(List treeNodes, List result) { for (TreeNode treeNode : treeNodes) { TreeItem treeItem = treeNode.getItem(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java index b84c5f1b9..01c8fa943 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java @@ -56,7 +56,7 @@ public class MethodBody implements Cloneable, Serializable { public ABCException[] exceptions = new ABCException[0]; public Traits traits = new Traits(); public transient List convertedItems; - public transient Exception convertException; + public transient Throwable convertException; public List getExceptionEntries() { List ret = new ArrayList<>(); @@ -152,11 +152,12 @@ public class MethodBody implements Cloneable, Serializable { } } catch (InterruptedException ex) { throw ex; - } catch (Exception ex) { + } catch (Exception | OutOfMemoryError | StackOverflowError ex) { Logger.getLogger(MethodBody.class.getName()).log(Level.SEVERE, "Decompilation error", ex); convertException = ex; - if (ex instanceof ExecutionException && ex.getCause() instanceof Exception) { - convertException = (Exception) ex.getCause(); + Throwable cause = ex.getCause(); + if (ex instanceof ExecutionException && cause instanceof Exception) { + convertException = (Exception) cause; } } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java index f03ae3b15..de250a303 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java @@ -693,11 +693,14 @@ public class Action implements GraphSourceItem { return tree; } }, timeout, TimeUnit.SECONDS); - } catch (TimeoutException | ExecutionException | OutOfMemoryError | TranslateException | StackOverflowError ex) { + } catch (InterruptedException ex) { + throw ex; + } catch (Exception | OutOfMemoryError | StackOverflowError ex) { Logger.getLogger(Action.class.getName()).log(Level.SEVERE, "Decompilation error in: " + path, ex); convertException = ex; - if (ex instanceof ExecutionException && ex.getCause() instanceof Exception) { - convertException = (Exception) ex.getCause(); + Throwable cause = ex.getCause(); + if (ex instanceof ExecutionException && cause instanceof Exception) { + convertException = cause; } } writer.continueMeasure(); diff --git a/src/com/jpexs/browsers/cache/firefox/MapBucket.java b/src/com/jpexs/browsers/cache/firefox/MapBucket.java index eca12d867..3ebd29c00 100644 --- a/src/com/jpexs/browsers/cache/firefox/MapBucket.java +++ b/src/com/jpexs/browsers/cache/firefox/MapBucket.java @@ -1,129 +1,128 @@ -/* - * Copyright (C) 2010-2014 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.browsers.cache.firefox; - -import com.jpexs.browsers.cache.CacheEntry; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.RandomAccessFile; -import java.util.HashMap; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author JPEXS - */ -public class MapBucket extends CacheEntry { - - public long hash; - public long enviction; - public Location dataLocation; - public Location metadataLocation; - private MetaData metadata; - - public MapBucket(InputStream is, File rootDir, Map dataFiles) throws IOException { - CacheInputStream cis = new CacheInputStream(is); - hash = cis.readInt32(); - enviction = cis.readInt32(); - dataLocation = new Location(cis.readInt32(), false, hash, rootDir, dataFiles); - metadataLocation = new Location(cis.readInt32(), true, hash, rootDir, dataFiles); - } - - public InputStream getMetaDataStream() throws IOException { - return metadataLocation.getInputStream(); - } - - public MetaData getMetaData() { - if (metadata == null) { - try { - metadata = new MetaData(getMetaDataStream()); - } catch (IncompatibleVersionException ie) { - } catch (IOException ex) { - Logger.getLogger(MapBucket.class.getName()).log(Level.SEVERE, null, ex); - } - } - return metadata; - } - - @Override - public String getRequestURL() { - String req = null; - MetaData m = getMetaData(); - if (m == null) { - return null; - } - req = m.request; - if (req == null) { - return null; - } - if (req.startsWith("HTTP:")) { - req = req.substring("HTTP:".length()); - } - return req; - } - - @Override - public Map getResponseHeaders() { - MetaData m = getMetaData(); - if (m == null) { - return null; - } - String responseHead = m.response.get("response-head"); - if (responseHead == null) { - return null; - } - String headers[] = responseHead.split("\r\n"); - Map ret = new HashMap<>(); - for (int h = 1; h < headers.length; h++) { - String hs = headers[h]; - if (hs.contains(":")) { - String hp[] = hs.split(":"); - ret.put(hp[0].trim(), hp[1].trim()); - } - } - return ret; - } - - @Override - public String getStatusLine() { - MetaData m = getMetaData(); - if (m == null) { - return null; - } - String responseHead = m.response.get("response-head"); - String headers[] = responseHead.split("\r\n"); - return headers[0]; - } - - @Override - public String getRequestMethod() { - return "GET"; //No POST caching in Firefox - } - - @Override - public InputStream getResponseRawDataStream() { - try { - return dataLocation.getInputStream(); - } catch (IOException ex) { - Logger.getLogger(MapBucket.class.getName()).log(Level.SEVERE, null, ex); - } - return null; - } -} +/* + * Copyright (C) 2010-2014 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.browsers.cache.firefox; + +import com.jpexs.browsers.cache.CacheEntry; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.RandomAccessFile; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + */ +public class MapBucket extends CacheEntry { + + public long hash; + public long enviction; + public Location dataLocation; + public Location metadataLocation; + private MetaData metadata; + + public MapBucket(InputStream is, File rootDir, Map dataFiles) throws IOException { + CacheInputStream cis = new CacheInputStream(is); + hash = cis.readInt32(); + enviction = cis.readInt32(); + dataLocation = new Location(cis.readInt32(), false, hash, rootDir, dataFiles); + metadataLocation = new Location(cis.readInt32(), true, hash, rootDir, dataFiles); + } + + public InputStream getMetaDataStream() throws IOException { + return metadataLocation.getInputStream(); + } + + public MetaData getMetaData() { + if (metadata == null) { + try { + metadata = new MetaData(getMetaDataStream()); + } catch (IncompatibleVersionException ie) { + } catch (IOException ex) { + Logger.getLogger(MapBucket.class.getName()).log(Level.SEVERE, null, ex); + } + } + return metadata; + } + + @Override + public String getRequestURL() { + MetaData m = getMetaData(); + if (m == null) { + return null; + } + String req = m.request; + if (req == null) { + return null; + } + if (req.startsWith("HTTP:")) { + req = req.substring("HTTP:".length()); + } + return req; + } + + @Override + public Map getResponseHeaders() { + MetaData m = getMetaData(); + if (m == null) { + return null; + } + String responseHead = m.response.get("response-head"); + if (responseHead == null) { + return null; + } + String headers[] = responseHead.split("\r\n"); + Map ret = new HashMap<>(); + for (int h = 1; h < headers.length; h++) { + String hs = headers[h]; + if (hs.contains(":")) { + String hp[] = hs.split(":"); + ret.put(hp[0].trim(), hp[1].trim()); + } + } + return ret; + } + + @Override + public String getStatusLine() { + MetaData m = getMetaData(); + if (m == null) { + return null; + } + String responseHead = m.response.get("response-head"); + String headers[] = responseHead.split("\r\n"); + return headers[0]; + } + + @Override + public String getRequestMethod() { + return "GET"; //No POST caching in Firefox + } + + @Override + public InputStream getResponseRawDataStream() { + try { + return dataLocation.getInputStream(); + } catch (IOException ex) { + Logger.getLogger(MapBucket.class.getName()).log(Level.SEVERE, null, ex); + } + return null; + } +} diff --git a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java index ca86dd206..ecb62361e 100644 --- a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java +++ b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java @@ -990,7 +990,6 @@ public class CommandLineArgumentParser { } } catch (OutOfMemoryError | Exception ex) { - exportOK = false; System.err.print("FAIL: Exporting Failed on Exception - "); Logger.getLogger(CommandLineArgumentParser.class.getName()).log(Level.SEVERE, null, ex); System.exit(1); diff --git a/src/com/jpexs/decompiler/flash/console/ConsoleAbortRetryIgnoreHandler.java b/src/com/jpexs/decompiler/flash/console/ConsoleAbortRetryIgnoreHandler.java index 75a0d7d17..f8ed144ee 100644 --- a/src/com/jpexs/decompiler/flash/console/ConsoleAbortRetryIgnoreHandler.java +++ b/src/com/jpexs/decompiler/flash/console/ConsoleAbortRetryIgnoreHandler.java @@ -1,71 +1,70 @@ -/* - * Copyright (C) 2010-2014 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.console; - -import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; -import java.util.Scanner; - -/** - * - * @author JPEXS - */ -public class ConsoleAbortRetryIgnoreHandler implements AbortRetryIgnoreHandler { - - int errorCount = 0; - int errorMode; - int retryCount; - - public ConsoleAbortRetryIgnoreHandler(int errorMode, int retryCount) { - this.errorMode = errorMode; - this.retryCount = retryCount; - } - - @Override - public int handle(Throwable thrown) { - if (errorMode != AbortRetryIgnoreHandler.UNDEFINED) { - int result = errorMode; - - if (errorMode == AbortRetryIgnoreHandler.RETRY && errorCount < retryCount) { - errorCount++; - } else { - result = AbortRetryIgnoreHandler.IGNORE; - } - - return result; - } - Scanner sc = new Scanner(System.in); - System.out.println("Error occured: " + thrown.getLocalizedMessage()); - String n = null; - do { - System.out.print("Select action: (A)bort, (R)Retry, (I)Ignore:"); - n = sc.nextLine(); - switch (n.toLowerCase()) { - case "a": - return AbortRetryIgnoreHandler.ABORT; - case "r": - return AbortRetryIgnoreHandler.RETRY; - case "i": - return AbortRetryIgnoreHandler.IGNORE; - } - } while (true); - } - - @Override - public AbortRetryIgnoreHandler getNewInstance() { - return new ConsoleAbortRetryIgnoreHandler(errorMode, retryCount); - } -} +/* + * Copyright (C) 2010-2014 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.console; + +import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; +import java.util.Scanner; + +/** + * + * @author JPEXS + */ +public class ConsoleAbortRetryIgnoreHandler implements AbortRetryIgnoreHandler { + + int errorCount = 0; + int errorMode; + int retryCount; + + public ConsoleAbortRetryIgnoreHandler(int errorMode, int retryCount) { + this.errorMode = errorMode; + this.retryCount = retryCount; + } + + @Override + public int handle(Throwable thrown) { + if (errorMode != AbortRetryIgnoreHandler.UNDEFINED) { + int result = errorMode; + + if (errorMode == AbortRetryIgnoreHandler.RETRY && errorCount < retryCount) { + errorCount++; + } else { + result = AbortRetryIgnoreHandler.IGNORE; + } + + return result; + } + Scanner sc = new Scanner(System.in); + System.out.println("Error occured: " + thrown.getLocalizedMessage()); + do { + System.out.print("Select action: (A)bort, (R)Retry, (I)Ignore:"); + String n = sc.nextLine(); + switch (n.toLowerCase()) { + case "a": + return AbortRetryIgnoreHandler.ABORT; + case "r": + return AbortRetryIgnoreHandler.RETRY; + case "i": + return AbortRetryIgnoreHandler.IGNORE; + } + } while (true); + } + + @Override + public AbortRetryIgnoreHandler getNewInstance() { + return new ConsoleAbortRetryIgnoreHandler(errorMode, retryCount); + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/GenericTagPanel.java b/src/com/jpexs/decompiler/flash/gui/GenericTagPanel.java index 72f287493..7627f438b 100644 --- a/src/com/jpexs/decompiler/flash/gui/GenericTagPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/GenericTagPanel.java @@ -1,588 +1,588 @@ -/* - * Copyright (C) 2010-2014 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.gui.generictageditors.BooleanEditor; -import com.jpexs.decompiler.flash.gui.generictageditors.ChangeListener; -import com.jpexs.decompiler.flash.gui.generictageditors.ColorEditor; -import com.jpexs.decompiler.flash.gui.generictageditors.GenericTagEditor; -import com.jpexs.decompiler.flash.gui.generictageditors.NumberEditor; -import com.jpexs.decompiler.flash.gui.generictageditors.ReflectionTools; -import com.jpexs.decompiler.flash.gui.generictageditors.StringEditor; -import com.jpexs.decompiler.flash.gui.helpers.SpringUtilities; -import com.jpexs.decompiler.flash.tags.Tag; -import com.jpexs.decompiler.flash.types.ARGB; -import com.jpexs.decompiler.flash.types.RGB; -import com.jpexs.decompiler.flash.types.RGBA; -import com.jpexs.decompiler.flash.types.annotations.Calculated; -import com.jpexs.decompiler.flash.types.annotations.Conditional; -import com.jpexs.decompiler.flash.types.annotations.Internal; -import com.jpexs.decompiler.flash.types.annotations.Multiline; -import com.jpexs.decompiler.flash.types.annotations.Optional; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.decompiler.flash.types.annotations.parser.ConditionEvaluator; -import com.jpexs.decompiler.flash.types.annotations.parser.ParseException; -import com.jpexs.helpers.Helper; -import java.awt.BorderLayout; -import java.awt.Component; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.lang.reflect.Array; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.swing.JButton; -import javax.swing.JEditorPane; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JScrollBar; -import javax.swing.JScrollPane; -import javax.swing.SpringLayout; - -/** - * Old Generic Tag editor - * - * @author JPEXS - */ -public class GenericTagPanel extends JPanel implements ChangeListener { - - private final JEditorPane genericTagPropertiesEditorPane; - private final JPanel genericTagPropertiesEditPanel; - private final JScrollPane genericTagPropertiesEditorPaneScrollPanel; - private final JScrollPane genericTagPropertiesEditPanelScrollPanel; - private Tag tag; - private Tag editedTag; - - private List keys = new ArrayList<>(); - private Map editors = new HashMap<>(); - private Map labels = new HashMap<>(); - private Map types = new HashMap<>(); - private Map> fieldPaths = new HashMap<>(); - private Map> fieldIndices = new HashMap<>(); - private HeaderLabel hdr; - private Set addKeys = new HashSet<>(); - private Map addButtons = new HashMap<>(); - private Map removeButtons = new HashMap<>(); - - public GenericTagPanel() { - super(new BorderLayout()); - - hdr = new HeaderLabel(""); - add(hdr, BorderLayout.NORTH); - genericTagPropertiesEditorPane = new JEditorPane() { - @Override - public boolean getScrollableTracksViewportWidth() { - return true; - } - }; - genericTagPropertiesEditorPane.setEditable(false); - genericTagPropertiesEditorPaneScrollPanel = new JScrollPane(genericTagPropertiesEditorPane); - add(genericTagPropertiesEditorPaneScrollPanel, BorderLayout.CENTER); - - genericTagPropertiesEditPanel = new JPanel(); - genericTagPropertiesEditPanel.setLayout(new SpringLayout()); - JPanel edPanel = new JPanel(new BorderLayout()); - edPanel.add(genericTagPropertiesEditPanel, BorderLayout.NORTH); - genericTagPropertiesEditPanelScrollPanel = new JScrollPane(edPanel); - } - - public void clear() { - editors.clear(); - fieldPaths.clear(); - fieldIndices.clear(); - labels.clear(); - types.clear(); - keys.clear(); - addKeys.clear(); - addButtons.clear(); - removeButtons.clear(); - genericTagPropertiesEditPanel.removeAll(); - genericTagPropertiesEditPanel.setSize(0, 0); - } - - public void setEditMode(boolean edit, Tag tag) { - if (tag == null) { - tag = this.tag; - } - - this.tag = tag; - this.editedTag = Helper.deepCopy(tag); - generateEditControls(editedTag, !edit); - - if (edit) { - remove(genericTagPropertiesEditorPaneScrollPanel); - add(genericTagPropertiesEditPanelScrollPanel, BorderLayout.CENTER); - } else { - genericTagPropertiesEditPanel.removeAll(); - genericTagPropertiesEditPanel.setSize(0, 0); - remove(genericTagPropertiesEditPanelScrollPanel); - add(genericTagPropertiesEditorPaneScrollPanel, BorderLayout.CENTER); - setTagText(this.tag); - } - revalidate(); - repaint(); - } - - private void setTagText(Tag tag) { - clear(); - generateEditControls(tag, true); - String val = ""; - for (String key : keys) { - GenericTagEditor ed = editors.get(key); - if (((Component) ed).isVisible()) { - val += key + " : " + ed.getReadOnlyValue() + "
"; - } - } - //HTML for colors: - val = "" + val + ""; - genericTagPropertiesEditorPane.setContentType("text/html"); - genericTagPropertiesEditorPane.setText(val); - genericTagPropertiesEditorPane.setCaretPosition(0); - hdr.setText(tag.toString()); - } - - private void generateEditControls(Tag tag, boolean readonly) { - clear(); - generateEditControlsRecursive(tag, "", new ArrayList(), new ArrayList(), readonly); - change(null); - } - - private void relayout(int propCount) { - //Lay out the panel. - SpringUtilities.makeCompactGrid(genericTagPropertiesEditPanel, - propCount, 3, //rows, cols - 6, 6, //initX, initY - 6, 6); //xPad, yPad - revalidate(); - repaint(); - } - - private int generateEditControlsRecursive(final Object obj, String parent, List parentFields, List parentIndices, boolean readonly) { - if (obj == null) { - return 0; - } - Field[] fields = obj.getClass().getDeclaredFields(); - int propCount = 0; - for (final Field field : fields) { - try { - if (Modifier.isStatic(field.getModifiers())) { - continue; - } - field.setAccessible(true); - String name = parent + field.getName(); - final Object value = field.get(obj); - if (List.class.isAssignableFrom(field.getType())) { - if (value != null) { - int i = 0; - for (Object obj1 : (Iterable) value) { - final String subname = name + "[" + i + "]"; - propCount += addEditor(subname, obj, field, i, obj1.getClass(), obj1, parentFields, parentIndices, readonly); - final int fi = i; - i++; - JButton removeButton = new JButton(View.getIcon("close16")); - removeButton.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - removeItem(obj, field, fi); - } - }); - removeButtons.put(subname, removeButton); - } - } - } else if (field.getType().isArray()) { - if (value != null) { - for (int i = 0; i < Array.getLength(value); i++) { - Object item = Array.get(value, i); - String subname = name + "[" + i + "]"; - propCount += addEditor(subname, obj, field, i, item.getClass(), item, parentFields, parentIndices, readonly); - final int fi = i; - JButton removeButton = new JButton(View.getIcon("close16")); - removeButton.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - removeItem(obj, field, fi); - } - }); - removeButtons.put(subname, removeButton); - } - } - } else { - propCount += addEditor(name, obj, field, 0, field.getType(), value, parentFields, parentIndices, readonly); - } - if (ReflectionTools.needsIndex(field) && !readonly && !field.getName().equals("clipActionRecords")) { //No clip actions, sorry - JButton addButton = new JButton(View.getIcon("add16")); - addButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - addItem(obj, field); - } - }); - name += "[]"; - - List parList = new ArrayList<>(parentFields); - parList.add(field); - fieldPaths.put(name, parList); - - List parIndices = new ArrayList<>(parentIndices); - parIndices.add(0); - fieldIndices.put(name, parIndices); - - addRow(name, addButton, field); - addKeys.add(name); - addButtons.put(name, addButton); - } - } catch (IllegalArgumentException | IllegalAccessException ex) { - Logger.getLogger(GenericTagPanel.class.getName()).log(Level.SEVERE, null, ex); - } - } - return propCount; - } - - private void removeItem(Object obj, Field field, int index) { - final JScrollBar sb = genericTagPropertiesEditPanelScrollPanel.getVerticalScrollBar(); - final int val = sb.getValue(); //save scroll top - SWFType swfType = field.getAnnotation(SWFType.class); - if (swfType != null && !swfType.countField().isEmpty()) { //Fields with same countField must be removed from too - Field fields[] = obj.getClass().getDeclaredFields(); - for (int f = 0; f < fields.length; f++) { - SWFType fieldSwfType = fields[f].getAnnotation(SWFType.class); - if (fieldSwfType != null && fieldSwfType.countField().equals(swfType.countField())) { - ReflectionTools.removeFromField(obj, fields[f], index); - } - } - try { - //If countField exists, decrement, otherwise do nothing - Field countField = obj.getClass().getDeclaredField(swfType.countField()); - if (countField != null) { - int cnt = countField.getInt(obj); - cnt--; - countField.setInt(obj, cnt); - } - } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException ex) { - //ignored - } - } else { - ReflectionTools.removeFromField(obj, field, index); - } - - generateEditControls(editedTag, false); - - //Restore scroll top after some time. TODO: Handle this better. I don't know how :-(. - new Thread() { - - @Override - public void run() { - try { - Thread.sleep(500); - } catch (InterruptedException ex) { - Logger.getLogger(GenericTagPanel.class.getName()).log(Level.SEVERE, null, ex); - } - View.execInEventDispatch(new Runnable() { - @Override - public void run() { - genericTagPropertiesEditPanelScrollPanel.getVerticalScrollBar().setValue(val); - } - }); - } - - }.start(); - revalidate(); - repaint(); - } - - private void addItem(Object obj, Field field) { - final JScrollBar sb = genericTagPropertiesEditPanelScrollPanel.getVerticalScrollBar(); - final int val = sb.getValue(); //save scroll top - SWFType swfType = field.getAnnotation(SWFType.class); - if (swfType != null && !swfType.countField().isEmpty()) { //Fields with same countField must be enlarged too - Field fields[] = obj.getClass().getDeclaredFields(); - for (int f = 0; f < fields.length; f++) { - SWFType fieldSwfType = fields[f].getAnnotation(SWFType.class); - if (fieldSwfType != null && fieldSwfType.countField().equals(swfType.countField())) { - ReflectionTools.addToField(obj, fields[f], ReflectionTools.getFieldSubSize(obj, fields[f]), true); - } - } - try { - //If countField exists, increment, otherwise do nothing - Field countField = obj.getClass().getDeclaredField(swfType.countField()); - if (countField != null) { - int cnt = countField.getInt(obj); - cnt++; - countField.setInt(obj, cnt); - } - } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException ex) { - //ignored - } - } else { - ReflectionTools.addToField(obj, field, ReflectionTools.getFieldSubSize(obj, field), true); - } - generateEditControls(editedTag, false); - - //Restore scroll top after some time. TODO: Handle this better. I don't know how :-(. - new Thread() { - - @Override - public void run() { - try { - Thread.sleep(500); - } catch (InterruptedException ex) { - Logger.getLogger(GenericTagPanel.class.getName()).log(Level.SEVERE, null, ex); - } - View.execInEventDispatch(new Runnable() { - @Override - public void run() { - genericTagPropertiesEditPanelScrollPanel.getVerticalScrollBar().setValue(val); - } - }); - } - - }.start(); - revalidate(); - repaint(); - } - - private int addEditor(String name, Object obj, Field field, int index, Class type, Object value, List parentList, List parentIndices, boolean readonly) throws IllegalArgumentException, IllegalAccessException { - Calculated calculated = field.getAnnotation(Calculated.class); - if (calculated != null) { - return 0; - } - List parList = new ArrayList<>(parentList); - parList.add(field); - - List parIndices = new ArrayList<>(parentIndices); - parIndices.add(index); - Internal inter = field.getAnnotation(Internal.class); - if (inter != null) { - return 0; - } - SWFType swfType = field.getAnnotation(SWFType.class); - Multiline multiline = field.getAnnotation(Multiline.class); - Component editor; - if (type.equals(int.class) || type.equals(Integer.class) - || type.equals(short.class) || type.equals(Short.class) - || type.equals(long.class) || type.equals(Long.class) - || type.equals(double.class) || type.equals(Double.class) - || type.equals(float.class) || type.equals(Float.class)) { - editor = new NumberEditor(name, obj, field, index, type, swfType); - } else if (type.equals(boolean.class) || type.equals(Boolean.class)) { - editor = new BooleanEditor(name, obj, field, index, type); - } else if (type.equals(String.class)) { - editor = new StringEditor(name, obj, field, index, type, multiline != null); - } else if (type.equals(RGB.class) || type.equals(RGBA.class) || type.equals(ARGB.class)) { - editor = new ColorEditor(name, obj, field, index, type); - } else { - if (value == null) { - if (readonly) { - return 0; - } - Optional opt = field.getAnnotation(Optional.class); - if (opt == null) { - try { - value = ReflectionTools.newInstanceOf(field.getType()); - field.set(obj, value); - } catch (InstantiationException | IllegalAccessException ex) { - Logger.getLogger(GenericTagPanel.class.getName()).log(Level.SEVERE, null, ex); - return 0; - } - } else { - return 0; - } - } - return generateEditControlsRecursive(value, name + ".", parList, parIndices, readonly); - } - if (editor instanceof GenericTagEditor) { - GenericTagEditor ce = (GenericTagEditor) editor; - ce.addChangeListener(this); - editors.put(name, ce); - fieldPaths.put(name, parList); - fieldIndices.put(name, parIndices); - addRow(name, editor, field); - } - return 1; - } - - private void addRow(String name, Component editor, Field field) { - JLabel label = new JLabel(name + ":", JLabel.TRAILING); - label.setVerticalAlignment(JLabel.TOP); - genericTagPropertiesEditPanel.add(label); - label.setLabelFor(editor); - labels.put(name, label); - genericTagPropertiesEditPanel.add(editor); - JLabel typeLabel = new JLabel(swfTypeToString(field.getAnnotation(SWFType.class)), JLabel.TRAILING); - typeLabel.setVerticalAlignment(JLabel.TOP); - genericTagPropertiesEditPanel.add(typeLabel); - types.put(name, typeLabel); - keys.add(name); - } - - public String swfTypeToString(SWFType swfType) { - if (swfType == null) { - return null; - } - String result = swfType.value().toString(); - if (swfType.count() > 0) { - result += "[" + swfType.count(); - if (swfType.countAdd() > 0) { - result += " + " + swfType.countAdd(); - } - result += "]"; - } else if (!swfType.countField().isEmpty()) { - result += "[" + swfType.countField(); - if (swfType.countAdd() > 0) { - result += " + " + swfType.countAdd(); - } - result += "]"; - } - return result; - } - - private void assignTag(Tag t, Tag assigned) { - if (t.getClass() != assigned.getClass()) { - return; - } - for (Field f : t.getClass().getDeclaredFields()) { - if ((f.getModifiers() & Modifier.FINAL) == Modifier.FINAL) { - continue; - } - if ((f.getModifiers() & Modifier.STATIC) == Modifier.STATIC) { - continue; - } - try { - f.set(t, f.get(assigned)); - } catch (IllegalArgumentException | IllegalAccessException ex) { - Logger.getLogger(GenericTagPanel.class.getName()).log(Level.SEVERE, null, ex); - } - } - } - - public void save() { - for (Object component : genericTagPropertiesEditPanel.getComponents()) { - if (component instanceof GenericTagEditor) { - ((GenericTagEditor) component).save(); - } - } - SWF swf = tag.getSwf(); - assignTag(tag, editedTag); - tag.setModified(true); - tag.setSwf(swf); - setTagText(tag); - } - - public Tag getTag() { - return tag; - } - - @Override - public void change(GenericTagEditor ed) { - for (String key : editors.keySet()) { - GenericTagEditor dependentEditor = editors.get(key); - Component dependentLabel = labels.get(key); - Component dependentTypeLabel = types.get(key); - List path = fieldPaths.get(key); - List indices = fieldIndices.get(key); - String p = ""; - boolean conditionMet = true; - for (int i = 0; i < path.size(); i++) { - Field f = path.get(i); - int index = indices.get(i); - String par = p; - if (!p.isEmpty()) { - p += "."; - } - p += f.getName(); - if (ReflectionTools.needsIndex(f)) { - p += "[" + index + "]"; - } - Conditional cond = f.getAnnotation(Conditional.class); - if (cond != null) { - ConditionEvaluator ev = new ConditionEvaluator(cond); - - try { - Set fieldNames = ev.getFields(); - Map fields = new HashMap<>(); - for (String fld : fieldNames) { - String ckey = ""; - if (!par.isEmpty()) { - ckey = par + "."; - } - ckey += fld; - if (editors.containsKey(ckey)) { - GenericTagEditor editor = editors.get(ckey); - Object val = editor.getChangedValue(); - fields.put(fld, true); - if (val instanceof Boolean) { - fields.put(fld, (Boolean) val); - } - } - } - boolean ok = ev.eval(fields); - if (conditionMet) { - conditionMet = ok; - } - ((Component) dependentEditor).setVisible(conditionMet); - dependentLabel.setVisible(conditionMet); - dependentTypeLabel.setVisible(conditionMet); - } catch (ParseException ex) { - Logger.getLogger(GenericTagPanel.class.getName()).log(Level.SEVERE, "Invalid condition", ex); - } - } - if (!conditionMet) { - break; - } - } - } - genericTagPropertiesEditPanel.removeAll(); - genericTagPropertiesEditPanel.setSize(0, 0); - int propCount = 0; - for (String key : keys) { - - Component dependentEditor = null; - if (addKeys.contains(key)) { - dependentEditor = addButtons.get(key); - } else if (removeButtons.containsKey(key)) { //It's array/list, add remove button - JPanel editRemPanel = new JPanel(new BorderLayout()); - editRemPanel.add((Component) editors.get(key), BorderLayout.CENTER); - editRemPanel.add(removeButtons.get(key), BorderLayout.EAST); - dependentEditor = editRemPanel; - } else { - dependentEditor = (Component) editors.get(key); - } - Component dependentLabel = labels.get(key); - Component dependentTypeLabel = types.get(key); - if (dependentEditor.isVisible()) { - genericTagPropertiesEditPanel.add(dependentLabel); - genericTagPropertiesEditPanel.add(((Component) dependentEditor)); - genericTagPropertiesEditPanel.add(dependentTypeLabel); - propCount++; - } - } - /*genericTagPropertiesEditPanel.add(new JPanel()); - genericTagPropertiesEditPanel.add(new JPanel()); - genericTagPropertiesEditPanel.add(new JPanel());*/ - relayout(propCount /*+ 1*/); - } -} +/* + * Copyright (C) 2010-2014 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.gui.generictageditors.BooleanEditor; +import com.jpexs.decompiler.flash.gui.generictageditors.ChangeListener; +import com.jpexs.decompiler.flash.gui.generictageditors.ColorEditor; +import com.jpexs.decompiler.flash.gui.generictageditors.GenericTagEditor; +import com.jpexs.decompiler.flash.gui.generictageditors.NumberEditor; +import com.jpexs.decompiler.flash.gui.generictageditors.ReflectionTools; +import com.jpexs.decompiler.flash.gui.generictageditors.StringEditor; +import com.jpexs.decompiler.flash.gui.helpers.SpringUtilities; +import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.types.ARGB; +import com.jpexs.decompiler.flash.types.RGB; +import com.jpexs.decompiler.flash.types.RGBA; +import com.jpexs.decompiler.flash.types.annotations.Calculated; +import com.jpexs.decompiler.flash.types.annotations.Conditional; +import com.jpexs.decompiler.flash.types.annotations.Internal; +import com.jpexs.decompiler.flash.types.annotations.Multiline; +import com.jpexs.decompiler.flash.types.annotations.Optional; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.decompiler.flash.types.annotations.parser.ConditionEvaluator; +import com.jpexs.decompiler.flash.types.annotations.parser.ParseException; +import com.jpexs.helpers.Helper; +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.JButton; +import javax.swing.JEditorPane; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollBar; +import javax.swing.JScrollPane; +import javax.swing.SpringLayout; + +/** + * Old Generic Tag editor + * + * @author JPEXS + */ +public class GenericTagPanel extends JPanel implements ChangeListener { + + private final JEditorPane genericTagPropertiesEditorPane; + private final JPanel genericTagPropertiesEditPanel; + private final JScrollPane genericTagPropertiesEditorPaneScrollPanel; + private final JScrollPane genericTagPropertiesEditPanelScrollPanel; + private Tag tag; + private Tag editedTag; + + private List keys = new ArrayList<>(); + private Map editors = new HashMap<>(); + private Map labels = new HashMap<>(); + private Map types = new HashMap<>(); + private Map> fieldPaths = new HashMap<>(); + private Map> fieldIndices = new HashMap<>(); + private HeaderLabel hdr; + private Set addKeys = new HashSet<>(); + private Map addButtons = new HashMap<>(); + private Map removeButtons = new HashMap<>(); + + public GenericTagPanel() { + super(new BorderLayout()); + + hdr = new HeaderLabel(""); + add(hdr, BorderLayout.NORTH); + genericTagPropertiesEditorPane = new JEditorPane() { + @Override + public boolean getScrollableTracksViewportWidth() { + return true; + } + }; + genericTagPropertiesEditorPane.setEditable(false); + genericTagPropertiesEditorPaneScrollPanel = new JScrollPane(genericTagPropertiesEditorPane); + add(genericTagPropertiesEditorPaneScrollPanel, BorderLayout.CENTER); + + genericTagPropertiesEditPanel = new JPanel(); + genericTagPropertiesEditPanel.setLayout(new SpringLayout()); + JPanel edPanel = new JPanel(new BorderLayout()); + edPanel.add(genericTagPropertiesEditPanel, BorderLayout.NORTH); + genericTagPropertiesEditPanelScrollPanel = new JScrollPane(edPanel); + } + + public void clear() { + editors.clear(); + fieldPaths.clear(); + fieldIndices.clear(); + labels.clear(); + types.clear(); + keys.clear(); + addKeys.clear(); + addButtons.clear(); + removeButtons.clear(); + genericTagPropertiesEditPanel.removeAll(); + genericTagPropertiesEditPanel.setSize(0, 0); + } + + public void setEditMode(boolean edit, Tag tag) { + if (tag == null) { + tag = this.tag; + } + + this.tag = tag; + this.editedTag = Helper.deepCopy(tag); + generateEditControls(editedTag, !edit); + + if (edit) { + remove(genericTagPropertiesEditorPaneScrollPanel); + add(genericTagPropertiesEditPanelScrollPanel, BorderLayout.CENTER); + } else { + genericTagPropertiesEditPanel.removeAll(); + genericTagPropertiesEditPanel.setSize(0, 0); + remove(genericTagPropertiesEditPanelScrollPanel); + add(genericTagPropertiesEditorPaneScrollPanel, BorderLayout.CENTER); + setTagText(this.tag); + } + revalidate(); + repaint(); + } + + private void setTagText(Tag tag) { + clear(); + generateEditControls(tag, true); + String val = ""; + for (String key : keys) { + GenericTagEditor ed = editors.get(key); + if (((Component) ed).isVisible()) { + val += key + " : " + ed.getReadOnlyValue() + "
"; + } + } + //HTML for colors: + val = "" + val + ""; + genericTagPropertiesEditorPane.setContentType("text/html"); + genericTagPropertiesEditorPane.setText(val); + genericTagPropertiesEditorPane.setCaretPosition(0); + hdr.setText(tag.toString()); + } + + private void generateEditControls(Tag tag, boolean readonly) { + clear(); + generateEditControlsRecursive(tag, "", new ArrayList(), new ArrayList(), readonly); + change(null); + } + + private void relayout(int propCount) { + //Lay out the panel. + SpringUtilities.makeCompactGrid(genericTagPropertiesEditPanel, + propCount, 3, //rows, cols + 6, 6, //initX, initY + 6, 6); //xPad, yPad + revalidate(); + repaint(); + } + + private int generateEditControlsRecursive(final Object obj, String parent, List parentFields, List parentIndices, boolean readonly) { + if (obj == null) { + return 0; + } + Field[] fields = obj.getClass().getDeclaredFields(); + int propCount = 0; + for (final Field field : fields) { + try { + if (Modifier.isStatic(field.getModifiers())) { + continue; + } + field.setAccessible(true); + String name = parent + field.getName(); + final Object value = field.get(obj); + if (List.class.isAssignableFrom(field.getType())) { + if (value != null) { + int i = 0; + for (Object obj1 : (Iterable) value) { + final String subname = name + "[" + i + "]"; + propCount += addEditor(subname, obj, field, i, obj1.getClass(), obj1, parentFields, parentIndices, readonly); + final int fi = i; + i++; + JButton removeButton = new JButton(View.getIcon("close16")); + removeButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + removeItem(obj, field, fi); + } + }); + removeButtons.put(subname, removeButton); + } + } + } else if (field.getType().isArray()) { + if (value != null) { + for (int i = 0; i < Array.getLength(value); i++) { + Object item = Array.get(value, i); + String subname = name + "[" + i + "]"; + propCount += addEditor(subname, obj, field, i, item.getClass(), item, parentFields, parentIndices, readonly); + final int fi = i; + JButton removeButton = new JButton(View.getIcon("close16")); + removeButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + removeItem(obj, field, fi); + } + }); + removeButtons.put(subname, removeButton); + } + } + } else { + propCount += addEditor(name, obj, field, 0, field.getType(), value, parentFields, parentIndices, readonly); + } + if (ReflectionTools.needsIndex(field) && !readonly && !field.getName().equals("clipActionRecords")) { //No clip actions, sorry + JButton addButton = new JButton(View.getIcon("add16")); + addButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + addItem(obj, field); + } + }); + name += "[]"; + + List parList = new ArrayList<>(parentFields); + parList.add(field); + fieldPaths.put(name, parList); + + List parIndices = new ArrayList<>(parentIndices); + parIndices.add(0); + fieldIndices.put(name, parIndices); + + addRow(name, addButton, field); + addKeys.add(name); + addButtons.put(name, addButton); + } + } catch (IllegalArgumentException | IllegalAccessException ex) { + Logger.getLogger(GenericTagPanel.class.getName()).log(Level.SEVERE, null, ex); + } + } + return propCount; + } + + private void removeItem(Object obj, Field field, int index) { + final JScrollBar sb = genericTagPropertiesEditPanelScrollPanel.getVerticalScrollBar(); + final int val = sb.getValue(); //save scroll top + SWFType swfType = field.getAnnotation(SWFType.class); + if (swfType != null && !swfType.countField().isEmpty()) { //Fields with same countField must be removed from too + Field fields[] = obj.getClass().getDeclaredFields(); + for (int f = 0; f < fields.length; f++) { + SWFType fieldSwfType = fields[f].getAnnotation(SWFType.class); + if (fieldSwfType != null && fieldSwfType.countField().equals(swfType.countField())) { + ReflectionTools.removeFromField(obj, fields[f], index); + } + } + try { + //If countField exists, decrement, otherwise do nothing + Field countField = obj.getClass().getDeclaredField(swfType.countField()); + if (countField != null) { + int cnt = countField.getInt(obj); + cnt--; + countField.setInt(obj, cnt); + } + } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException ex) { + //ignored + } + } else { + ReflectionTools.removeFromField(obj, field, index); + } + + generateEditControls(editedTag, false); + + //Restore scroll top after some time. TODO: Handle this better. I don't know how :-(. + new Thread() { + + @Override + public void run() { + try { + Thread.sleep(500); + } catch (InterruptedException ex) { + Logger.getLogger(GenericTagPanel.class.getName()).log(Level.SEVERE, null, ex); + } + View.execInEventDispatch(new Runnable() { + @Override + public void run() { + genericTagPropertiesEditPanelScrollPanel.getVerticalScrollBar().setValue(val); + } + }); + } + + }.start(); + revalidate(); + repaint(); + } + + private void addItem(Object obj, Field field) { + final JScrollBar sb = genericTagPropertiesEditPanelScrollPanel.getVerticalScrollBar(); + final int val = sb.getValue(); //save scroll top + SWFType swfType = field.getAnnotation(SWFType.class); + if (swfType != null && !swfType.countField().isEmpty()) { //Fields with same countField must be enlarged too + Field fields[] = obj.getClass().getDeclaredFields(); + for (int f = 0; f < fields.length; f++) { + SWFType fieldSwfType = fields[f].getAnnotation(SWFType.class); + if (fieldSwfType != null && fieldSwfType.countField().equals(swfType.countField())) { + ReflectionTools.addToField(obj, fields[f], ReflectionTools.getFieldSubSize(obj, fields[f]), true); + } + } + try { + //If countField exists, increment, otherwise do nothing + Field countField = obj.getClass().getDeclaredField(swfType.countField()); + if (countField != null) { + int cnt = countField.getInt(obj); + cnt++; + countField.setInt(obj, cnt); + } + } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException ex) { + //ignored + } + } else { + ReflectionTools.addToField(obj, field, ReflectionTools.getFieldSubSize(obj, field), true); + } + generateEditControls(editedTag, false); + + //Restore scroll top after some time. TODO: Handle this better. I don't know how :-(. + new Thread() { + + @Override + public void run() { + try { + Thread.sleep(500); + } catch (InterruptedException ex) { + Logger.getLogger(GenericTagPanel.class.getName()).log(Level.SEVERE, null, ex); + } + View.execInEventDispatch(new Runnable() { + @Override + public void run() { + genericTagPropertiesEditPanelScrollPanel.getVerticalScrollBar().setValue(val); + } + }); + } + + }.start(); + revalidate(); + repaint(); + } + + private int addEditor(String name, Object obj, Field field, int index, Class type, Object value, List parentList, List parentIndices, boolean readonly) throws IllegalArgumentException, IllegalAccessException { + Calculated calculated = field.getAnnotation(Calculated.class); + if (calculated != null) { + return 0; + } + List parList = new ArrayList<>(parentList); + parList.add(field); + + List parIndices = new ArrayList<>(parentIndices); + parIndices.add(index); + Internal inter = field.getAnnotation(Internal.class); + if (inter != null) { + return 0; + } + SWFType swfType = field.getAnnotation(SWFType.class); + Multiline multiline = field.getAnnotation(Multiline.class); + Component editor; + if (type.equals(int.class) || type.equals(Integer.class) + || type.equals(short.class) || type.equals(Short.class) + || type.equals(long.class) || type.equals(Long.class) + || type.equals(double.class) || type.equals(Double.class) + || type.equals(float.class) || type.equals(Float.class)) { + editor = new NumberEditor(name, obj, field, index, type, swfType); + } else if (type.equals(boolean.class) || type.equals(Boolean.class)) { + editor = new BooleanEditor(name, obj, field, index, type); + } else if (type.equals(String.class)) { + editor = new StringEditor(name, obj, field, index, type, multiline != null); + } else if (type.equals(RGB.class) || type.equals(RGBA.class) || type.equals(ARGB.class)) { + editor = new ColorEditor(name, obj, field, index, type); + } else { + if (value == null) { + if (readonly) { + return 0; + } + Optional opt = field.getAnnotation(Optional.class); + if (opt == null) { + try { + value = ReflectionTools.newInstanceOf(field.getType()); + field.set(obj, value); + } catch (InstantiationException | IllegalAccessException ex) { + Logger.getLogger(GenericTagPanel.class.getName()).log(Level.SEVERE, null, ex); + return 0; + } + } else { + return 0; + } + } + return generateEditControlsRecursive(value, name + ".", parList, parIndices, readonly); + } + if (editor instanceof GenericTagEditor) { + GenericTagEditor ce = (GenericTagEditor) editor; + ce.addChangeListener(this); + editors.put(name, ce); + fieldPaths.put(name, parList); + fieldIndices.put(name, parIndices); + addRow(name, editor, field); + } + return 1; + } + + private void addRow(String name, Component editor, Field field) { + JLabel label = new JLabel(name + ":", JLabel.TRAILING); + label.setVerticalAlignment(JLabel.TOP); + genericTagPropertiesEditPanel.add(label); + label.setLabelFor(editor); + labels.put(name, label); + genericTagPropertiesEditPanel.add(editor); + JLabel typeLabel = new JLabel(swfTypeToString(field.getAnnotation(SWFType.class)), JLabel.TRAILING); + typeLabel.setVerticalAlignment(JLabel.TOP); + genericTagPropertiesEditPanel.add(typeLabel); + types.put(name, typeLabel); + keys.add(name); + } + + public String swfTypeToString(SWFType swfType) { + if (swfType == null) { + return null; + } + String result = swfType.value().toString(); + if (swfType.count() > 0) { + result += "[" + swfType.count(); + if (swfType.countAdd() > 0) { + result += " + " + swfType.countAdd(); + } + result += "]"; + } else if (!swfType.countField().isEmpty()) { + result += "[" + swfType.countField(); + if (swfType.countAdd() > 0) { + result += " + " + swfType.countAdd(); + } + result += "]"; + } + return result; + } + + private void assignTag(Tag t, Tag assigned) { + if (t.getClass() != assigned.getClass()) { + return; + } + for (Field f : t.getClass().getDeclaredFields()) { + if ((f.getModifiers() & Modifier.FINAL) == Modifier.FINAL) { + continue; + } + if ((f.getModifiers() & Modifier.STATIC) == Modifier.STATIC) { + continue; + } + try { + f.set(t, f.get(assigned)); + } catch (IllegalArgumentException | IllegalAccessException ex) { + Logger.getLogger(GenericTagPanel.class.getName()).log(Level.SEVERE, null, ex); + } + } + } + + public void save() { + for (Object component : genericTagPropertiesEditPanel.getComponents()) { + if (component instanceof GenericTagEditor) { + ((GenericTagEditor) component).save(); + } + } + SWF swf = tag.getSwf(); + assignTag(tag, editedTag); + tag.setModified(true); + tag.setSwf(swf); + setTagText(tag); + } + + public Tag getTag() { + return tag; + } + + @Override + public void change(GenericTagEditor ed) { + for (String key : editors.keySet()) { + GenericTagEditor dependentEditor = editors.get(key); + Component dependentLabel = labels.get(key); + Component dependentTypeLabel = types.get(key); + List path = fieldPaths.get(key); + List indices = fieldIndices.get(key); + String p = ""; + boolean conditionMet = true; + for (int i = 0; i < path.size(); i++) { + Field f = path.get(i); + int index = indices.get(i); + String par = p; + if (!p.isEmpty()) { + p += "."; + } + p += f.getName(); + if (ReflectionTools.needsIndex(f)) { + p += "[" + index + "]"; + } + Conditional cond = f.getAnnotation(Conditional.class); + if (cond != null) { + ConditionEvaluator ev = new ConditionEvaluator(cond); + + try { + Set fieldNames = ev.getFields(); + Map fields = new HashMap<>(); + for (String fld : fieldNames) { + String ckey = ""; + if (!par.isEmpty()) { + ckey = par + "."; + } + ckey += fld; + if (editors.containsKey(ckey)) { + GenericTagEditor editor = editors.get(ckey); + Object val = editor.getChangedValue(); + fields.put(fld, true); + if (val instanceof Boolean) { + fields.put(fld, (Boolean) val); + } + } + } + boolean ok = ev.eval(fields); + if (conditionMet) { + conditionMet = ok; + } + ((Component) dependentEditor).setVisible(conditionMet); + dependentLabel.setVisible(conditionMet); + dependentTypeLabel.setVisible(conditionMet); + } catch (ParseException ex) { + Logger.getLogger(GenericTagPanel.class.getName()).log(Level.SEVERE, "Invalid condition", ex); + } + } + if (!conditionMet) { + break; + } + } + } + genericTagPropertiesEditPanel.removeAll(); + genericTagPropertiesEditPanel.setSize(0, 0); + int propCount = 0; + for (String key : keys) { + + Component dependentEditor; + if (addKeys.contains(key)) { + dependentEditor = addButtons.get(key); + } else if (removeButtons.containsKey(key)) { //It's array/list, add remove button + JPanel editRemPanel = new JPanel(new BorderLayout()); + editRemPanel.add((Component) editors.get(key), BorderLayout.CENTER); + editRemPanel.add(removeButtons.get(key), BorderLayout.EAST); + dependentEditor = editRemPanel; + } else { + dependentEditor = (Component) editors.get(key); + } + Component dependentLabel = labels.get(key); + Component dependentTypeLabel = types.get(key); + if (dependentEditor.isVisible()) { + genericTagPropertiesEditPanel.add(dependentLabel); + genericTagPropertiesEditPanel.add(((Component) dependentEditor)); + genericTagPropertiesEditPanel.add(dependentTypeLabel); + propCount++; + } + } + /*genericTagPropertiesEditPanel.add(new JPanel()); + genericTagPropertiesEditPanel.add(new JPanel()); + genericTagPropertiesEditPanel.add(new JPanel());*/ + relayout(propCount /*+ 1*/); + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/ListLayout.java b/src/com/jpexs/decompiler/flash/gui/ListLayout.java index 498ef63e1..44f9a157e 100644 --- a/src/com/jpexs/decompiler/flash/gui/ListLayout.java +++ b/src/com/jpexs/decompiler/flash/gui/ListLayout.java @@ -1,103 +1,102 @@ -/* - * Copyright (C) 2010-2014 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 java.awt.Component; -import java.awt.Container; -import java.awt.Dimension; -import java.awt.Insets; -import java.awt.LayoutManager; - -/** - * - * @author JPEXS - */ -public class ListLayout implements LayoutManager { - - private int border; - - public ListLayout() { - this(5); - } - - public ListLayout(int border) { - this.border = border; - } - - @Override - public void addLayoutComponent(String name, Component comp) { - } - - @Override - public void removeLayoutComponent(Component comp) { - } - - @Override - public Dimension preferredLayoutSize(Container parent) { - int h = 0; - int maxw = 0; - Insets ins = parent.getInsets(); - boolean first = true; - for (Component c : parent.getComponents()) { - if (!c.isVisible()) { - continue; - } - if (true) { //!first) { - h += border; - } - Dimension pref = c.getPreferredSize(); - if (pref.width > maxw) { - maxw = pref.width; - } - h += pref.height; - first = false; - } - h += border; - - maxw = (parent.getSize().width == 0 ? maxw : parent.getSize().width) - ins.left - ins.right; - return new Dimension(maxw, h); - } - - @Override - public Dimension minimumLayoutSize(Container parent) { - return preferredLayoutSize(parent); - } - - @Override - public void layoutContainer(Container parent) { - Dimension dim = preferredLayoutSize(parent); - int top = 0; - Insets ins = parent.getInsets(); - top = ins.top; - boolean first = true; - for (Component c : parent.getComponents()) { - if (!c.isVisible()) { - continue; - } - if (!first) { - top += border; - } - Dimension pref = c.getPreferredSize(); - c.setPreferredSize(new Dimension(dim.width, pref.height)); - c.setMinimumSize(new Dimension(dim.width, pref.height)); - c.setBounds(0, top, dim.width, pref.height); - top += pref.height; - first = false; - } - - } -} +/* + * Copyright (C) 2010-2014 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 java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Insets; +import java.awt.LayoutManager; + +/** + * + * @author JPEXS + */ +public class ListLayout implements LayoutManager { + + private int border; + + public ListLayout() { + this(5); + } + + public ListLayout(int border) { + this.border = border; + } + + @Override + public void addLayoutComponent(String name, Component comp) { + } + + @Override + public void removeLayoutComponent(Component comp) { + } + + @Override + public Dimension preferredLayoutSize(Container parent) { + int h = 0; + int maxw = 0; + Insets ins = parent.getInsets(); + boolean first = true; + for (Component c : parent.getComponents()) { + if (!c.isVisible()) { + continue; + } + if (true) { //!first) { + h += border; + } + Dimension pref = c.getPreferredSize(); + if (pref.width > maxw) { + maxw = pref.width; + } + h += pref.height; + first = false; + } + h += border; + + maxw = (parent.getSize().width == 0 ? maxw : parent.getSize().width) - ins.left - ins.right; + return new Dimension(maxw, h); + } + + @Override + public Dimension minimumLayoutSize(Container parent) { + return preferredLayoutSize(parent); + } + + @Override + public void layoutContainer(Container parent) { + Dimension dim = preferredLayoutSize(parent); + Insets ins = parent.getInsets(); + int top = ins.top; + boolean first = true; + for (Component c : parent.getComponents()) { + if (!c.isVisible()) { + continue; + } + if (!first) { + top += border; + } + Dimension pref = c.getPreferredSize(); + c.setPreferredSize(new Dimension(dim.width, pref.height)); + c.setMinimumSize(new Dimension(dim.width, pref.height)); + c.setBounds(0, top, dim.width, pref.height); + top += pref.height; + first = false; + } + + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/LoadingPanel.java b/src/com/jpexs/decompiler/flash/gui/LoadingPanel.java index db2cece80..53563452e 100644 --- a/src/com/jpexs/decompiler/flash/gui/LoadingPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/LoadingPanel.java @@ -93,8 +93,7 @@ public class LoadingPanel extends JPanel { lastSize = size; drawTimer = new Timer(); int timeSpin = 1000; - double delay = 0; - delay = timeSpin / o; + double delay = timeSpin / o; while (delay < 10) { o--; delay = timeSpin / o; diff --git a/src/com/jpexs/decompiler/flash/gui/Main.java b/src/com/jpexs/decompiler/flash/gui/Main.java index 7693cd389..f46b35b1d 100644 --- a/src/com/jpexs/decompiler/flash/gui/Main.java +++ b/src/com/jpexs/decompiler/flash/gui/Main.java @@ -329,7 +329,7 @@ public class Main { if (mode == SaveFileMode.EXE) { InputStream exeStream = View.class.getClassLoader().getResourceAsStream("com/jpexs/helpers/resource/Swf2Exe.bin"); byte[] buffer = new byte[4096]; - int bytesRead = 0; + int bytesRead; while ((bytesRead = exeStream.read(buffer)) != -1) { fos.write(buffer, 0, bytesRead); } diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index ae03deb8b..c04f03b27 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -1255,7 +1255,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec SearchPanel textSearchPanel = previewPanel.getTextPanel().getSearchPanel(); textSearchPanel.setOptions(ignoreCase, regexp); List found = new ArrayList<>(); - Pattern pat = null; + Pattern pat; if (regexp) { pat = Pattern.compile(txt, ignoreCase ? Pattern.CASE_INSENSITIVE : 0); } else { @@ -1379,7 +1379,6 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec List flaFilters = new ArrayList<>(); List xflFilters = new ArrayList<>(); List versions = new ArrayList<>(); - FileFilter defaultFilter = null; for (int i = FLAVersion.values().length - 1; i >= 0; i--) { final FLAVersion v = FLAVersion.values()[i]; if (!swf.isAS3 && v.minASVersion() > 2) { @@ -1398,7 +1397,6 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec } }; if (v == FLAVersion.CS6) { - defaultFilter = f; fc.setFileFilter(f); } else { fc.addChoosableFileFilter(f); @@ -1419,9 +1417,6 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec xflFilters.add(f); } } - if (defaultFilter == null) { - defaultFilter = flaFilters.get(0); - } fc.setAcceptAllFileFilterUsed(false); JFrame f = new JFrame(); @@ -2302,7 +2297,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec final Tag tag = (Tag) tagObj; showCard(CARDPREVIEWPANEL); DrawableTag d = (DrawableTag) tag; - Timelined timelined = null; + Timelined timelined; if (tagObj instanceof Timelined && !(tagObj instanceof ButtonTag)) { timelined = (Timelined) tag; } else { diff --git a/src/com/jpexs/decompiler/flash/gui/PreviewImage.java b/src/com/jpexs/decompiler/flash/gui/PreviewImage.java index 4bfd708ee..0e00cf22a 100644 --- a/src/com/jpexs/decompiler/flash/gui/PreviewImage.java +++ b/src/com/jpexs/decompiler/flash/gui/PreviewImage.java @@ -169,7 +169,6 @@ public class PreviewImage extends JPanel { private Image renderImage(SWF swf, TreeItem treeItem) { - double scale = 1; int width = 0; int height = 0; SerializableImage imgSrc = null; @@ -206,7 +205,7 @@ public class PreviewImage extends JPanel { w = w2; } - scale = (double) w / (double) w1; + double scale = (double) w / (double) w1; if (w1 <= w2 && h1 <= h2) { scale = 1; } diff --git a/src/com/jpexs/decompiler/flash/gui/SoundTagPlayer.java b/src/com/jpexs/decompiler/flash/gui/SoundTagPlayer.java index 56df898a8..10a047d90 100644 --- a/src/com/jpexs/decompiler/flash/gui/SoundTagPlayer.java +++ b/src/com/jpexs/decompiler/flash/gui/SoundTagPlayer.java @@ -131,7 +131,7 @@ public class SoundTagPlayer implements MediaDisplay { public void run() { boolean playAgain = true; while (playAgain) { - int startPos = 0; + int startPos; synchronized (playLock) { startPos = actualPos * FRAME_DIVISOR; } diff --git a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java index eee52ffbc..7b8a5fb07 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java @@ -759,7 +759,7 @@ public class ABCPanel extends JPanel implements ItemListener, ActionListener, Se View.navigateUrl(adobePage); - int ret = 0; + int ret; do { ret = View.showConfirmDialog(this, AppStrings.translate("message.action.playerglobal.place").replace("%libpath%", Configuration.getFlashLibPath().getAbsolutePath()), AppStrings.translate("message.action.playerglobal.title"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE); swc = Configuration.getPlayerSWC(); diff --git a/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java b/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java index 498dabad1..9d7024534 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java @@ -459,7 +459,6 @@ public class DecompiledEditorPane extends LineMarkedEditorPane implements CaretL public void cacheScriptPack(ScriptPack scriptLeaf, List abcList) throws InterruptedException { int maxCacheSize = 50; int scriptIndex = scriptLeaf.scriptIndex; - HilightedText hilightedCode = null; ScriptInfo script = null; ABC abc = scriptLeaf.abc; if (scriptIndex > -1) { @@ -469,7 +468,7 @@ public class DecompiledEditorPane extends LineMarkedEditorPane implements CaretL boolean parallel = Configuration.parallelSpeedUp.get(); HilightedTextWriter writer = new HilightedTextWriter(Configuration.getCodeFormatting(), true); scriptLeaf.toSource(writer, abcList, script.traits.traits, ScriptExportMode.AS, parallel); - hilightedCode = new HilightedText(writer); + HilightedText hilightedCode = new HilightedText(writer); cache.put(scriptLeaf, new CachedDecompilation(hilightedCode)); } } diff --git a/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java b/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java index f404af8c6..ea92a2070 100644 --- a/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java @@ -200,33 +200,13 @@ public class ActionPanel extends JPanel implements ActionListener, SearchListene } } - private void getASMs(String path, List nodes, Map result) { - for (TreeNode n : nodes) { - String subPath = path + "/" + n.toString(); - if (n.getItem() instanceof ASMSource) { - //cacheScript((ASMSource) n.tag); - String npath = subPath; - int ppos = 1; - while (result.containsKey(npath)) { - ppos++; - npath = subPath + "[" + ppos + "]"; - } - result.put(npath, (ASMSource) n.getItem()); - } - - getASMs(subPath, n.subNodes, result); - } - } - public boolean search(final String txt, boolean ignoreCase, boolean regexp) { if ((txt != null) && (!txt.isEmpty())) { searchPanel.setOptions(ignoreCase, regexp); SWF swf = mainPanel.getCurrentSwf(); - List list = SWF.createASTagList(swf.tags, swf); - Map asms = new HashMap<>(); - getASMs("", list, asms); + Map asms = swf.getASMs(); final List found = new ArrayList<>(); - Pattern pat = null; + Pattern pat; if (regexp) { pat = Pattern.compile(txt, ignoreCase ? Pattern.CASE_INSENSITIVE : 0); } else { diff --git a/src/com/jpexs/process/win32/Win32ProcessTools.java b/src/com/jpexs/process/win32/Win32ProcessTools.java index a51d129ef..4248e2339 100644 --- a/src/com/jpexs/process/win32/Win32ProcessTools.java +++ b/src/com/jpexs/process/win32/Win32ProcessTools.java @@ -386,7 +386,6 @@ public class Win32ProcessTools extends ProcessTools { } long actualPos = 0; - byte[] prevBytes = new byte[0]; List guardedPages = new ArrayList<>(); for (int pg = 0; pg < pages.size(); pg++) { MEMORY_BASIC_INFORMATION mbi = pages.get(pg); @@ -408,7 +407,7 @@ public class Win32ProcessTools extends ProcessTools { byte[] data = buf.getByteArray(0, bytesReadRef.getValue().intValue()); - prevBytes = Arrays.copyOfRange(data, data.length - maxFindLen, data.length); + byte[] prevBytes = Arrays.copyOfRange(data, data.length - maxFindLen, data.length); byte[] dataPlusPrev = mergeArrays(prevBytes, data); loopi: for (int i = 0; i < dataPlusPrev.length - maxFindLen; i++) {