From 1b8eab9414e6ade8e3c955f40c12527b5aaf023b Mon Sep 17 00:00:00 2001 From: "honfika@gmail.com" Date: Sat, 17 Jan 2015 21:35:58 +0100 Subject: [PATCH] import swf from XML --- .../src/com/jpexs/decompiler/flash/SWF.java | 4 +- .../flash/exporters/swf/SwfXmlExporter.java | 18 +- .../flash/importers/SwfXmlImporter.java | 262 ++++++++++++++++++ .../com/jpexs/decompiler/flash/tags/Tag.java | 94 +++++++ .../com/jpexs/helpers}/ReflectionTools.java | 2 +- .../decompiler/flash/gui/GenericTagPanel.java | 2 +- .../flash/gui/GenericTagTreePanel.java | 2 +- .../flash/gui/MainFrameRibbonMenu.java | 1 + .../jpexs/decompiler/flash/gui/MainPanel.java | 33 ++- .../gui/generictageditors/BooleanEditor.java | 1 + .../gui/generictageditors/ColorEditor.java | 1 + .../gui/generictageditors/NumberEditor.java | 1 + .../gui/generictageditors/StringEditor.java | 1 + .../flash/gui/locales/MainFrame.properties | 3 + .../flash/gui/locales/MainFrame_hu.properties | 3 + .../flash/gui/tagtree/TagTreeContextMenu.java | 8 + 16 files changed, 421 insertions(+), 15 deletions(-) create mode 100644 libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SwfXmlImporter.java rename {src/com/jpexs/decompiler/flash/gui/generictageditors => libsrc/ffdec_lib/src/com/jpexs/helpers}/ReflectionTools.java (99%) 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 368175e49..dd25c5a53 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java @@ -695,7 +695,7 @@ public final class SWF implements SWFContainerItem, Timelined { frameRate = sis.readUI8("frameRate"); frameCount = sis.readUI16("frameCount"); List tags = sis.readTagList(this, 0, parallelRead, true, !checkOnly); - if (tags.get(tags.size() - 1).getId() == EndTag.ID) { + if (tags.size() > 0 && tags.get(tags.size() - 1).getId() == EndTag.ID) { tags.remove(tags.size() - 1); } else { hasEndTag = false; @@ -2201,6 +2201,8 @@ public final class SWF implements SWFContainerItem, Timelined { } public void clearAllCache() { + characters = null; + abcList = null; clearImageCache(); clearScriptCache(); Cache.clearAll(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/swf/SwfXmlExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/swf/SwfXmlExporter.java index 2d84a9f34..b1ef08a1b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/swf/SwfXmlExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/swf/SwfXmlExporter.java @@ -92,10 +92,10 @@ public class SwfXmlExporter { } public void exportXml(SWF swf, Document doc, Node node) throws IOException { - generateXml(doc, node, "swf", swf, 0); + generateXml(doc, node, "swf", swf, false, 0); } - private static void generateXml(Document doc, Node node, String name, Object obj, int level){ + private static void generateXml(Document doc, Node node, String name, Object obj, boolean addAsChildNode, int level){ if (obj == null) { return; } @@ -117,7 +117,13 @@ public class SwfXmlExporter { value = Helper.escapeXML((String) value); } - ((Element) node).setAttribute(name, value.toString()); + if (addAsChildNode) { + Element childNode = doc.createElement(name); + childNode.setTextContent(value.toString()); + node.appendChild(childNode); + } else { + ((Element) node).setAttribute(name, value.toString()); + } } else if (cls.isEnum()) { ((Element) node).setAttribute(name, obj.toString()); } else if (obj instanceof ByteArrayRange) { @@ -134,7 +140,7 @@ public class SwfXmlExporter { Element listNode = doc.createElement(name); node.appendChild(listNode); for (int i = 0; i < list.size(); i++) { - generateXml(doc, listNode, "item", list.get(i), level + 1); + generateXml(doc, listNode, "item", list.get(i), true, level + 1); } } else if (cls.isArray()) { String arrayType = cls.getComponentType().getSimpleName(); @@ -142,7 +148,7 @@ public class SwfXmlExporter { node.appendChild(arrayNode); int length = Array.getLength(obj); for (int i = 0; i < length; i++) { - generateXml(doc, arrayNode, "item", Array.get(obj, i), level + 1); + generateXml(doc, arrayNode, "item", Array.get(obj, i), true, level + 1); } } else { if (obj instanceof LazyObject) { @@ -167,7 +173,7 @@ public class SwfXmlExporter { try { f.setAccessible(true); - generateXml(doc, objNode, f.getName(), f.get(obj), level + 1); + generateXml(doc, objNode, f.getName(), f.get(obj), false, level + 1); } catch (IllegalArgumentException | IllegalAccessException ex) { Logger.getLogger(SwfXmlExporter.class.getName()).log(Level.SEVERE, null, ex); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SwfXmlImporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SwfXmlImporter.java new file mode 100644 index 000000000..70b6e6ebb --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SwfXmlImporter.java @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.importers; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.types.ALPHABITMAPDATA; +import com.jpexs.decompiler.flash.types.ALPHACOLORMAPDATA; +import com.jpexs.decompiler.flash.types.ARGB; +import com.jpexs.decompiler.flash.types.BITMAPDATA; +import com.jpexs.decompiler.flash.types.BUTTONCONDACTION; +import com.jpexs.decompiler.flash.types.BUTTONRECORD; +import com.jpexs.decompiler.flash.types.CLIPACTIONRECORD; +import com.jpexs.decompiler.flash.types.CLIPACTIONS; +import com.jpexs.decompiler.flash.types.CLIPEVENTFLAGS; +import com.jpexs.decompiler.flash.types.COLORMAPDATA; +import com.jpexs.decompiler.flash.types.CXFORM; +import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA; +import com.jpexs.decompiler.flash.types.ColorTransform; +import com.jpexs.decompiler.flash.types.ConstantColorColorTransform; +import com.jpexs.decompiler.flash.types.FILLSTYLE; +import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY; +import com.jpexs.decompiler.flash.types.FOCALGRADIENT; +import com.jpexs.decompiler.flash.types.GLYPHENTRY; +import com.jpexs.decompiler.flash.types.GRADIENT; +import com.jpexs.decompiler.flash.types.GRADRECORD; +import com.jpexs.decompiler.flash.types.KERNINGRECORD; +import com.jpexs.decompiler.flash.types.LANGCODE; +import com.jpexs.decompiler.flash.types.LINESTYLE; +import com.jpexs.decompiler.flash.types.LINESTYLE2; +import com.jpexs.decompiler.flash.types.LINESTYLEARRAY; +import com.jpexs.decompiler.flash.types.MATRIX; +import com.jpexs.decompiler.flash.types.MORPHFILLSTYLE; +import com.jpexs.decompiler.flash.types.MORPHFILLSTYLEARRAY; +import com.jpexs.decompiler.flash.types.MORPHFOCALGRADIENT; +import com.jpexs.decompiler.flash.types.MORPHGRADIENT; +import com.jpexs.decompiler.flash.types.MORPHGRADRECORD; +import com.jpexs.decompiler.flash.types.MORPHLINESTYLE; +import com.jpexs.decompiler.flash.types.MORPHLINESTYLE2; +import com.jpexs.decompiler.flash.types.MORPHLINESTYLEARRAY; +import com.jpexs.decompiler.flash.types.PIX15; +import com.jpexs.decompiler.flash.types.PIX24; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.RGB; +import com.jpexs.decompiler.flash.types.RGBA; +import com.jpexs.decompiler.flash.types.SHAPE; +import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; +import com.jpexs.decompiler.flash.types.SOUNDENVELOPE; +import com.jpexs.decompiler.flash.types.SOUNDINFO; +import com.jpexs.decompiler.flash.types.TEXTRECORD; +import com.jpexs.decompiler.flash.types.ZONEDATA; +import com.jpexs.decompiler.flash.types.ZONERECORD; +import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord; +import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord; +import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord; +import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.ReflectionTools; +import java.io.IOException; +import java.io.StringReader; +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * + * @author JPEXS + */ +@SuppressWarnings("unchecked") +public class SwfXmlImporter { + + private Map swfTags; + private Map swfObjects; + + public void importSwf(SWF swf, String xml) throws IOException { + DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + try { + DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); + Document doc = docBuilder.parse(new InputSource(new StringReader(xml))); + processElement(doc.getDocumentElement(), swf, swf); + } catch (ParserConfigurationException | SAXException ex) { + Logger.getLogger(SwfXmlImporter.class.getName()).log(Level.SEVERE, null, ex); + } + } + + private void processElement(Element element, Object obj, SWF swf) { + Class cls = obj.getClass(); + for (int i = 0; i < element.getAttributes().getLength(); i++) { + Attr attr = (Attr) element.getAttributes().item(i); + String name = attr.getName(); + if (!name.equals("type")) { + try { + Field field = cls.getField(name); + String attrValue = attr.getValue(); + field.set(obj, getAs(field.getType(), attrValue)); + } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException ex) { + Logger.getLogger(SwfXmlImporter.class.getName()).log(Level.SEVERE, null, ex); + } + } + } + + for (int i = 0; i < element.getChildNodes().getLength(); i++) { + Node childNode = element.getChildNodes().item(i); + if (childNode instanceof Element) { + Element child = (Element) childNode; + String name = child.getTagName(); + try { + Field field = cls.getField(name); + Class childCls = field.getType(); + if (List.class.isAssignableFrom(childCls)) { + List list = new ArrayList(); + for (int j = 0; j < child.getChildNodes().getLength(); j++) { + Node childChildNode = child.getChildNodes().item(j); + if (childChildNode instanceof Element) { + Element childChild = (Element) child.getChildNodes().item(j); + Object childObj = processObject(childChild, ReflectionTools.getFieldSubType(obj, field), swf); + list.add(childObj); + } + } + + field.set(obj, list); + } else if (childCls.isArray()) { + List list = new ArrayList(); + for (int j = 0; j < child.getChildNodes().getLength(); j++) { + Node childChildNode = child.getChildNodes().item(j); + if (childChildNode instanceof Element) { + Element childChild = (Element) child.getChildNodes().item(j); + Object childObj = processObject(childChild, childCls.getComponentType(), swf); + list.add(childObj); + } + } + + Object array = Array.newInstance(childCls.getComponentType(), list.size()); + for (int j = 0; j < list.size(); j++) { + Array.set(array, j, list.get(j)); + } + + field.set(obj, array); + } else { + Object childObj = processObject(child, null, swf); + field.set(obj, childObj); + } + } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException | NoSuchMethodException | InstantiationException | InvocationTargetException ex) { + Logger.getLogger(SwfXmlImporter.class.getName()).log(Level.SEVERE, null, ex); + } + } + } + } + + private Object processObject(Element element, Class requiredType, SWF swf) throws IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InstantiationException, InvocationTargetException { + String type = element.getAttribute("type"); + if (type != null && !type.isEmpty()) { + Object childObj = createObject(type, swf); + processElement(element, childObj, swf); + return childObj; + } else { + return getAs(requiredType, element.getTextContent()); + } + } + + private Object createObject(String type, SWF swf) throws NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { + if (swfTags == null) { + Map tags = new HashMap<>(); + Map knownTags = Tag.getKnownClasses(); + for (Integer key : knownTags.keySet()) { + Class cls = knownTags.get(key); + tags.put(cls.getSimpleName(), cls); + } + + swfTags = tags; + } + + Class cls = swfTags.get(type); + if (cls != null) { + return cls.getConstructor(SWF.class).newInstance(swf); + } + + if (swfObjects == null) { + Map objects = new HashMap<>(); + Class[] knownObjects = new Class[] { ALPHABITMAPDATA.class, ALPHACOLORMAPDATA.class, ARGB.class, BITMAPDATA.class, + BUTTONCONDACTION.class, BUTTONRECORD.class, CLIPACTIONRECORD.class, CLIPACTIONS.class, CLIPEVENTFLAGS.class, + COLORMAPDATA.class, ColorTransform.class, ConstantColorColorTransform.class, CXFORM.class, CXFORMWITHALPHA.class, + FILLSTYLE.class, FILLSTYLEARRAY.class, FOCALGRADIENT.class, GLYPHENTRY.class, GRADIENT.class, GRADRECORD.class, + KERNINGRECORD.class, LANGCODE.class, LINESTYLE.class, LINESTYLE2.class, LINESTYLEARRAY.class, MATRIX.class, + MORPHFILLSTYLE.class, MORPHFILLSTYLEARRAY.class, MORPHFOCALGRADIENT.class, MORPHGRADIENT.class, + MORPHGRADRECORD.class, MORPHLINESTYLE.class, MORPHLINESTYLE2.class, MORPHLINESTYLEARRAY.class, PIX15.class, + PIX24.class, RECT.class, RGB.class, RGBA.class, SHAPE.class, SHAPEWITHSTYLE.class, SOUNDENVELOPE.class, + SOUNDINFO.class, TEXTRECORD.class, ZONEDATA.class, ZONERECORD.class, + CurvedEdgeRecord.class, EndShapeRecord.class, StraightEdgeRecord.class, StyleChangeRecord.class }; + for (Class cls2 : knownObjects) { + objects.put(cls2.getSimpleName(), cls2); + } + + swfObjects = objects; + } + + cls = swfObjects.get(type); + if (cls != null) { + return cls.getConstructor().newInstance(); + } + + return null; + } + + private Object getAs(Class cls, String stringValue) throws IllegalArgumentException, IllegalAccessException { + if (cls == Byte.class || cls == byte.class) { + return Byte.parseByte(stringValue); + } else if (cls == Short.class || cls == short.class) { + return Short.parseShort(stringValue); + } else if (cls == Integer.class || cls == int.class) { + return Integer.parseInt(stringValue); + } else if (cls == Long.class || cls == long.class) { + return Long.parseLong(stringValue); + } else if (cls == Float.class || cls == float.class) { + return Float.parseFloat(stringValue); + } else if (cls == Double.class || cls == double.class) { + return Double.parseDouble(stringValue); + } else if (cls == Boolean.class || cls == boolean.class) { + return Boolean.parseBoolean(stringValue); + } else if (cls == Character.class || cls == char.class) { + return stringValue.charAt(0); + } else if (cls == String.class) { + return stringValue; + } else if (cls == ByteArrayRange.class) { + ByteArrayRange range = new ByteArrayRange(stringValue); + return range; + } else if (cls.isEnum()) { + return Enum.valueOf(cls, stringValue); + } else { + throw new RuntimeException("Unsupported object type."); + } + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/Tag.java index 1da1424a3..66fb54124 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/Tag.java @@ -38,8 +38,10 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.Serializable; import java.util.Arrays; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; /** @@ -134,6 +136,7 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable { private static final Object lockObject = new Object(); private volatile static List knownTagIds; + private volatile static Map knownTagClasses; private volatile static List requiredTagIds; public static List getKnownTags() { @@ -227,6 +230,97 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable { return knownTagIds; } + public static Map getKnownClasses() { + if (knownTagClasses == null) { + synchronized (lockObject) { + if (knownTagClasses == null) { + Map map = new HashMap<>(); + map.put(CSMTextSettingsTag.ID, CSMTextSettingsTag.class); + map.put(DebugIDTag.ID, DebugIDTag.class); + map.put(DefineBinaryDataTag.ID, DefineBinaryDataTag.class); + map.put(DefineBitsJPEG2Tag.ID, DefineBitsJPEG2Tag.class); + map.put(DefineBitsJPEG3Tag.ID, DefineBitsJPEG3Tag.class); + map.put(DefineBitsJPEG4Tag.ID, DefineBitsJPEG4Tag.class); + map.put(DefineBitsLossless2Tag.ID, DefineBitsLossless2Tag.class); + map.put(DefineBitsLosslessTag.ID, DefineBitsLosslessTag.class); + map.put(DefineBitsTag.ID, DefineBitsTag.class); + map.put(DefineButton2Tag.ID, DefineButton2Tag.class); + map.put(DefineButtonCxformTag.ID, DefineButtonCxformTag.class); + map.put(DefineButtonSoundTag.ID, DefineButtonSoundTag.class); + map.put(DefineButtonTag.ID, DefineButtonTag.class); + map.put(DefineEditTextTag.ID, DefineEditTextTag.class); + map.put(DefineFont2Tag.ID, DefineFont2Tag.class); + map.put(DefineFont3Tag.ID, DefineFont3Tag.class); + map.put(DefineFont4Tag.ID, DefineFont4Tag.class); + map.put(DefineFontAlignZonesTag.ID, DefineFontAlignZonesTag.class); + map.put(DefineFontInfo2Tag.ID, DefineFontInfo2Tag.class); + map.put(DefineFontInfoTag.ID, DefineFontInfoTag.class); + map.put(DefineFontNameTag.ID, DefineFontNameTag.class); + map.put(DefineFontTag.ID, DefineFontTag.class); + map.put(DefineMorphShape2Tag.ID, DefineMorphShape2Tag.class); + map.put(DefineMorphShapeTag.ID, DefineMorphShapeTag.class); + map.put(DefineScalingGridTag.ID, DefineScalingGridTag.class); + map.put(DefineSceneAndFrameLabelDataTag.ID, DefineSceneAndFrameLabelDataTag.class); + map.put(DefineShape2Tag.ID, DefineShape2Tag.class); + map.put(DefineShape3Tag.ID, DefineShape3Tag.class); + map.put(DefineShape4Tag.ID, DefineShape4Tag.class); + map.put(DefineShapeTag.ID, DefineShapeTag.class); + map.put(DefineSoundTag.ID, DefineSoundTag.class); + map.put(DefineSpriteTag.ID, DefineSpriteTag.class); + map.put(DefineText2Tag.ID, DefineText2Tag.class); + map.put(DefineTextTag.ID, DefineTextTag.class); + map.put(DefineVideoStreamTag.ID, DefineVideoStreamTag.class); + map.put(DoABCDefineTag.ID, DoABCDefineTag.class); + map.put(DoABCTag.ID, DoABCTag.class); + map.put(DoActionTag.ID, DoActionTag.class); + map.put(DoInitActionTag.ID, DoInitActionTag.class); + map.put(EnableDebugger2Tag.ID, EnableDebugger2Tag.class); + map.put(EnableDebuggerTag.ID, EnableDebuggerTag.class); + map.put(EnableTelemetryTag.ID, EnableTelemetryTag.class); + map.put(EndTag.ID, EndTag.class); + map.put(ExportAssetsTag.ID, ExportAssetsTag.class); + map.put(FileAttributesTag.ID, FileAttributesTag.class); + map.put(FrameLabelTag.ID, FrameLabelTag.class); + map.put(ImportAssets2Tag.ID, ImportAssets2Tag.class); + map.put(ImportAssetsTag.ID, ImportAssetsTag.class); + map.put(JPEGTablesTag.ID, JPEGTablesTag.class); + map.put(MetadataTag.ID, MetadataTag.class); + map.put(PlaceObject2Tag.ID, PlaceObject2Tag.class); + map.put(PlaceObject3Tag.ID, PlaceObject3Tag.class); + map.put(PlaceObject4Tag.ID, PlaceObject4Tag.class); + map.put(PlaceObjectTag.ID, PlaceObjectTag.class); + map.put(ProductInfoTag.ID, ProductInfoTag.class); + map.put(ProtectTag.ID, ProtectTag.class); + map.put(RemoveObject2Tag.ID, RemoveObject2Tag.class); + map.put(RemoveObjectTag.ID, RemoveObjectTag.class); + map.put(ScriptLimitsTag.ID, ScriptLimitsTag.class); + map.put(SetBackgroundColorTag.ID, SetBackgroundColorTag.class); + map.put(SetTabIndexTag.ID, SetTabIndexTag.class); + map.put(ShowFrameTag.ID, ShowFrameTag.class); + map.put(SoundStreamBlockTag.ID, SoundStreamBlockTag.class); + map.put(SoundStreamHead2Tag.ID, SoundStreamHead2Tag.class); + map.put(SoundStreamHeadTag.ID, SoundStreamHeadTag.class); + map.put(StartSound2Tag.ID, StartSound2Tag.class); + map.put(StartSoundTag.ID, StartSoundTag.class); + map.put(SymbolClassTag.ID, SymbolClassTag.class); + map.put(VideoFrameTag.ID, VideoFrameTag.class); + map.put(DefineCompactedFont.ID, DefineCompactedFont.class); + map.put(DefineExternalGradient.ID, DefineExternalGradient.class); + map.put(DefineExternalImage.ID, DefineExternalImage.class); + map.put(DefineExternalImage2.ID, DefineExternalImage2.class); + map.put(DefineExternalSound.ID, DefineExternalSound.class); + map.put(DefineExternalStreamSound.ID, DefineExternalStreamSound.class); + map.put(DefineGradientMap.ID, DefineGradientMap.class); + map.put(DefineSubImage.ID, DefineSubImage.class); + map.put(ExporterInfo.ID, ExporterInfo.class); + map.put(FontTextureInfo.ID, FontTextureInfo.class); + knownTagClasses = map; + } + } + } + return knownTagClasses; + } + public static List getRequiredTags() { if (requiredTagIds == null) { synchronized (lockObject) { diff --git a/src/com/jpexs/decompiler/flash/gui/generictageditors/ReflectionTools.java b/libsrc/ffdec_lib/src/com/jpexs/helpers/ReflectionTools.java similarity index 99% rename from src/com/jpexs/decompiler/flash/gui/generictageditors/ReflectionTools.java rename to libsrc/ffdec_lib/src/com/jpexs/helpers/ReflectionTools.java index 4acf9db2b..2c7566d2e 100644 --- a/src/com/jpexs/decompiler/flash/gui/generictageditors/ReflectionTools.java +++ b/libsrc/ffdec_lib/src/com/jpexs/helpers/ReflectionTools.java @@ -14,7 +14,7 @@ * 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.generictageditors; +package com.jpexs.helpers; import java.lang.reflect.Array; import java.lang.reflect.Field; diff --git a/src/com/jpexs/decompiler/flash/gui/GenericTagPanel.java b/src/com/jpexs/decompiler/flash/gui/GenericTagPanel.java index f95b3fc61..0c833480b 100644 --- a/src/com/jpexs/decompiler/flash/gui/GenericTagPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/GenericTagPanel.java @@ -22,7 +22,6 @@ 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; @@ -38,6 +37,7 @@ import com.jpexs.decompiler.flash.types.annotations.SWFType; import com.jpexs.decompiler.flash.types.annotations.parser.AnnotationParseException; import com.jpexs.decompiler.flash.types.annotations.parser.ConditionEvaluator; import com.jpexs.helpers.Helper; +import com.jpexs.helpers.ReflectionTools; import java.awt.BorderLayout; import java.awt.Component; import java.awt.event.ActionEvent; diff --git a/src/com/jpexs/decompiler/flash/gui/GenericTagTreePanel.java b/src/com/jpexs/decompiler/flash/gui/GenericTagTreePanel.java index de5c6bde7..b76f33f11 100644 --- a/src/com/jpexs/decompiler/flash/gui/GenericTagTreePanel.java +++ b/src/com/jpexs/decompiler/flash/gui/GenericTagTreePanel.java @@ -21,7 +21,6 @@ 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; @@ -36,6 +35,7 @@ import com.jpexs.decompiler.flash.types.annotations.SWFArray; import com.jpexs.decompiler.flash.types.annotations.SWFType; import com.jpexs.decompiler.flash.types.annotations.parser.AnnotationParseException; import com.jpexs.decompiler.flash.types.annotations.parser.ConditionEvaluator; +import com.jpexs.helpers.ReflectionTools; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; diff --git a/src/com/jpexs/decompiler/flash/gui/MainFrameRibbonMenu.java b/src/com/jpexs/decompiler/flash/gui/MainFrameRibbonMenu.java index d85152914..56a5b8205 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainFrameRibbonMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/MainFrameRibbonMenu.java @@ -96,6 +96,7 @@ public class MainFrameRibbonMenu extends MainFrameMenu implements ActionListener public static final String ACTION_EXPORT_SEL = "EXPORTSEL"; public static final String ACTION_EXPORT_JAVA_SOURCE = "EXPORTJAVASOURCE"; public static final String ACTION_EXPORT_SWF_XML = "EXPORTSWFXML"; + public static final String ACTION_IMPORT_SWF_XML = "IMPORTSWFXML"; private static final String ACTION_EXPORT = "EXPORT"; private static final String ACTION_IMPORT_TEXT = "IMPORTTEXT"; private static final String ACTION_CHECK_UPDATES = "CHECKUPDATES"; diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index 440bfe885..0d5c12645 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -74,6 +74,7 @@ import com.jpexs.decompiler.flash.helpers.Freed; import com.jpexs.decompiler.flash.importers.BinaryDataImporter; import com.jpexs.decompiler.flash.importers.ImageImporter; import com.jpexs.decompiler.flash.importers.ShapeImporter; +import com.jpexs.decompiler.flash.importers.SwfXmlImporter; import com.jpexs.decompiler.flash.importers.TextImporter; import com.jpexs.decompiler.flash.tags.ABCContainerTag; import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag; @@ -1671,6 +1672,27 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec } } + public void importSwfXml() { + List sel = tagTree.getSelected(tagTree); + for (TreeItem item : sel) { + if (item instanceof SWF) { + SWF swf = (SWF) item; + File selectedFile = showImportFileChooser("filter.xml|*.xml"); + if (selectedFile != null) { + File selfile = Helper.fixDialogFile(selectedFile); + String xml = Helper.readTextFile(selfile.getPath()); + try { + new SwfXmlImporter().importSwf(swf, xml); + swf.clearAllCache(); + refreshTree(); + } catch (IOException ex) { + logger.log(Level.SEVERE, null, ex); + } + } + } + } + } + public void restoreControlFlow(final boolean all) { Main.startWork(translate("work.restoringControlFlow")); if ((!all) || confirmExperimental()) { @@ -1936,7 +1958,6 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec if (item instanceof DefineSoundTag) { File selectedFile = showImportFileChooser("filter.sounds|*.mp3;*.wav|filter.sounds.mp3|*.mp3|filter.sounds.wav|*.wav"); if (selectedFile != null) { - Configuration.lastOpenDir.set(Helper.fixDialogFile(selectedFile).getParentFile().getAbsolutePath()); File selfile = Helper.fixDialogFile(selectedFile); DefineSoundTag ds = (DefineSoundTag) item; int soundFormat = SoundFormat.FORMAT_UNCOMPRESSED_LITTLE_ENDIAN; @@ -1961,7 +1982,6 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec if (it.importSupported()) { File selectedFile = showImportFileChooser("filter.images|*.jpg;*.jpeg;*.gif;*.png;*.bmp"); if (selectedFile != null) { - Configuration.lastOpenDir.set(Helper.fixDialogFile(selectedFile).getParentFile().getAbsolutePath()); File selfile = Helper.fixDialogFile(selectedFile); byte[] data = Helper.readFile(selfile.getAbsolutePath()); try { @@ -1983,7 +2003,6 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec ShapeTag st = (ShapeTag) item; File selectedFile = showImportFileChooser("filter.images|*.jpg;*.jpeg;*.gif;*.png;*.bmp"); if (selectedFile != null) { - Configuration.lastOpenDir.set(Helper.fixDialogFile(selectedFile).getParentFile().getAbsolutePath()); File selfile = Helper.fixDialogFile(selectedFile); byte[] data = Helper.readFile(selfile.getAbsolutePath()); try { @@ -2004,7 +2023,6 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec DefineBinaryDataTag bt = (DefineBinaryDataTag) item; File selectedFile = showImportFileChooser(""); if (selectedFile != null) { - Configuration.lastOpenDir.set(Helper.fixDialogFile(selectedFile).getParentFile().getAbsolutePath()); File selfile = Helper.fixDialogFile(selectedFile); byte[] data = Helper.readFile(selfile.getAbsolutePath()); new BinaryDataImporter().importData(bt, data); @@ -2026,6 +2044,9 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec case MainFrameRibbonMenu.ACTION_EXPORT_SWF_XML: exportSwfXml(); break; + case MainFrameRibbonMenu.ACTION_IMPORT_SWF_XML: + importSwfXml(); + break; case MainFrameRibbonMenu.ACTION_EXPORT_SEL: export(true); break; @@ -2078,7 +2099,9 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec JFrame f = new JFrame(); View.setWindowIcon(f); if (fc.showOpenDialog(f) == JFileChooser.APPROVE_OPTION) { - return fc.getSelectedFile(); + File result = fc.getSelectedFile(); + Configuration.lastOpenDir.set(Helper.fixDialogFile(result).getParentFile().getAbsolutePath()); + return result; } return null; diff --git a/src/com/jpexs/decompiler/flash/gui/generictageditors/BooleanEditor.java b/src/com/jpexs/decompiler/flash/gui/generictageditors/BooleanEditor.java index f0a3122f3..d00cbd9e0 100644 --- a/src/com/jpexs/decompiler/flash/gui/generictageditors/BooleanEditor.java +++ b/src/com/jpexs/decompiler/flash/gui/generictageditors/BooleanEditor.java @@ -16,6 +16,7 @@ */ package com.jpexs.decompiler.flash.gui.generictageditors; +import com.jpexs.helpers.ReflectionTools; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.lang.reflect.Field; diff --git a/src/com/jpexs/decompiler/flash/gui/generictageditors/ColorEditor.java b/src/com/jpexs/decompiler/flash/gui/generictageditors/ColorEditor.java index ea7a566df..d50138677 100644 --- a/src/com/jpexs/decompiler/flash/gui/generictageditors/ColorEditor.java +++ b/src/com/jpexs/decompiler/flash/gui/generictageditors/ColorEditor.java @@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.gui.AppStrings; import com.jpexs.decompiler.flash.types.ARGB; import com.jpexs.decompiler.flash.types.RGB; import com.jpexs.decompiler.flash.types.RGBA; +import com.jpexs.helpers.ReflectionTools; import java.awt.Color; import java.awt.Component; import java.awt.Cursor; diff --git a/src/com/jpexs/decompiler/flash/gui/generictageditors/NumberEditor.java b/src/com/jpexs/decompiler/flash/gui/generictageditors/NumberEditor.java index 86f8218eb..32f852b87 100644 --- a/src/com/jpexs/decompiler/flash/gui/generictageditors/NumberEditor.java +++ b/src/com/jpexs/decompiler/flash/gui/generictageditors/NumberEditor.java @@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.gui.generictageditors; import com.jpexs.decompiler.flash.types.BasicType; import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ReflectionTools; import java.awt.Component; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; diff --git a/src/com/jpexs/decompiler/flash/gui/generictageditors/StringEditor.java b/src/com/jpexs/decompiler/flash/gui/generictageditors/StringEditor.java index 17ec7b41c..4e4c42ff4 100644 --- a/src/com/jpexs/decompiler/flash/gui/generictageditors/StringEditor.java +++ b/src/com/jpexs/decompiler/flash/gui/generictageditors/StringEditor.java @@ -17,6 +17,7 @@ package com.jpexs.decompiler.flash.gui.generictageditors; import com.jpexs.helpers.Helper; +import com.jpexs.helpers.ReflectionTools; import java.awt.Component; import java.awt.Dimension; import java.awt.event.FocusAdapter; diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties index 650e87e60..1a245811c 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties @@ -551,3 +551,6 @@ message.confirm.closeAll = There are unsaved changes. Do you really want to clos contextmenu.exportJavaSource = Export Java Source contextmenu.exportSwfXml = Export SWF as XML +contextmenu.importSwfXml = Import SWF XML + +filter.xml = XML diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_hu.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_hu.properties index 5de306c15..a41ce9a73 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_hu.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_hu.properties @@ -551,3 +551,6 @@ message.confirm.closeAll = Mentetlen v\u00e1ltoz\u00e1sok vannak. Szeretn\u00e9 contextmenu.exportJavaSource = Java k\u00f3d export\u00e1l\u00e1s contextmenu.exportSwfXml = SWF export\u00e1l\u00e1sa XML-k\u00e9nt +contextmenu.importSwfXml = SWF XML import\u00e1l\u00e1s + +filter.xml = XML diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java index 12b1b7942..4cdbc8daa 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java @@ -78,6 +78,7 @@ public class TagTreeContextMenu extends JPopupMenu implements ActionListener { private JMenuItem jumpToCharacterMenuItem; private JMenuItem exportJavaSourceMenuItem; private JMenuItem exportSwfXmlMenuItem; + private JMenuItem importSwfXmlMenuItem; private JMenuItem closeMenuItem; private JMenu addTagMenu; private JMenu moveTagMenu; @@ -134,6 +135,11 @@ public class TagTreeContextMenu extends JPopupMenu implements ActionListener { exportSwfXmlMenuItem.addActionListener(mainPanel); add(exportSwfXmlMenuItem); + importSwfXmlMenuItem = new JMenuItem(mainPanel.translate("contextmenu.importSwfXml")); + importSwfXmlMenuItem.setActionCommand(MainFrameRibbonMenu.ACTION_IMPORT_SWF_XML); + importSwfXmlMenuItem.addActionListener(mainPanel); + add(importSwfXmlMenuItem); + closeMenuItem = new JMenuItem(mainPanel.translate("contextmenu.closeSwf")); closeMenuItem.setActionCommand(ACTION_CLOSE_SWF); closeMenuItem.addActionListener(this); @@ -227,6 +233,8 @@ public class TagTreeContextMenu extends JPopupMenu implements ActionListener { replaceMenuItem.setVisible(false); rawEditMenuItem.setVisible(false); jumpToCharacterMenuItem.setVisible(false); + exportJavaSourceMenuItem.setVisible(allSelectedIsSwf); + exportSwfXmlMenuItem.setVisible(allSelectedIsSwf); closeMenuItem.setVisible(allSelectedIsSwf); addTagMenu.setVisible(false); moveTagMenu.setVisible(false);