From 887c42caca5d6ace9f20cd3de400b3b4fa3180b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=F8=EDk?= Date: Sat, 22 Feb 2014 13:56:12 +0100 Subject: [PATCH] Generic tag editor as tree --- trunk/src/com/jpexs/decompiler/flash/SWF.java | 12 +- .../decompiler/flash/gui/GenericTagPanel.java | 16 +- .../flash/gui/GenericTagTreePanel.java | 713 ++++++++++++++++++ .../jpexs/decompiler/flash/gui/MainPanel.java | 79 +- .../com/jpexs/decompiler/flash/gui/View.java | 65 ++ .../gui/generictageditors/NumberEditor.java | 22 +- .../generictageditors/ReflectionTools.java | 62 +- .../gui/generictageditors/StringEditor.java | 21 +- .../flash/gui/helpers/SpringUtilities.java | 5 +- .../flash/gui/locales/MainFrame.properties | 10 +- .../flash/gui/locales/MainFrame_cs.properties | 8 + .../flash/tags/DefineButtonSoundTag.java | 1 - .../flash/tags/DefineFontAlignZonesTag.java | 2 + .../tags/DefineSceneAndFrameLabelDataTag.java | 11 +- .../flash/tags/ExportAssetsTag.java | 7 +- .../flash/tags/FileAttributesTag.java | 10 +- .../flash/tags/ImportAssets2Tag.java | 22 +- .../flash/tags/ImportAssetsTag.java | 22 +- .../decompiler/flash/tags/SymbolClassTag.java | 24 +- .../com/jpexs/decompiler/flash/tags/Tag.java | 6 + .../decompiler/flash/tags/base/ImportTag.java | 1 - .../decompiler/flash/types/TEXTRECORD.java | 2 + .../decompiler/flash/types/ZONERECORD.java | 2 + .../flash/types/annotations/SWFArray.java | 41 + .../parser/ConditionEvaluator.java | 2 - .../decompiler/flash/xfl/XFLConverter.java | 6 +- 26 files changed, 1023 insertions(+), 149 deletions(-) create mode 100644 trunk/src/com/jpexs/decompiler/flash/gui/GenericTagTreePanel.java create mode 100644 trunk/src/com/jpexs/decompiler/flash/types/annotations/SWFArray.java diff --git a/trunk/src/com/jpexs/decompiler/flash/SWF.java b/trunk/src/com/jpexs/decompiler/flash/SWF.java index af2233c76..f1a6f4ce5 100644 --- a/trunk/src/com/jpexs/decompiler/flash/SWF.java +++ b/trunk/src/com/jpexs/decompiler/flash/SWF.java @@ -510,9 +510,9 @@ public final class SWF implements TreeItem { for (Tag t : tags) { if (t instanceof SymbolClassTag) { SymbolClassTag sct = (SymbolClassTag) t; - for (int i = 0; i < sct.tagIDs.length; i++) { - if ((!classes.containsKey(sct.tagIDs[i])) && (!classes.containsValue(sct.classNames[i]))) { - classes.put(sct.tagIDs[i], sct.classNames[i]); + for (int i = 0; i < sct.tags.length; i++) { + if ((!classes.containsKey(sct.tags[i])) && (!classes.containsValue(sct.names[i]))) { + classes.put(sct.tags[i], sct.names[i]); } } } @@ -1793,10 +1793,10 @@ public final class SWF implements TreeItem { for (Tag tag : tags) { if (tag instanceof SymbolClassTag) { SymbolClassTag sc = (SymbolClassTag) tag; - for (int i = 0; i < sc.classNames.length; i++) { - String newname = deobfuscation.deobfuscateNameWithPackage(sc.classNames[i], deobfuscated, renameType, deobfuscated); + for (int i = 0; i < sc.names.length; i++) { + String newname = deobfuscation.deobfuscateNameWithPackage(sc.names[i], deobfuscated, renameType, deobfuscated); if (newname != null) { - sc.classNames[i] = newname; + sc.names[i] = newname; } } } diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/GenericTagPanel.java b/trunk/src/com/jpexs/decompiler/flash/gui/GenericTagPanel.java index c0ccef2e5..3b5d5ed12 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/GenericTagPanel.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/GenericTagPanel.java @@ -40,17 +40,12 @@ 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.FlowLayout; -import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.awt.event.AdjustmentEvent; -import java.awt.event.AdjustmentListener; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -58,7 +53,6 @@ import java.util.Map; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; -import javax.swing.Box; import javax.swing.JButton; import javax.swing.JEditorPane; import javax.swing.JLabel; @@ -66,10 +60,9 @@ import javax.swing.JPanel; import javax.swing.JScrollBar; import javax.swing.JScrollPane; import javax.swing.SpringLayout; -import javax.swing.SwingUtilities; /** - * + * Old Generic Tag editor * @author JPEXS */ public class GenericTagPanel extends JPanel implements ChangeListener { @@ -330,7 +323,7 @@ public class GenericTagPanel extends JPanel implements ChangeListener { for (int f = 0; f < fields.length; f++) { SWFType fieldSwfType = fields[f].getAnnotation(SWFType.class); if (fieldSwfType != null && fieldSwfType.countField().equals(swfType.countField())) { - ReflectionTools.enlargeField(obj, fields[f], true); + ReflectionTools.addToField(obj, fields[f], ReflectionTools.getFieldSubSize(obj, fields[f]),true); } } try { @@ -345,7 +338,7 @@ public class GenericTagPanel extends JPanel implements ChangeListener { //ignored } } else { - ReflectionTools.enlargeField(obj, field, true); + ReflectionTools.addToField(obj, field,ReflectionTools.getFieldSubSize(obj, field), true); } generateEditControls(editedTag, false); @@ -478,9 +471,6 @@ public class GenericTagPanel extends JPanel implements ChangeListener { if((f.getModifiers()&Modifier.STATIC) == Modifier.STATIC){ continue; } - if(f.getName().equals("ID")){ - continue; - } try { f.set(t, f.get(assigned)); } catch (IllegalArgumentException | IllegalAccessException ex) { diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/GenericTagTreePanel.java b/trunk/src/com/jpexs/decompiler/flash/gui/GenericTagTreePanel.java new file mode 100644 index 000000000..ae33d5ce0 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/gui/GenericTagTreePanel.java @@ -0,0 +1,713 @@ +/* + * Copyright (C) 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.AppStrings; +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.gui.generictageditors.BooleanEditor; +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.tags.Tag; +import com.jpexs.decompiler.flash.types.ARGB; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.RGB; +import com.jpexs.decompiler.flash.types.RGBA; +import com.jpexs.decompiler.flash.types.annotations.Internal; +import com.jpexs.decompiler.flash.types.annotations.Multiline; +import com.jpexs.decompiler.flash.types.annotations.SWFArray; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.Helper; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Graphics; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.EventObject; +import java.util.List; +import java.util.Objects; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.AbstractCellEditor; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JTree; +import javax.swing.event.TreeModelListener; +import javax.swing.plaf.basic.BasicLabelUI; +import javax.swing.plaf.basic.BasicTreeUI; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeCellEditor; +import javax.swing.tree.TreeModel; +import javax.swing.tree.TreePath; + +/** + * + * @author JPEXS + */ +public class GenericTagTreePanel extends GenericTagPanel { + + private JTree tree; + private Tag editedTag; + + private class MyTree extends JTree { + + public MyTree() { + setBackground(Color.white); + setUI(new BasicTreeUI() { + + @Override + public void paint(Graphics g, JComponent c) { + setHashColor(Color.gray); + super.paint(g, c); + } + + }); + setCellRenderer(new MyTreeCellRenderer()); + setCellEditor(new MyTreeCellEditor(this)); + setInvokesStopCellEditing(true); + + } + } + + private class MyTreeCellEditor extends AbstractCellEditor implements TreeCellEditor { + + private GenericTagEditor editor = null; + private JTree tree; + + public MyTreeCellEditor(JTree tree) { + this.tree = tree; + } + + @Override + public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row) { + if (value instanceof FieldNode) { + FieldNode fnode = (FieldNode) value; + Field field = fnode.field; + int index = fnode.index; + Object obj = fnode.obj; + Class type; + try { + type = ReflectionTools.getValue(obj, field, index).getClass(); + } catch (IllegalArgumentException | IllegalAccessException ex) { + ex.printStackTrace(); + return null; + } + SWFType swfType = field.getAnnotation(SWFType.class); + Multiline multiline = field.getAnnotation(Multiline.class); + 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(field.getName(), obj, field, index, type, swfType); + } else if (type.equals(boolean.class) || type.equals(Boolean.class)) { + editor = new BooleanEditor(field.getName(), obj, field, index, type); + } else if (type.equals(String.class)) { + editor = new StringEditor(field.getName(), obj, field, index, type, multiline != null); + } else if (type.equals(RGB.class) || type.equals(RGBA.class) || type.equals(ARGB.class)) { + editor = new ColorEditor(field.getName(), obj, field, index, type); + } + JPanel pan = new JPanel(); + FlowLayout fl = new FlowLayout(FlowLayout.LEFT, 0, 0); + fl.setAlignOnBaseline(true); + pan.setLayout(fl); + JLabel nameLabel = new JLabel(fnode.getNameType() + " = ") { + + @Override + public BaselineResizeBehavior getBaselineResizeBehavior() { + return Component.BaselineResizeBehavior.CONSTANT_ASCENT; + } + + @Override + public int getBaseline(int width, int height) { + return 0; + } + + }; + pan.setBackground(Color.white); + nameLabel.setSize(nameLabel.getWidth(), ((Component) editor).getHeight()); + nameLabel.setAlignmentY(TOP_ALIGNMENT); + ((JComponent) editor).setAlignmentY(TOP_ALIGNMENT); + pan.add(nameLabel); + pan.add((Component) editor); + pan.setPreferredSize(new Dimension((int) nameLabel.getPreferredSize().getWidth() + 5 + (int) ((Component) editor).getPreferredSize().getWidth(), (int) ((Component) editor).getPreferredSize().getHeight())); + return pan; + } + return null; + + } + + @Override + public Object getCellEditorValue() { + return editor.getChangedValue(); + } + + @Override + public boolean isCellEditable(EventObject e) { + if (!(e instanceof MouseEvent)) { + return false; + } + + MouseEvent me = (MouseEvent) e; + TreePath path = tree.getPathForLocation(me.getX(), me.getY()); + + if (path == null) { + return false; + } + Object obj = path.getLastPathComponent(); + + boolean ret = super.isCellEditable(e) + && path != null && (tree.getModel().isLeaf(obj)); + return ret; + } + + @Override + public boolean stopCellEditing() { + super.stopCellEditing(); + editor.save(); + ((MyTreeModel)tree.getModel()).vchanged(tree.getSelectionPath()); + return true; + } + + } + + public GenericTagTreePanel() { + setLayout(new BorderLayout()); + tree = new MyTree(); + + add(tree, BorderLayout.CENTER); + tree.addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + if (!tree.isEditable()) { + return; + } + int selRow = tree.getRowForLocation(e.getX(), e.getY()); + TreePath selPath = tree.getPathForLocation(e.getX(), e.getY()); + if (selRow != -1 && selPath != null) { + if (e.getClickCount() == 1) { + if (e.getButton() == MouseEvent.BUTTON3) { //right click + Object selObject = selPath.getLastPathComponent(); + if (selObject instanceof FieldNode) { + final FieldNode fnode = (FieldNode) selObject; + SWFArray swfArray = fnode.field.getAnnotation(SWFArray.class); + String itemStr = ""; + if(swfArray!=null){ + itemStr = swfArray.value(); + } + if(itemStr.equals("")){ + itemStr = AppStrings.translate("generictag.array.item"); + } + if (ReflectionTools.needsIndex(fnode.field)) { + JPopupMenu p = new JPopupMenu(); + JMenuItem mi; + mi = new JMenuItem(AppStrings.translate("generictag.array.insertbeginning").replace("%item%", itemStr)); + mi.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + addItem(fnode.obj, fnode.field, 0); + } + }); + p.add(mi); + + if (fnode.index > -1) { + mi = new JMenuItem(AppStrings.translate("generictag.array.insertbefore").replace("%item%", itemStr)); + mi.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + addItem(fnode.obj, fnode.field, fnode.index); + } + }); + p.add(mi); + + mi = new JMenuItem(AppStrings.translate("generictag.array.remove").replace("%item%", itemStr)); + mi.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + removeItem(fnode.obj, fnode.field, fnode.index); + } + }); + p.add(mi); + + mi = new JMenuItem(AppStrings.translate("generictag.array.insertafter").replace("%item%", itemStr)); + mi.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + addItem(fnode.obj, fnode.field, fnode.index + 1); + } + }); + p.add(mi); + } + + mi = new JMenuItem(AppStrings.translate("generictag.array.insertend").replace("%item%", itemStr)); + mi.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + addItem(fnode.obj, fnode.field, ReflectionTools.getFieldSubSize(fnode.obj, fnode.field)); + } + }); + p.add(mi); + //} + p.show(tree, e.getX(), e.getY()); + } + } + } + } else if (e.getClickCount() == 2) { + //myDoubleClick(selRow, selPath); + } + } + } + }); + } + + private Tag tag; + + public class MyTreeCellRenderer extends DefaultTreeCellRenderer { + + @Override + public Component getTreeCellRendererComponent( + JTree tree, + Object value, + boolean sel, + boolean expanded, + boolean leaf, + int row, + boolean hasFocus) { + + super.getTreeCellRendererComponent( + tree, value, sel, + expanded, leaf, row, + hasFocus); + + setUI(new BasicLabelUI()); + setOpaque(false); + setBackgroundNonSelectionColor(Color.white); + return this; + } + + } + + public void clear() { + + } + + private static class FieldNode extends DefaultMutableTreeNode { + + private Object obj; + private Field field; + private int index; + + public FieldNode(Object obj, Field field, int index) { + this.obj = obj; + this.field = field; + this.index = index; + } + + @Override + public void setUserObject(Object userObject) { + + } + + + /* +*/ + @Override + public String toString() { + + String valStr = ""; + if (ReflectionTools.needsIndex(field) && (index == -1)) { + valStr += ""; + } else if (hasEditor(obj, field, index)) { + Object val = getValue(); + Color color = null; + String colorAdd = ""; + if(val instanceof RGB){ //Note: Can be RGBA too + color = ((RGB)val).toColor(); + } + if(val instanceof ARGB){ + color = ((ARGB)val).toColor(); + } + + if(color!=null){ + colorAdd = "● "; + } + + valStr += " = " + colorAdd + val.toString(); + } + return ""+getNameType() + valStr+""; + } + + public String getType() { + SWFType swfType = field.getAnnotation(SWFType.class); + SWFArray swfArray = field.getAnnotation(SWFArray.class); + String typeStr = null; + if ((swfType != null || swfArray!=null) && !(ReflectionTools.needsIndex(field) && (index > -1))) { + Class type = field.getType(); + if (ReflectionTools.needsIndex(field)) { + type = ReflectionTools.getFieldSubType(obj, field); + } + typeStr = swfTypeToString(type, swfType, swfArray); + } + return typeStr; + } + + public String getNameType() { + String typeStr = getType(); + return getName() + (typeStr != null ? " : " + typeStr : ""); + } + + public String getName() { + SWFArray swfArray = field.getAnnotation(SWFArray.class); + String name=""; + if(swfArray!=null){ + name = swfArray.value(); + } + return (index > -1 ? name + "[" + index + "]" : field.getName()); + } + + public Object getValue() { + try { + if (ReflectionTools.needsIndex(field) && (index == -1)) { + return obj; + } + return ReflectionTools.getValue(obj, field, index); + } catch (IllegalArgumentException | IllegalAccessException ex) { + return null; + } + } + + @Override + public int hashCode() { + int hash = 7; + hash = 11 * hash + Objects.hashCode(this.obj); + hash = 11 * hash + Objects.hashCode(this.field); + hash = 11 * hash + this.index; + return hash; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final FieldNode other = (FieldNode) obj; + if (!Objects.equals(this.obj, other.obj)) { + return false; + } + if (!Objects.equals(this.field, other.field)) { + return false; + } + if (this.index != other.index) { + return false; + } + return true; + } + + DefaultTreeModel d; + } + + private static class MyTreeModel extends DefaultTreeModel { + + private Object root; + private List listeners = new ArrayList<>(); + private DefaultMutableTreeNode rootNode; + + public MyTreeModel(Tag root) { + super(new DefaultMutableTreeNode(root)); + this.root = root; + } + + @Override + public Object getRoot() { + return root; + } + + @Override + public Object getChild(Object parent, int index) { + if (parent == root) { + return new FieldNode(root, getAvailableFields(root.getClass()).get(index), -1); + } + FieldNode fnode = (FieldNode) parent; + Field field = fnode.field; + if (ReflectionTools.needsIndex(field) && (fnode.index == -1)) { //Arrays ot Lists + return new FieldNode(fnode.obj, field, index); + } + parent = fnode.getValue(); + return new FieldNode(parent, getAvailableFields(parent.getClass()).get(index), -1); + } + + @Override + public int getChildCount(Object parent) { + if (parent == root) { + return getAvailableFields(root.getClass()).size(); + } + FieldNode fnode = (FieldNode) parent; + if (isLeaf(fnode)) { + return 0; + } + Field field = fnode.field; + if (ReflectionTools.needsIndex(field) && (fnode.index == -1)) { //Arrays ot Lists + return ReflectionTools.getFieldSubSize(fnode.obj, field); + } + parent = fnode.getValue(); + + return getAvailableFields(parent.getClass()).size(); + } + + @Override + public boolean isLeaf(Object node) { + if (node == root) { + return false; + } + + FieldNode fnode = (FieldNode) node; + Field field = fnode.field; + if (ReflectionTools.needsIndex(field) && fnode.index == -1) { + return false; + } + boolean r = hasEditor(fnode.obj, field, fnode.index); + return r; + } + + public void vchanged(TreePath path){ + fireTreeNodesChanged(this, path.getPath(), null, null); + } + + @Override + public int getIndexOfChild(Object parent, Object child) { + int cnt = getChildCount(parent); + for (int i = 0; i < cnt; i++) { + if (getChild(parent, i).equals(child)) { + return i; + } + } + return -1; + } + } + + private TreeModel getModel() { + return new MyTreeModel(editedTag); + } + + public void setEditMode(boolean edit, Tag tag) { + if (tag == null) { + tag = this.tag; + } + this.tag = tag; + this.editedTag = (Tag) Helper.deepCopy(tag); + refreshTree(); + tree.setEditable(edit); + } + + public void save() { + tree.stopEditing(); + SWF swf = tag.getSwf(); + assignTag(tag, editedTag); + tag.setModified(true); + tag.setSwf(swf); + } + + private void assignTag(Tag t, Tag assigned) { + if (t.getClass() != assigned.getClass()) { + return; + } + for (Field f : getAvailableFields(t.getClass())) { + try { + f.set(t, f.get(assigned)); + } catch (IllegalArgumentException | IllegalAccessException ex) { + Logger.getLogger(GenericTagPanel.class.getName()).log(Level.SEVERE, null, ex); + } + } + } + + public Tag getTag() { + return tag; + } + + public static String swfArrayToString(SWFArray swfArray){ + String result=""; + if(swfArray==null){ + return result; + } + if (swfArray.count() > 0) { + result += "[" + swfArray.count() + "]"; + } else if (!swfArray.countField().equals("")) { + result += "[" + swfArray.countField()+ "]"; + } + return result; + } + + public static String swfTypeToString(Class type, SWFType swfType, SWFArray swfArray) { + String stype = type.getSimpleName(); + if (swfType == null) { + return stype+swfArrayToString(swfArray); + } + String result = swfType.value().toString(); + if (swfType.value() == BasicType.OTHER) { + result = stype; + } + if (swfType.count() > 0) { + result += "[" + swfType.count(); + if (swfType.countAdd() > 0) { + result += " + " + swfType.countAdd(); + } + result += "]"; + } else if (!swfType.countField().equals("")) { + result += "[" + swfType.countField(); + if (swfType.countAdd() > 0) { + result += " + " + swfType.countAdd(); + } + result += "]"; + } + return result+swfArrayToString(swfArray); + } + + private static boolean hasEditor(Object obj, Field field, int index) { + if (ReflectionTools.needsIndex(field) && index == -1) { + return false; + } + Class type; + try { + Object val = ReflectionTools.getValue(obj, field, index); + if (val == null) { + return false; + } + type = val.getClass(); + } catch (IllegalArgumentException | IllegalAccessException ex) { + return false; + } + SWFType swfType = field.getAnnotation(SWFType.class); + Multiline multiline = field.getAnnotation(Multiline.class); + + 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)) { + return true; + } else if (type.equals(boolean.class) || type.equals(Boolean.class)) { + return true; + } else if (type.equals(String.class)) { + return true; + } else if (type.equals(RGB.class) || type.equals(RGBA.class) || type.equals(ARGB.class)) { + return true; + } else { + return false; + } + } + + private static List getAvailableFields(Class cls) { + List ret = new ArrayList<>(); + Field fields[] = cls.getFields(); + for (Field f : fields) { + if (Modifier.isStatic(f.getModifiers())) { + continue; + } + f.setAccessible(true); + Internal inter = f.getAnnotation(Internal.class); + if (inter != null) { + continue; + } + ret.add(f); + } + return ret; + } + + private void addItem(Object obj, Field field, int index) { + SWFArray swfArray = field.getAnnotation(SWFArray.class); + if (swfArray != null && !swfArray.countField().equals("")) { //Fields with same countField must be enlarged too + Field fields[] = obj.getClass().getDeclaredFields(); + for (int f = 0; f < fields.length; f++) { + SWFArray fieldSwfArray = fields[f].getAnnotation(SWFArray.class); + if (fieldSwfArray != null && fieldSwfArray.countField().equals(swfArray.countField())) { + ReflectionTools.addToField(obj, fields[f], index, true); + } + } + try { + //If countField exists, increment, otherwise do nothing + Field countField = obj.getClass().getDeclaredField(swfArray.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, index, true); + } + refreshTree(); + } + + public void refreshTree() { + View.refreshTree(tree, getModel()); + revalidate(); + repaint(); + } + + private void removeItem(Object obj, Field field, int index) { + SWFArray swfArray = field.getAnnotation(SWFArray.class); + if (swfArray != null && !swfArray.countField().equals("")) { //Fields with same countField must be removed from too + Field fields[] = obj.getClass().getDeclaredFields(); + for (int f = 0; f < fields.length; f++) { + SWFArray fieldSwfArray = fields[f].getAnnotation(SWFArray.class); + if (fieldSwfArray != null && fieldSwfArray.countField().equals(swfArray.countField())) { + ReflectionTools.removeFromField(obj, fields[f], index); + } + } + try { + //If countField exists, decrement, otherwise do nothing + Field countField = obj.getClass().getDeclaredField(swfArray.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); + } + + refreshTree(); + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/trunk/src/com/jpexs/decompiler/flash/gui/MainPanel.java index c037c62d0..3603fb680 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -16,7 +16,6 @@ */ package com.jpexs.decompiler.flash.gui; -import com.jpexs.decompiler.flash.gui.timeline.TimelineFrame; import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; import com.jpexs.decompiler.flash.AppStrings; import com.jpexs.decompiler.flash.ApplicationInfo; @@ -39,6 +38,7 @@ import com.jpexs.decompiler.flash.gui.abc.treenodes.TreeElement; import com.jpexs.decompiler.flash.gui.action.ActionPanel; import com.jpexs.decompiler.flash.gui.player.FlashPlayerPanel; import com.jpexs.decompiler.flash.gui.player.PlayerControls; +import com.jpexs.decompiler.flash.gui.timeline.TimelineFrame; import com.jpexs.decompiler.flash.gui.treenodes.SWFBundleNode; import com.jpexs.decompiler.flash.gui.treenodes.SWFNode; import com.jpexs.decompiler.flash.helpers.Freed; @@ -503,7 +503,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec private JPanel createGenericTagCard() { JPanel genericTagCard = new JPanel(new BorderLayout()); - genericTagPanel = new GenericTagPanel(); + genericTagPanel = new GenericTagTreePanel(); genericTagCard.add(genericTagPanel, BorderLayout.CENTER); genericEditButton = new JButton(translate("button.edit"), View.getIcon("edit16")); @@ -1520,9 +1520,9 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec for (Tag t : swf.tags) { if (t instanceof SymbolClassTag) { SymbolClassTag sc = (SymbolClassTag) t; - for (int i = 0; i < sc.tagIDs.length; i++) { - if (sc.tagIDs[i] == 0) { - documentClass = sc.classNames[i]; + for (int i = 0; i < sc.tags.length; i++) { + if (sc.tags[i] == 0) { + documentClass = sc.names[i]; break loopdc; } } @@ -2011,6 +2011,11 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec showCard(CARDEMPTYPANEL); refreshTree(); } + + public void refreshTree(){ + View.refreshTree(tagTree, new TagTreeModel(mainFrame, swfs)); + expandSwfNodes(); + } public void refreshDecompiled() { clearCache(); @@ -2879,16 +2884,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec showDetailWithPreview(CARDFONTPANEL); } - public void refreshTree() { - List> expandedNodes = getExpandedNodes(tagTree); - - tagTree.setModel(new TagTreeModel(mainFrame, swfs)); - - expandSwfNodes(); - expandTreeNodes(tagTree, expandedNodes); - } - - public void expandSwfNodes() { + public void expandSwfNodes() { TreeModel model = tagTree.getModel(); Object node = model.getRoot(); int childCount = model.getChildCount(node); @@ -2898,59 +2894,6 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec } } - private List> getExpandedNodes(JTree tree) { - List> expandedNodes = new ArrayList<>(); - int rowCount = tree.getRowCount(); - for (int i = 0; i < rowCount; i++) { - TreePath path = tree.getPathForRow(i); - if (tree.isExpanded(path)) { - List pathAsStringList = new ArrayList<>(); - for (Object pathCompnent : path.getPath()) { - pathAsStringList.add(pathCompnent.toString()); - } - expandedNodes.add(pathAsStringList); - } - } - return expandedNodes; - } - - private void expandTreeNodes(JTree tree, List> pathsToExpand) { - for (List pathAsStringList : pathsToExpand) { - expandTreeNode(tree, pathAsStringList); - } - } - - private void expandTreeNode(JTree tree, List pathAsStringList) { - TreeModel model = tree.getModel(); - Object node = model.getRoot(); - - if (pathAsStringList.isEmpty()) { - return; - } - if (!pathAsStringList.get(0).equals(node.toString())) { - return; - } - - List path = new ArrayList<>(); - path.add(node); - - for (int i = 1; i < pathAsStringList.size(); i++) { - String name = pathAsStringList.get(i); - int childCount = model.getChildCount(node); - for (int j = 0; j < childCount; j++) { - Object child = model.getChild(node, j); - if (child.toString().equals(name)) { - node = child; - path.add(node); - break; - } - } - } - - TreePath tp = new TreePath(path.toArray(new Object[path.size()])); - tree.expandPath(tp); - } - public void setEditText(boolean edit) { setEditText(edit, true); } diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/View.java b/trunk/src/com/jpexs/decompiler/flash/gui/View.java index 9f732c180..8dc665b1f 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/View.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/View.java @@ -30,6 +30,7 @@ import java.awt.event.KeyEvent; import java.awt.event.WindowEvent; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; +import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.AbstractAction; @@ -43,6 +44,7 @@ import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JRootPane; +import javax.swing.JTree; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import javax.swing.UIDefaults; @@ -50,6 +52,8 @@ import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.plaf.FontUIResource; import javax.swing.plaf.basic.BasicColorChooserUI; +import javax.swing.tree.TreeModel; +import javax.swing.tree.TreePath; import org.pushingpixels.flamingo.api.common.icon.ImageWrapperResizableIcon; import org.pushingpixels.substance.api.ComponentState; import org.pushingpixels.substance.api.SubstanceColorScheme; @@ -352,4 +356,65 @@ public class View { public static SubstanceColorScheme getColorScheme() { return SubstanceColorSchemeUtilities.getActiveColorScheme(new JButton(), ComponentState.ENABLED); } + + public static void refreshTree(JTree tree,TreeModel model) { + List> expandedNodes = getExpandedNodes(tree); + tree.setModel(model); + expandTreeNodes(tree, expandedNodes); + } + + + + private static List> getExpandedNodes(JTree tree) { + List> expandedNodes = new ArrayList<>(); + int rowCount = tree.getRowCount(); + for (int i = 0; i < rowCount; i++) { + TreePath path = tree.getPathForRow(i); + if (tree.isExpanded(path)) { + List pathAsStringList = new ArrayList<>(); + for (Object pathCompnent : path.getPath()) { + pathAsStringList.add(pathCompnent.toString()); + } + expandedNodes.add(pathAsStringList); + } + } + return expandedNodes; + } + + private static void expandTreeNodes(JTree tree, List> pathsToExpand) { + for (List pathAsStringList : pathsToExpand) { + expandTreeNode(tree, pathAsStringList); + } + } + + private static void expandTreeNode(JTree tree, List pathAsStringList) { + TreeModel model = tree.getModel(); + Object node = model.getRoot(); + + if (pathAsStringList.isEmpty()) { + return; + } + if (!pathAsStringList.get(0).equals(node.toString())) { + return; + } + + List path = new ArrayList<>(); + path.add(node); + + for (int i = 1; i < pathAsStringList.size(); i++) { + String name = pathAsStringList.get(i); + int childCount = model.getChildCount(node); + for (int j = 0; j < childCount; j++) { + Object child = model.getChild(node, j); + if (child.toString().equals(name)) { + node = child; + path.add(node); + break; + } + } + } + + TreePath tp = new TreePath(path.toArray(new Object[path.size()])); + tree.expandPath(tp); + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/generictageditors/NumberEditor.java b/trunk/src/com/jpexs/decompiler/flash/gui/generictageditors/NumberEditor.java index 6171651bd..4dea19c09 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/generictageditors/NumberEditor.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/generictageditors/NumberEditor.java @@ -18,12 +18,15 @@ package com.jpexs.decompiler.flash.gui.generictageditors; import com.jpexs.decompiler.flash.types.BasicType; import com.jpexs.decompiler.flash.types.annotations.SWFType; +import java.awt.Component; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.lang.reflect.Field; +import javax.swing.JFormattedTextField; import javax.swing.JSpinner; import javax.swing.SpinnerModel; import javax.swing.SpinnerNumberModel; +import javax.swing.text.DefaultFormatter; /** * @@ -38,6 +41,18 @@ public class NumberEditor extends JSpinner implements GenericTagEditor { private final SWFType swfType; private String fieldName; + @Override + public BaselineResizeBehavior getBaselineResizeBehavior() { + return Component.BaselineResizeBehavior.CONSTANT_ASCENT; + } + + @Override + public int getBaseline(int width, int height) { + return 0; + } + + + public NumberEditor(String fieldName,Object obj, Field field, int index, Class type, SWFType swfType) { setSize(100, getSize().height); setMaximumSize(getSize()); @@ -49,7 +64,10 @@ public class NumberEditor extends JSpinner implements GenericTagEditor { this.fieldName = fieldName; try { Object value = ReflectionTools.getValue(obj, field, index); - setModel(getModel(swfType, value)); + setModel(getModel(swfType, value)); + JFormattedTextField jtf = ((JSpinner.NumberEditor)getEditor()).getTextField(); + DefaultFormatter formatter = (DefaultFormatter) jtf.getFormatter(); + formatter.setCommitsOnValidEdit(true); } catch (IllegalArgumentException | IllegalAccessException ex) { // ignore } @@ -169,7 +187,7 @@ public class NumberEditor extends JSpinner implements GenericTagEditor { } @Override - public Object getChangedValue() { + public Object getChangedValue() { Object value = null; if (type.equals(int.class) || type.equals(Integer.class)) { value = Integer.parseInt(getValue().toString()); diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/generictageditors/ReflectionTools.java b/trunk/src/com/jpexs/decompiler/flash/gui/generictageditors/ReflectionTools.java index 30d257b45..dce6d4dff 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/generictageditors/ReflectionTools.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/generictageditors/ReflectionTools.java @@ -30,6 +30,9 @@ import java.util.logging.Logger; public class ReflectionTools { public static Object getValue(Object obj, Field field, int index) throws IllegalArgumentException, IllegalAccessException { + if(getFieldSubSize(obj, field)<=index){ + return null; + } Object value = field.get(obj); if (List.class.isAssignableFrom(field.getType())) { return ((List) value).get(index); @@ -50,10 +53,29 @@ public class ReflectionTools { } return false; } + + @SuppressWarnings("unchecked") + public static int getFieldSubSize(Object obj,Field field){ + Object val; + try { + val = field.get(obj); + } catch (IllegalArgumentException | IllegalAccessException ex) { + return 0; + } + if (List.class.isAssignableFrom(field.getType())) { + return ((List)val).size(); + } else if (field.getType().isArray()) { + return Array.getLength(val); + } + return 0; + } @SuppressWarnings("unchecked") public static void setValue(Object obj, Field field, int index, Object newValue) throws IllegalArgumentException, IllegalAccessException { Object value = field.get(obj); + if(needsIndex(field)&& index>=getFieldSubSize(obj, field)){ //outofbounds, ignore + return; + } if (List.class.isAssignableFrom(field.getType())) { ((List) value).set(index, newValue); } else if (field.getType().isArray()) { @@ -77,7 +99,7 @@ public class ReflectionTools { } @SuppressWarnings("unchecked") - public static boolean enlargeList(Object object, Field field) { + public static boolean addToList(Object object, Field field, int index) { if (!List.class.isAssignableFrom(field.getType())) { return false; } @@ -92,7 +114,7 @@ public class ReflectionTools { Class parameterClass = (Class) listType.getActualTypeArguments()[0]; try { Object val = newInstanceOf(parameterClass); - list.add(val); + list.add(index,val); } catch (InstantiationException | IllegalAccessException ex) { Logger.getLogger(ReflectionTools.class.getName()).log(Level.SEVERE, null, ex); return false; @@ -100,7 +122,24 @@ public class ReflectionTools { return true; } - public static boolean enlargeArray(Object object, Field field, boolean notnull) { + public static Class getFieldSubType(Object object,Field field){ + if(field.getType().isArray()){ + Object arrValue; + try { + arrValue = field.get(object); + return arrValue.getClass().getComponentType(); + } catch (IllegalArgumentException | IllegalAccessException ex) { + return null; + } + } + if(List.class.isAssignableFrom(field.getType())) { + ParameterizedType listType = (ParameterizedType) field.getGenericType(); + return (Class) listType.getActualTypeArguments()[0]; + } + return null; + } + + public static boolean addToArray(Object object, Field field, int index, boolean notnull) { if (!field.getType().isArray()) { return false; } @@ -114,17 +153,22 @@ public class ReflectionTools { Class componentClass = arrValue.getClass().getComponentType(); int originalSize = Array.getLength(arrValue); Object copy = Array.newInstance(componentClass, originalSize + 1); - for (int i = 0; i < originalSize; i++) { + //Copy items before + for (int i = 0; i < index; i++) { Array.set(copy, i, Array.get(arrValue, i)); } - if (!componentClass.isPrimitive() && notnull) { + if (!componentClass.isPrimitive()) { try { - Array.set(copy, originalSize, componentClass.newInstance()); + Array.set(copy, index, componentClass.newInstance()); } catch (InstantiationException | IllegalAccessException ex) { Logger.getLogger(ReflectionTools.class.getName()).log(Level.SEVERE, null, ex); return false; } } + //Copy items after + for (int i = index; i < originalSize ; i++) { + Array.set(copy, i+1, Array.get(arrValue, i)); + } try { field.set(object, copy); } catch (IllegalArgumentException | IllegalAccessException ex) { @@ -134,13 +178,13 @@ public class ReflectionTools { return true; } - public static boolean enlargeField(Object object, Field field, boolean notnull) { + public static boolean addToField(Object object, Field field, int index,boolean notnull) { if (List.class.isAssignableFrom(field.getType())) { - return enlargeList(object, field); + return addToList(object, field,index); } if (field.getType().isArray()) { - return enlargeArray(object, field, notnull); + return addToArray(object, field, index,notnull); } return false; } diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/generictageditors/StringEditor.java b/trunk/src/com/jpexs/decompiler/flash/gui/generictageditors/StringEditor.java index 6e7793e96..edcf45d5a 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/generictageditors/StringEditor.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/generictageditors/StringEditor.java @@ -17,12 +17,12 @@ package com.jpexs.decompiler.flash.gui.generictageditors; import com.jpexs.helpers.Helper; +import java.awt.Component; import java.awt.Dimension; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.lang.reflect.Field; import javax.swing.JTextArea; -import jsyntaxpane.util.StringUtils; /** * @@ -41,6 +41,25 @@ public class StringEditor extends JTextArea implements GenericTagEditor { public boolean getScrollableTracksViewportWidth() { return true; } + + @Override + public Dimension getPreferredSize() { + Dimension ret= super.getPreferredSize(); + ret.width = 300; + return ret; + } + + + @Override + public BaselineResizeBehavior getBaselineResizeBehavior() { + return Component.BaselineResizeBehavior.CONSTANT_ASCENT; + } + + @Override + public int getBaseline(int width, int height) { + return 0; + } + public StringEditor(String fieldName,Object obj, Field field, int index, Class type, boolean multiline) { setLineWrap(true); diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/helpers/SpringUtilities.java b/trunk/src/com/jpexs/decompiler/flash/gui/helpers/SpringUtilities.java index 6189403db..2cc3fdcb8 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/helpers/SpringUtilities.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/helpers/SpringUtilities.java @@ -30,9 +30,10 @@ */ package com.jpexs.decompiler.flash.gui.helpers; -import javax.swing.*; +import java.awt.Component; +import java.awt.Container; +import javax.swing.Spring; import javax.swing.SpringLayout; -import java.awt.*; /** * A 1.4 file that provides utility methods for creating form- or grid-style diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties b/trunk/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties index b94690741..c81d6dc14 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties +++ b/trunk/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties @@ -442,4 +442,12 @@ menu.tools.search = Text Search menu.tools.timeline = Timeline dialog.selectcolor.title = Select color -button.selectcolor.hint = Click to select color \ No newline at end of file +button.selectcolor.hint = Click to select color + +#default item name, will be used in following sentences +generictag.array.item = item +generictag.array.insertbeginning = Insert %item% at the beginning +generictag.array.insertbefore = Insert %item% before +generictag.array.remove = Remove %item% +generictag.array.insertafter = Insert %item% after +generictag.array.insertend = Insert %item% at the end \ No newline at end of file diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties b/trunk/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties index 88a87069c..d5559fd20 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties +++ b/trunk/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties @@ -445,3 +445,11 @@ menu.tools.timeline = \u010casov\u00e1 osa dialog.selectcolor.title = Vyberte barvu button.selectcolor.hint = Kliknut\u00edm vyberete barvu + +#default item name, will be used in following sentences +generictag.array.item = polo\u017eku +generictag.array.insertbeginning = Vlo\u017eit %item% na za\u010d\u00e1tek +generictag.array.insertbefore = Vlo\u017eit %item% p\u0159ed +generictag.array.remove = Odstranit %item% +generictag.array.insertafter = Vlo\u017eit %item% za +generictag.array.insertend = Vlo\u017eit %item% na konec \ No newline at end of file diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineButtonSoundTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineButtonSoundTag.java index 1914623db..9588d5543 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineButtonSoundTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineButtonSoundTag.java @@ -20,7 +20,6 @@ import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; -import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.types.BasicType; import com.jpexs.decompiler.flash.types.SOUNDINFO; import com.jpexs.decompiler.flash.types.annotations.SWFType; diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineFontAlignZonesTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineFontAlignZonesTag.java index 7f2931c6c..975cb4a7b 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineFontAlignZonesTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineFontAlignZonesTag.java @@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.types.BasicType; import com.jpexs.decompiler.flash.types.ZONERECORD; import com.jpexs.decompiler.flash.types.annotations.Reserved; +import com.jpexs.decompiler.flash.types.annotations.SWFArray; import com.jpexs.decompiler.flash.types.annotations.SWFType; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -39,6 +40,7 @@ public class DefineFontAlignZonesTag extends Tag { @Reserved @SWFType(value = BasicType.UB, count = 6) public int reserved; + @SWFArray(value="zone",countField = "glyphCount") public List zoneTable; public static final int ID = 73; diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineSceneAndFrameLabelDataTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineSceneAndFrameLabelDataTag.java index 0da758e58..1327df322 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineSceneAndFrameLabelDataTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineSceneAndFrameLabelDataTag.java @@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.annotations.SWFArray; import com.jpexs.decompiler.flash.types.annotations.SWFType; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -33,15 +34,17 @@ import java.io.OutputStream; */ public class DefineSceneAndFrameLabelDataTag extends Tag { - @SWFType(value=BasicType.EncodedU32,countField="sceneCount") + @SWFType(value=BasicType.EncodedU32) + @SWFArray(value="offset",countField="sceneCount") public long[] sceneOffsets; - @SWFType(countField="sceneCount") + @SWFArray(value="name",countField="sceneCount") public String[] sceneNames; - @SWFType(value=BasicType.EncodedU32,countField="frameLabelCount") + @SWFType(value=BasicType.EncodedU32) + @SWFArray(value="frameNum", countField="frameLabelCount") public long[] frameNums; - @SWFType(countField = "frameLabelCount") + @SWFArray(countField = "frameLabelCount") public String[] frameNames; public static final int ID = 86; diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/ExportAssetsTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/ExportAssetsTag.java index f4c1308b2..6aad7e22f 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/ExportAssetsTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/ExportAssetsTag.java @@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.annotations.SWFArray; import com.jpexs.decompiler.flash.types.annotations.SWFType; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -38,9 +39,11 @@ public class ExportAssetsTag extends Tag { /** * HashMap with assets */ - @SWFType(value = BasicType.UI16,countField = "count") + @SWFType(value = BasicType.UI16) + @SWFArray(value="tag",countField = "count") public List tags; - @SWFType(countField = "count") + + @SWFArray(value="name",countField = "count") public List names; public static final int ID = 56; diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/FileAttributesTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/FileAttributesTag.java index ce75e1bdb..4f43a2de9 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/FileAttributesTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/FileAttributesTag.java @@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.annotations.Reserved; import com.jpexs.decompiler.flash.types.annotations.SWFType; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -34,11 +35,14 @@ public class FileAttributesTag extends Tag { public boolean actionScript3; public boolean useNetwork; public boolean noCrossDomainCache; - private boolean reserved1; - private boolean reserved2; + @Reserved + public boolean reserved1; + @Reserved + public boolean reserved2; @SWFType(value = BasicType.UB, count = 24) - private int reserved3; + @Reserved + public int reserved3; public static final int ID = 69; public FileAttributesTag() { diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/ImportAssets2Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/ImportAssets2Tag.java index 0de5cfcb0..00cff8512 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/ImportAssets2Tag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/ImportAssets2Tag.java @@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.tags.base.ImportTag; import com.jpexs.decompiler.flash.types.BasicType; import com.jpexs.decompiler.flash.types.annotations.Reserved; +import com.jpexs.decompiler.flash.types.annotations.SWFArray; import com.jpexs.decompiler.flash.types.annotations.SWFType; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -49,9 +50,10 @@ public class ImportAssets2Tag extends Tag implements ImportTag { /** * HashMap with assets */ - @SWFType(value=BasicType.UI16,countField = "count") - public List characterIds; - @SWFType(countField = "count") + @SWFType(value=BasicType.UI16) + @SWFArray(value="tag",countField = "count") + public List tags; + @SWFArray(value="name",countField = "count") public List names; public static final int ID = 71; @@ -66,7 +68,7 @@ public class ImportAssets2Tag extends Tag implements ImportTag { */ public ImportAssets2Tag(SWF swf, byte[] data, int version, long pos) throws IOException { super(swf, ID, "ImportAssets2", data, pos); - characterIds = new ArrayList<>(); + tags = new ArrayList<>(); names = new ArrayList<>(); SWFInputStream sis = new SWFInputStream(new ByteArrayInputStream(data), version); url = sis.readString(); @@ -76,7 +78,7 @@ public class ImportAssets2Tag extends Tag implements ImportTag { for (int i = 0; i < count; i++) { int charId = sis.readUI16(); String tagName = sis.readString(); - characterIds.add(charId); + tags.add(charId); names.add(tagName); } } @@ -96,9 +98,9 @@ public class ImportAssets2Tag extends Tag implements ImportTag { sos.writeString(url); sos.writeUI8(reserved1); sos.writeUI8(reserved2); - sos.writeUI16(characterIds.size()); - for (int i=0;i getAssets() { Map assets = new HashMap<>(); - for (int i = 0; i < characterIds.size(); i++) { - assets.put(characterIds.get(i), names.get(i)); + for (int i = 0; i < tags.size(); i++) { + assets.put(tags.get(i), names.get(i)); } return assets; } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/ImportAssetsTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/ImportAssetsTag.java index 49289c5f5..82dcfa8de 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/ImportAssetsTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/ImportAssetsTag.java @@ -21,6 +21,7 @@ import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.tags.base.ImportTag; import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.annotations.SWFArray; import com.jpexs.decompiler.flash.types.annotations.SWFType; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -42,9 +43,10 @@ public class ImportAssetsTag extends Tag implements ImportTag { /** * HashMap with assets */ - @SWFType(value=BasicType.UI16,countField = "count") - public List characterIds; - @SWFType(countField = "count") + @SWFType(value=BasicType.UI16) + @SWFArray(value="tag",countField = "count") + public List tags; + @SWFArray(value="name",countField = "count") public List names; public static final int ID = 57; @@ -59,7 +61,7 @@ public class ImportAssetsTag extends Tag implements ImportTag { */ public ImportAssetsTag(SWF swf, byte[] data, int version, long pos) throws IOException { super(swf, ID, "ImportAssets", data, pos); - characterIds = new ArrayList<>(); + tags = new ArrayList<>(); names = new ArrayList<>(); SWFInputStream sis = new SWFInputStream(new ByteArrayInputStream(data), version); url = sis.readString(); @@ -67,7 +69,7 @@ public class ImportAssetsTag extends Tag implements ImportTag { for (int i = 0; i < count; i++) { int charId = sis.readUI16(); String tagName = sis.readString(); - characterIds.add(charId); + tags.add(charId); names.add(tagName); } } @@ -85,9 +87,9 @@ public class ImportAssetsTag extends Tag implements ImportTag { SWFOutputStream sos = new SWFOutputStream(os, version); try { sos.writeString(url); - sos.writeUI16(characterIds.size()); - for (int i = 0; i < characterIds.size(); i++) { - sos.writeUI16(characterIds.get(i)); + sos.writeUI16(tags.size()); + for (int i = 0; i < tags.size(); i++) { + sos.writeUI16(tags.get(i)); sos.writeString(names.get(i)); } } catch (IOException e) { @@ -98,8 +100,8 @@ public class ImportAssetsTag extends Tag implements ImportTag { @Override public Map getAssets() { Map assets = new HashMap<>(); - for (int i = 0; i < characterIds.size(); i++) { - assets.put(characterIds.get(i), names.get(i)); + for (int i = 0; i < tags.size(); i++) { + assets.put(tags.get(i), names.get(i)); } return assets; } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/SymbolClassTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/SymbolClassTag.java index 26a55d9b5..88c3cde4c 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/SymbolClassTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/SymbolClassTag.java @@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.annotations.SWFArray; import com.jpexs.decompiler.flash.types.annotations.SWFType; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -28,23 +29,24 @@ import java.io.OutputStream; public class SymbolClassTag extends Tag { - @SWFType(value=BasicType.UI16,countField = "numSymbols") - public int[] tagIDs; - @SWFType(countField = "numSymbols") - public String[] classNames; + @SWFType(value=BasicType.UI16) + @SWFArray(value="tag",countField = "numSymbols") + public int[] tags; + @SWFArray(value="name",countField = "numSymbols") + public String[] names; public static final int ID = 76; public SymbolClassTag(SWF swf, byte[] data, int version, long pos) throws IOException { super(swf, ID, "SymbolClass", data, pos); SWFInputStream sis = new SWFInputStream(new ByteArrayInputStream(data), version); int numSymbols = sis.readUI16(); - tagIDs = new int[numSymbols]; - classNames = new String[numSymbols]; + tags = new int[numSymbols]; + names = new String[numSymbols]; for (int ii = 0; ii < numSymbols; ii++) { int tagID = sis.readUI16(); String className = sis.readString(); - tagIDs[ii] = tagID; - classNames[ii] = className; + tags[ii] = tagID; + names[ii] = className; } } @@ -60,11 +62,11 @@ public class SymbolClassTag extends Tag { OutputStream os = baos; SWFOutputStream sos = new SWFOutputStream(os, version); try { - int numSymbols = tagIDs.length; + int numSymbols = tags.length; sos.writeUI16(numSymbols); for (int ii = 0; ii < numSymbols; ii++) { - sos.writeUI16(tagIDs[ii]); - sos.writeString(classNames[ii]); + sos.writeUI16(tags[ii]); + sos.writeString(names[ii]); } } catch (IOException e) { } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/Tag.java index a480f783f..82bdf0b65 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/Tag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/Tag.java @@ -31,6 +31,7 @@ import com.jpexs.decompiler.flash.tags.gfx.DefineGradientMap; import com.jpexs.decompiler.flash.tags.gfx.DefineSubImage; import com.jpexs.decompiler.flash.tags.gfx.ExporterInfoTag; import com.jpexs.decompiler.flash.tags.gfx.FontTextureInfo; +import com.jpexs.decompiler.flash.types.annotations.Internal; import java.io.Serializable; import java.util.Arrays; import java.util.HashMap; @@ -55,11 +56,16 @@ public class Tag implements NeedsCharacters, Exportable, ContainerItem, Serializ * If true, then Tag is written to the stream as longer than 0x3f even if it * is not */ + @Internal public boolean forceWriteAsLong = false; + @Internal private final long pos; protected String name; + @Internal public Tag previousTag; + @Internal protected transient SWF swf; + @Internal private boolean modified; public String getName() { diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/base/ImportTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/base/ImportTag.java index 358dad0c4..40a96cf27 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/base/ImportTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/base/ImportTag.java @@ -16,7 +16,6 @@ */ package com.jpexs.decompiler.flash.tags.base; -import java.util.HashMap; import java.util.Map; /** diff --git a/trunk/src/com/jpexs/decompiler/flash/types/TEXTRECORD.java b/trunk/src/com/jpexs/decompiler/flash/types/TEXTRECORD.java index c7a370270..36afeba49 100644 --- a/trunk/src/com/jpexs/decompiler/flash/types/TEXTRECORD.java +++ b/trunk/src/com/jpexs/decompiler/flash/types/TEXTRECORD.java @@ -21,6 +21,7 @@ import com.jpexs.decompiler.flash.tags.DefineTextTag; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.FontTag; import com.jpexs.decompiler.flash.types.annotations.Conditional; +import com.jpexs.decompiler.flash.types.annotations.SWFArray; import com.jpexs.decompiler.flash.types.annotations.SWFType; import java.io.Serializable; import java.util.List; @@ -58,6 +59,7 @@ public class TEXTRECORD implements Serializable { @SWFType(BasicType.UI16) public int textHeight; + @SWFArray(countField = "glyphCount") public GLYPHENTRY[] glyphEntries; public String getText(List tags, FontTag font) { diff --git a/trunk/src/com/jpexs/decompiler/flash/types/ZONERECORD.java b/trunk/src/com/jpexs/decompiler/flash/types/ZONERECORD.java index e0f291344..293abea10 100644 --- a/trunk/src/com/jpexs/decompiler/flash/types/ZONERECORD.java +++ b/trunk/src/com/jpexs/decompiler/flash/types/ZONERECORD.java @@ -16,6 +16,7 @@ */ package com.jpexs.decompiler.flash.types; +import com.jpexs.decompiler.flash.types.annotations.SWFArray; import java.io.Serializable; /** @@ -25,6 +26,7 @@ import java.io.Serializable; */ public class ZONERECORD implements Serializable{ + @SWFArray(value="zone",countField = "numZoneData") public ZONEDATA[] zonedata = new ZONEDATA[0]; public boolean zoneMaskX; public boolean zoneMaskY; diff --git a/trunk/src/com/jpexs/decompiler/flash/types/annotations/SWFArray.java b/trunk/src/com/jpexs/decompiler/flash/types/annotations/SWFArray.java new file mode 100644 index 000000000..d353e20b1 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/types/annotations/SWFArray.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 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.types.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Marks array and list fields + * + * @author JPEXS + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface SWFArray { + + /// Name of one item + String value() default ""; + + /// Number of items in array + int count() default -1; + + /// Field which means number of items in array + String countField() default ""; +} diff --git a/trunk/src/com/jpexs/decompiler/flash/types/annotations/parser/ConditionEvaluator.java b/trunk/src/com/jpexs/decompiler/flash/types/annotations/parser/ConditionEvaluator.java index 5e0c49d32..683c043b3 100644 --- a/trunk/src/com/jpexs/decompiler/flash/types/annotations/parser/ConditionEvaluator.java +++ b/trunk/src/com/jpexs/decompiler/flash/types/annotations/parser/ConditionEvaluator.java @@ -24,8 +24,6 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.Stack; -import java.util.logging.Level; -import java.util.logging.Logger; /** * diff --git a/trunk/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java b/trunk/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java index e271c9bd2..4bc5a695a 100644 --- a/trunk/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java +++ b/trunk/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java @@ -2118,9 +2118,9 @@ public class XFLConverter { for (Tag t : tags) { if (t instanceof SymbolClassTag) { SymbolClassTag sc = (SymbolClassTag) t; - for (int i = 0; i < sc.tagIDs.length; i++) { - if (!ret.containsKey(sc.tagIDs[i]) && !ret.containsValue(sc.classNames[i])) { - ret.put(sc.tagIDs[i], sc.classNames[i]); + for (int i = 0; i < sc.tags.length; i++) { + if (!ret.containsKey(sc.tags[i]) && !ret.containsValue(sc.names[i])) { + ret.put(sc.tags[i], sc.names[i]); } } }