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 f6da6d5002..9a9c6cd0ea 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 @@ -32,7 +32,6 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; -import java.io.StringWriter; import java.io.Writer; import java.lang.reflect.Array; import java.lang.reflect.Field; @@ -43,19 +42,14 @@ 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 javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; -import org.w3c.dom.CDATASection; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; +import javax.xml.transform.stream.StreamSource; /** * @@ -68,155 +62,171 @@ public class SwfXmlExporter { private final Map> cachedFields = new HashMap<>(); public List exportXml(SWF swf, File outFile) throws IOException { - DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); try { - DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); - Document xmlDoc = docBuilder.newDocument(); - exportXml(swf, xmlDoc, xmlDoc); - try (Writer writer = new Utf8OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(outFile)))) { - writer.append(getXml(xmlDoc)); + File tmp = File.createTempFile("FFDEC", "XML"); + + try (Writer writer = new Utf8OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(tmp)))) { + XMLStreamWriter xmlWriter = XMLOutputFactory.newInstance().createXMLStreamWriter(writer); + + xmlWriter.writeStartDocument(); + xmlWriter.writeComment("WARNING: The structure of this XML is not final. In later versions of FFDec it can be changed."); + xmlWriter.writeComment(ApplicationInfo.applicationVerName); + + exportXml(swf, xmlWriter); + + xmlWriter.writeEndDocument(); + xmlWriter.flush(); + xmlWriter.close(); } - } catch (ParserConfigurationException ex) { - logger.log(Level.SEVERE, null, ex); - } - List ret = new ArrayList<>(); - ret.add(outFile); - return ret; - } + TransformerFactory factory = TransformerFactory.newInstance(); - private String getXml(Document xml) { - TransformerFactory transformerFactory = TransformerFactory.newInstance(); - StringWriter writer = new StringWriter(); - try { - Transformer transformer = transformerFactory.newTransformer(); + Transformer transformer = factory.newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); - DOMSource source = new DOMSource(xml); - StreamResult result = new StreamResult(writer); - transformer.transform(source, result); - } catch (TransformerException ex) { + + transformer.transform(new StreamSource(tmp), new StreamResult(outFile)); + + tmp.delete(); + } catch (Exception ex) { logger.log(Level.SEVERE, null, ex); } - return writer.toString(); + + List ret = new ArrayList<>(); + ret.add(outFile); + return ret; } - public void exportXml(SWF swf, Document doc, Node node) throws IOException { - generateXml(doc, node, "swf", swf, false, 0, false); + public void exportXml(SWF swf, XMLStreamWriter writer) throws IOException, XMLStreamException { + generateXml(writer, "swf", swf, false, false); } public List getSwfFieldsCached(Class cls) { List result = cachedFields.get(cls); if (result == null) { result = ReflectionTools.getSwfFields(cls); + + result.removeIf((f) -> { + return Modifier.isStatic(f.getModifiers()) || f.getAnnotation(Internal.class) != null; + }); + + result.sort((o1, o2) -> { + + boolean a1 = canBeAttribute(o1.getType()); + boolean a2 = canBeAttribute(o2.getType()); + + if(a1 == a2 && a1 == true) { + return o1.getName().compareTo(o2.getName()); + } + + return a1 ? -1 : a2 ? 1 : 0; + }); + cachedFields.put(cls, result); } return result; } - private void generateXml(Document doc, Node node, String name, Object obj, boolean isListItem, int level, boolean needsCData) { + private boolean isPrimitive(Class cls) { + return cls != null && !cls.equals(Void.class) && (cls.isPrimitive() + || cls == Short.class + || cls == Integer.class + || cls == Long.class + || cls == Float.class + || cls == Double.class + || cls == Boolean.class + || cls == Character.class + || cls == String.class); + } + + private boolean canBeAttribute(Class cls) { + return cls != null && (isPrimitive(cls) + || cls.equals(byte[].class) + || ByteArrayRange.class.isAssignableFrom(cls) + || cls.isEnum()); + } + + private boolean isList(Class cls) { + return cls != null && (cls.isArray() || List.class.isAssignableFrom(cls)); + } + + private void generateXml(XMLStreamWriter writer, String name, Object obj, boolean isListItem, boolean needsCData) throws XMLStreamException { Class cls = obj != null ? obj.getClass() : null; if (obj != null && needsCData && cls == String.class) { - - Element objNode = doc.createElement(name); - objNode.setAttribute("type", "String"); - CDATASection cdataNode = doc.createCDATASection((String) obj); - objNode.appendChild(cdataNode); - - node.appendChild(objNode); - } else if (obj != null && (cls == Byte.class || cls == byte.class - || cls == Short.class || cls == short.class - || cls == Integer.class || cls == int.class - || cls == Long.class || cls == long.class - || cls == Float.class || cls == float.class - || cls == Double.class || cls == double.class - || cls == Boolean.class || cls == boolean.class - || cls == Character.class || cls == char.class - || cls == String.class)) { + writer.writeStartElement(name); + writer.writeAttribute("type", "String"); + writer.writeCData((String) obj); + writer.writeEndElement(); + } else if (obj != null && isPrimitive(cls)) { Object value = obj; if (value instanceof String) { value = Helper.removeInvalidXMLCharacters((String) value); } if (isListItem) { - Element childNode = doc.createElement(name); - childNode.setTextContent(value.toString()); - node.appendChild(childNode); + writer.writeStartElement(name); + writer.writeCharacters(value.toString()); + writer.writeEndElement(); } else { - ((Element) node).setAttribute(name, value.toString()); + writer.writeAttribute(name, value.toString()); } } else if (cls != null && obj != null && cls.isEnum()) { - ((Element) node).setAttribute(name, obj.toString()); + writer.writeAttribute(name, obj.toString()); } else if (obj instanceof ByteArrayRange) { ByteArrayRange range = (ByteArrayRange) obj; byte[] data = range.getRangeData(); - ((Element) node).setAttribute(name, Helper.byteArrayToHex(data)); + writer.writeAttribute(name, Helper.byteArrayToHex(data)); } else if (obj instanceof byte[]) { byte[] data = (byte[]) obj; - ((Element) node).setAttribute(name, Helper.byteArrayToHex(data)); - } else if (cls != null && obj != null && List.class.isAssignableFrom(cls)) { - List list = (List) obj; - Element listNode = doc.createElement(name); - node.appendChild(listNode); - for (int i = 0; i < list.size(); i++) { - generateXml(doc, listNode, "item", list.get(i), true, level + 1, false); + writer.writeAttribute(name, Helper.byteArrayToHex(data)); + } else if (isList(cls)) { + Object value = obj; + if (List.class.isAssignableFrom(cls)) { + value = ((List) value).toArray(); } - } else if (cls != null && cls.isArray()) { - Class arrayType = cls.getComponentType(); - Element arrayNode = doc.createElement(name); - node.appendChild(arrayNode); - int length = Array.getLength(obj); + + writer.writeStartElement(name); + int length = Array.getLength(value); for (int i = 0; i < length; i++) { - generateXml(doc, arrayNode, "item", Array.get(obj, i), true, level + 1, false); + generateXml(writer, "item", Array.get(value, i), true, false); } + writer.writeEndElement(); } else if (obj != null) { if (obj instanceof LazyObject) { ((LazyObject) obj).load(); } Class clazz = obj.getClass(); + List fields = getSwfFieldsCached(clazz); + if (obj instanceof InternalClass) { clazz = clazz.getSuperclass(); } - String className = clazz.getSimpleName(); - List fields = getSwfFieldsCached(obj.getClass()); - Element objNode = doc.createElement(name); - objNode.setAttribute("type", className); - if (obj instanceof UnknownTag) { - objNode.setAttribute("tagId", "" + ((Tag) obj).getId()); - } - node.appendChild(objNode); + writer.writeStartElement(name); + writer.writeAttribute("type", clazz.getSimpleName()); - if (level == 0) { - objNode.appendChild(doc.createComment("WARNING: The structure of this XML is not final. In later versions of FFDec it can be changed.")); - objNode.appendChild(doc.createComment(ApplicationInfo.applicationVerName)); + if (obj instanceof UnknownTag) { + writer.writeAttribute("tagId", String.valueOf(((Tag) obj).getId())); } for (Field f : fields) { - if (Modifier.isStatic(f.getModifiers())) { - continue; - } - - Internal inter = f.getAnnotation(Internal.class); - if (inter != null) { - continue; - } Multiline multilineA = f.getAnnotation(Multiline.class); try { f.setAccessible(true); - generateXml(doc, objNode, f.getName(), f.get(obj), false, level + 1, multilineA != null); + generateXml(writer, f.getName(), f.get(obj), false, multilineA != null); } catch (IllegalArgumentException | IllegalAccessException ex) { logger.log(Level.SEVERE, null, ex); } } + writer.writeEndElement(); } else if (isListItem) { - Element childNode = doc.createElement(name); - childNode.setAttribute("isNull", Boolean.TRUE.toString()); - node.appendChild(childNode); + writer.writeStartElement(name); + writer.writeAttribute("isNull", Boolean.TRUE.toString()); + writer.writeEndElement(); } } } 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 index 0dea429009..3642a998fb 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SwfXmlImporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SwfXmlImporter.java @@ -102,7 +102,12 @@ import com.jpexs.helpers.ByteArrayRange; import com.jpexs.helpers.HashArrayList; import com.jpexs.helpers.ReflectionTools; +import com.jpexs.helpers.utf8.Utf8InputStreamReader; +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; import java.io.IOException; +import java.io.Reader; import java.io.StringReader; import java.lang.reflect.Array; import java.lang.reflect.Constructor; @@ -114,15 +119,10 @@ 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; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; /** * @@ -133,21 +133,84 @@ public class SwfXmlImporter { private static final Logger logger = Logger.getLogger(SwfXmlImporter.class.getName()); - private Map swfTags; + private static final Map swfTags; - private Map swfObjects; + private static final Map swfObjects; - private Map swfObjectsParam; + private static final Map swfObjectsParam; + + static { + Map tags = new HashMap<>(); + Map knownTags = Tag.getKnownClasses(); + for (Integer key : knownTags.keySet()) { + Class cls = knownTags.get(key).getCls(); + if (!ReflectionTools.canInstantiate(cls)) { + System.err.println("Can't instantiate: " + cls.getName()); + } + tags.put(cls.getSimpleName(), cls); + } + + swfTags = tags; + + 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, 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, + BEVELFILTER.class, BLURFILTER.class, COLORMATRIXFILTER.class, CONVOLUTIONFILTER.class, + DROPSHADOWFILTER.class, GLOWFILTER.class, GRADIENTBEVELFILTER.class, GRADIENTGLOWFILTER.class, + AVM2ConstantPool.class, Decimal.class, Namespace.class, NamespaceSet.class, Multiname.class, MethodInfo.class, MetadataInfo.class, + ValueKind.class, InstanceInfo.class, Traits.class, TraitClass.class, TraitFunction.class, + TraitMethodGetterSetter.class, TraitSlotConst.class, ClassInfo.class, ScriptInfo.class, MethodBody.class, + ABCException.class, ABCVersion.class, Amf3Value.class}; + + for (Class cls2 : knownObjects) { + if (!ReflectionTools.canInstantiateDefaultConstructor(cls2)) { + System.err.println("Can't instantiate: " + cls2.getName()); + } + objects.put(cls2.getSimpleName(), cls2); + } + + swfObjects = objects; + + Map objectsParam = new HashMap<>(); + Class[] knownObjectsParam = new Class[]{ABC.class}; + for (Class cls2 : knownObjectsParam) { + if (!ReflectionTools.canInstantiate(cls2)) { + System.err.println("Can't instantiate: " + cls2.getName()); + } + objectsParam.put(cls2.getSimpleName(), cls2); + } + + swfObjectsParam = objectsParam; + } + + private boolean isList(Class cls) { + return cls != null && (cls.isArray() || List.class.isAssignableFrom(cls)); + } - public void importSwf(SWF swf, String xml) throws IOException { - DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + public void importSwf(SWF swf, File inFile) throws IOException { + XMLInputFactory xmlFactory = XMLInputFactory.newInstance(); + try { - DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); - Document doc = docBuilder.parse(new InputSource(new StringReader(xml))); - processElement(doc.getDocumentElement(), swf, swf, null); + try(Reader reader = new Utf8InputStreamReader(new BufferedInputStream(new FileInputStream(inFile)))) { + XMLStreamReader xmlReader = xmlFactory.createXMLStreamReader(reader); + + xmlReader.nextTag(); + xmlReader.require(XMLStreamConstants.START_ELEMENT, null, "swf"); + + processElement(xmlReader, swf, swf, null); + } + swf.clearAllCache(); setSwfAndTimelined(swf); - } catch (ParserConfigurationException | SAXException ex) { + } catch (XMLStreamException ex) { logger.log(Level.SEVERE, null, ex); } } @@ -167,12 +230,11 @@ private void setSwfAndTimelined(SWF swf) { } public Object importObject(String xml, Class requiredType, SWF swf) throws IOException { - DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + XMLInputFactory xmlFactory = XMLInputFactory.newInstance(); try { - DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); - Document doc = docBuilder.parse(new InputSource(new StringReader(xml))); - return processObject(doc.getDocumentElement(), requiredType, swf, null); - } catch (ParserConfigurationException | SAXException | IllegalArgumentException | IllegalAccessException | NoSuchMethodException | InstantiationException | InvocationTargetException ex) { + XMLStreamReader reader = xmlFactory.createXMLStreamReader(new StringReader(xml)); + return processObject(reader, requiredType, swf, null); + } catch (IllegalArgumentException | IllegalAccessException | NoSuchMethodException | InstantiationException | InvocationTargetException | XMLStreamException ex) { Logger.getLogger(SwfXmlImporter.class.getName()).log(Level.SEVERE, null, ex); } return null; @@ -212,117 +274,145 @@ private static void setFieldValue(Field field, Object obj, Object value) throws }*/ } - private void processElement(Element element, Object obj, SWF swf, Tag tag) { + private void processElement(XMLStreamReader reader, Object obj, SWF swf, Tag tag) throws XMLStreamException { + // Check if element started and start if needed + if(!reader.isStartElement()) { + reader.nextTag(); + reader.require(XMLStreamConstants.START_ELEMENT, null, null); + } + 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("tagId") && "UnknownTag".equals(element.getAttribute("type"))) { + + Map attributes = new HashMap<>(); + for (int i = 0; i < reader.getAttributeCount(); i++) { + String name = reader.getAttributeLocalName(i); + String value = reader.getAttributeValue(i); + attributes.put(name, value); + } + + for (Map.Entry entry : attributes.entrySet()) { + String name = entry.getKey(); + String val = entry.getValue(); + + if (name.equals("tagId") && "UnknownTag".equals(attributes.get("type"))) { continue; } if (!name.equals("type")) { try { Field field = getField(cls, name); - String attrValue = attr.getValue(); - setFieldValue(field, obj, getAs(field.getType(), attrValue)); + setFieldValue(field, obj, getAs(field.getType(), val)); } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException ex) { logger.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 = getField(cls, name); - Class childCls = field.getType(); - if (List.class.isAssignableFrom(childCls)) { - List list = HashArrayList.class.isAssignableFrom(childCls) ? new HashArrayList() : 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, tag); - list.add(childObj); - } - } - - setFieldValue(field, 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, tag); - list.add(childObj); - } - } - - Object array = Array.newInstance(childCls.getComponentType(), list.size()); + + // Check for child elements + reader.nextTag(); + while(reader.isStartElement()) { + // Child element open + String name = reader.getLocalName(); + try { + Field field = getField(cls, name); + Class childCls = field.getType(); + + if(isList(childCls)) { + List list = HashArrayList.class.isAssignableFrom(childCls) ? new HashArrayList() : new ArrayList(); + Class reqType = childCls.isArray() ? childCls.getComponentType() : ReflectionTools.getFieldSubType(obj, field); + + // Check for list item elements + reader.nextTag(); + while(reader.isStartElement()) { + Object childObj = processObject(reader, reqType, swf, tag); + list.add(childObj); + + reader.nextTag(); + } + + Object value = list; + + if(childCls.isArray()) { + value = Array.newInstance(childCls.getComponentType(), list.size()); for (int j = 0; j < list.size(); j++) { - Array.set(array, j, list.get(j)); + Array.set(value, j, list.get(j)); } - - setFieldValue(field, obj, array); - } else { - Object childObj = processObject(child, null, swf, tag); - setFieldValue(field, obj, childObj); } - } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException | NoSuchMethodException | InstantiationException | InvocationTargetException ex) { - logger.log(Level.SEVERE, "Error while getting val from class " + cls + " field: " + name, ex); + + setFieldValue(field, obj, value); + } + else { + Object childObj = processObject(reader, null, swf, tag); + setFieldValue(field, obj, childObj); } + } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException | NoSuchMethodException | InstantiationException | InvocationTargetException ex) { + logger.log(Level.SEVERE, "Error while getting val from class " + cls + " field: " + name, ex); } + + + reader.nextTag(); + } + + // Check if element ended and end if needed + if(reader.getEventType() != XMLStreamConstants.END_ELEMENT) { + reader.nextTag(); + reader.require(XMLStreamConstants.END_ELEMENT, null, null); } } - private Object processObject(Element element, Class requiredType, SWF swf, Tag tag) throws IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InstantiationException, InvocationTargetException { - String type = element.getAttribute("type"); - String tagTypeIdStr = element.getAttribute("tagId"); + private Object processObject(XMLStreamReader reader, Class requiredType, SWF swf, Tag tag) throws IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InstantiationException, InvocationTargetException, XMLStreamException { + // Check if element started and start if needed + if(!reader.isStartElement()) { + reader.nextTag(); + reader.require(XMLStreamConstants.START_ELEMENT, null, null); + } + + Map attributes = new HashMap<>(); + for (int i = 0; i < reader.getAttributeCount(); i++) { + String name = reader.getAttributeLocalName(i); + String value = reader.getAttributeValue(i); + attributes.put(name, value); + } + + String type = attributes.get("type"); + String tagTypeIdStr = attributes.get("tagId"); int tagTypeId = -1; try { tagTypeId = Integer.parseInt(tagTypeIdStr); } catch (NumberFormatException nfe) { //ignore } + + Object ret; + if ("String".equals(type)) { - return element.getTextContent(); + ret = reader.getElementText(); } else if (type != null && !type.isEmpty()) { Object childObj = createObject(type, tagTypeId, swf, tag); if (childObj instanceof Tag) { tag = (Tag) childObj; } - processElement(element, childObj, swf, tag); - return childObj; + processElement(reader, childObj, swf, tag); + ret = childObj; } else { - String isNullAttr = element.getAttribute("isNull"); + String isNullAttr = attributes.get("isNull"); if (Boolean.parseBoolean(isNullAttr)) { - return null; + ret = null; + } else { + ret = getAs(requiredType, reader.getElementText()); } - - return getAs(requiredType, element.getTextContent()); } + + // Check if element ended and end if needed + if(reader.getEventType() != XMLStreamConstants.END_ELEMENT) { + reader.nextTag(); + reader.require(XMLStreamConstants.END_ELEMENT, null, null); + } + + return ret; } private Object createObject(String type, int tagTypeId, SWF swf, Tag tag) 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).getCls(); - if (!ReflectionTools.canInstantiate(cls)) { - System.err.println("Can't instantiate: " + cls.getName()); - } - tags.put(cls.getSimpleName(), cls); - } - - swfTags = tags; - } - if ("UnknownTag".equals(type)) { return new UnknownTag(swf, tagTypeId); } @@ -332,52 +422,11 @@ private Object createObject(String type, int tagTypeId, SWF swf, Tag tag) throws 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, 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, - BEVELFILTER.class, BLURFILTER.class, COLORMATRIXFILTER.class, CONVOLUTIONFILTER.class, - DROPSHADOWFILTER.class, GLOWFILTER.class, GRADIENTBEVELFILTER.class, GRADIENTGLOWFILTER.class, - AVM2ConstantPool.class, Decimal.class, Namespace.class, NamespaceSet.class, Multiname.class, MethodInfo.class, MetadataInfo.class, - ValueKind.class, InstanceInfo.class, Traits.class, TraitClass.class, TraitFunction.class, - TraitMethodGetterSetter.class, TraitSlotConst.class, ClassInfo.class, ScriptInfo.class, MethodBody.class, - ABCException.class, ABCVersion.class, Amf3Value.class}; - for (Class cls2 : knownObjects) { - if (!ReflectionTools.canInstantiateDefaultConstructor(cls2)) { - System.err.println("Can't instantiate: " + cls2.getName()); - } - objects.put(cls2.getSimpleName(), cls2); - } - - swfObjects = objects; - } - cls = swfObjects.get(type); if (cls != null) { return cls.getConstructor().newInstance(); } - if (swfObjectsParam == null) { - Map objects = new HashMap<>(); - Class[] knownObjects = new Class[]{ABC.class}; - for (Class cls2 : knownObjects) { - if (!ReflectionTools.canInstantiate(cls2)) { - System.err.println("Can't instantiate: " + cls2.getName()); - } - objects.put(cls2.getSimpleName(), cls2); - } - - swfObjectsParam = objects; - } - cls = swfObjectsParam.get(type); if (cls != null) { for (Constructor constructor : cls.getConstructors()) { @@ -422,7 +471,7 @@ private Object getAs(Class cls, String stringValue) throws IllegalArgumentExcept } else if (cls.isEnum()) { return Enum.valueOf(cls, stringValue); } else { - throw new RuntimeException("Unsupported object type."); + throw new RuntimeException("Unsupported object type: " + cls.getSimpleName() + "."); } } } diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/SwfXmlExportImportTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/SwfXmlExportImportTest.java index 7343f3f296..9d164e9498 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/SwfXmlExportImportTest.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/SwfXmlExportImportTest.java @@ -12,7 +12,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.decompiler.flash; import com.jpexs.decompiler.flash.abc.NotSameException; @@ -94,10 +95,9 @@ public void testExportImportXml(String filePath) { File outFile = new File(fdir + File.separator + Helper.makeFileName("swf.xml")); new SwfXmlExporter().exportXml(swf, outFile); - String xml = Helper.readTextFile(outFile.getPath()); SWF swf2 = new SWF(); - new SwfXmlImporter().importSwf(swf2, xml); + new SwfXmlImporter().importSwf(swf2, outFile); if (swf.getTags().size() != swf2.getTags().size()) { throw new NotSameException(0); diff --git a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java index 95663220a5..4cf43b57a9 100644 --- a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java +++ b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java @@ -2583,9 +2583,9 @@ private static void parseXml2Swf(Stack args) { } try { - String xml = Helper.readTextFile(args.pop()); + File inFile = new File(args.pop()); SWF swf = new SWF(); - new SwfXmlImporter().importSwf(swf, xml); + new SwfXmlImporter().importSwf(swf, inFile); try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(new File(args.pop())))) { swf.saveTo(fos); } diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index c6038ae9a8..ae006a66fd 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -2706,9 +2706,8 @@ public void importSwfXml() { File selectedFile = showImportFileChooser("filter.xml|*.xml", false); if (selectedFile != null) { File selfile = Helper.fixDialogFile(selectedFile); - String xml = Helper.readTextFile(selfile.getPath()); try { - new SwfXmlImporter().importSwf(swf, xml); + new SwfXmlImporter().importSwf(swf, selfile); swf.clearAllCache(); swf.assignExportNamesToSymbols(); swf.assignClassesToSymbols();