mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-09-25 00:42:52 +00:00
import swf from XML
This commit is contained in:
@@ -695,7 +695,7 @@ public final class SWF implements SWFContainerItem, Timelined {
|
||||
frameRate = sis.readUI8("frameRate");
|
||||
frameCount = sis.readUI16("frameCount");
|
||||
List<Tag> 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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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<String, Class> swfTags;
|
||||
private Map<String, Class> 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<String, Class> tags = new HashMap<>();
|
||||
Map<Integer, Class> 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<String, Class> 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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<Integer> knownTagIds;
|
||||
private volatile static Map<Integer, Class> knownTagClasses;
|
||||
private volatile static List<Integer> requiredTagIds;
|
||||
|
||||
public static List<Integer> getKnownTags() {
|
||||
@@ -227,6 +230,97 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable {
|
||||
return knownTagIds;
|
||||
}
|
||||
|
||||
public static Map<Integer, Class> getKnownClasses() {
|
||||
if (knownTagClasses == null) {
|
||||
synchronized (lockObject) {
|
||||
if (knownTagClasses == null) {
|
||||
Map<Integer, Class> 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<Integer> getRequiredTags() {
|
||||
if (requiredTagIds == null) {
|
||||
synchronized (lockObject) {
|
||||
|
||||
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2015 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.helpers;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
if (field.getType().isArray()) {
|
||||
return Array.get(value, index);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static boolean needsIndex(Field field) {
|
||||
if (List.class.isAssignableFrom(field.getType())) {
|
||||
return true;
|
||||
} else if (field.getType().isArray()) {
|
||||
return true;
|
||||
}
|
||||
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()) {
|
||||
Array.set(value, index, newValue);
|
||||
} else {
|
||||
field.set(obj, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean canInstantiate(Class cls) {
|
||||
if (cls.isInterface()) {
|
||||
return false;
|
||||
}
|
||||
if (Modifier.isAbstract(cls.getModifiers())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean canAddToField(Object object, Field field) {
|
||||
if (List.class.isAssignableFrom(field.getType())) {
|
||||
|
||||
ParameterizedType listType = (ParameterizedType) field.getGenericType();
|
||||
Class<?> parameterClass = (Class<?>) listType.getActualTypeArguments()[0];
|
||||
return canInstantiate(parameterClass);
|
||||
}
|
||||
|
||||
if (field.getType().isArray()) {
|
||||
Object arrValue;
|
||||
try {
|
||||
arrValue = field.get(object);
|
||||
} catch (IllegalArgumentException | IllegalAccessException ex) {
|
||||
Logger.getLogger(ReflectionTools.class.getName()).log(Level.SEVERE, null, ex);
|
||||
return false;
|
||||
}
|
||||
Class componentClass = arrValue.getClass().getComponentType();
|
||||
if (componentClass.isPrimitive()) {
|
||||
return true;
|
||||
}
|
||||
return canInstantiate(componentClass);
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
public static Object newInstanceOf(Class cls) throws InstantiationException, IllegalAccessException {
|
||||
if (cls == Integer.class || cls == int.class) {
|
||||
return 0;
|
||||
} else if (cls == Float.class || cls == float.class) {
|
||||
return 0.0f;
|
||||
} else if (cls == Double.class || cls == double.class) {
|
||||
return (double) 0;
|
||||
} else if (cls == Long.class || cls == long.class) {
|
||||
return 0L;
|
||||
}
|
||||
if (cls.isInterface()) {
|
||||
return null;
|
||||
}
|
||||
if (Modifier.isAbstract(cls.getModifiers())) {
|
||||
return null;
|
||||
}
|
||||
return cls.newInstance();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static boolean addToList(Object object, Field field, int index) {
|
||||
if (!List.class.isAssignableFrom(field.getType())) {
|
||||
return false;
|
||||
}
|
||||
List list;
|
||||
try {
|
||||
list = (List) field.get(object);
|
||||
} catch (IllegalArgumentException | IllegalAccessException ex) {
|
||||
Logger.getLogger(ReflectionTools.class.getName()).log(Level.SEVERE, null, ex);
|
||||
return false;
|
||||
}
|
||||
ParameterizedType listType = (ParameterizedType) field.getGenericType();
|
||||
Class<?> parameterClass = (Class<?>) listType.getActualTypeArguments()[0];
|
||||
try {
|
||||
Object val = newInstanceOf(parameterClass);
|
||||
if (val == null) {
|
||||
return false;
|
||||
}
|
||||
list.add(index, val);
|
||||
} catch (InstantiationException | IllegalAccessException ex) {
|
||||
Logger.getLogger(ReflectionTools.class.getName()).log(Level.SEVERE, null, ex);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
Object arrValue;
|
||||
try {
|
||||
arrValue = field.get(object);
|
||||
} catch (IllegalArgumentException | IllegalAccessException ex) {
|
||||
Logger.getLogger(ReflectionTools.class.getName()).log(Level.SEVERE, null, ex);
|
||||
return false;
|
||||
}
|
||||
Class componentClass = arrValue.getClass().getComponentType();
|
||||
Object val = null;
|
||||
if (!componentClass.isPrimitive()) {
|
||||
try {
|
||||
val = newInstanceOf(componentClass);
|
||||
} catch (InstantiationException | IllegalAccessException ex) {
|
||||
Logger.getLogger(ReflectionTools.class.getName()).log(Level.SEVERE, null, ex);
|
||||
return false;
|
||||
}
|
||||
if (val == null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int originalSize = Array.getLength(arrValue);
|
||||
Object copy = Array.newInstance(componentClass, originalSize + 1);
|
||||
|
||||
//Copy items before
|
||||
for (int i = 0; i < index; i++) {
|
||||
Array.set(copy, i, Array.get(arrValue, i));
|
||||
}
|
||||
if (val != null) {
|
||||
Array.set(copy, index, val);
|
||||
}
|
||||
//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) {
|
||||
Logger.getLogger(ReflectionTools.class.getName()).log(Level.SEVERE, null, ex);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean addToField(Object object, Field field, int index, boolean notnull) {
|
||||
if (List.class.isAssignableFrom(field.getType())) {
|
||||
return addToList(object, field, index);
|
||||
}
|
||||
|
||||
if (field.getType().isArray()) {
|
||||
return addToArray(object, field, index, notnull);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean removeFromField(Object object, Field field, int index) {
|
||||
if (List.class.isAssignableFrom(field.getType())) {
|
||||
return removeFromList(object, field, index);
|
||||
}
|
||||
|
||||
if (field.getType().isArray()) {
|
||||
return removeFromArray(object, field, index);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean removeFromList(Object object, Field field, int index) {
|
||||
List list;
|
||||
try {
|
||||
list = (List) field.get(object);
|
||||
} catch (IllegalArgumentException | IllegalAccessException ex) {
|
||||
Logger.getLogger(ReflectionTools.class.getName()).log(Level.SEVERE, null, ex);
|
||||
return false;
|
||||
}
|
||||
if (index < 0 || index >= list.size()) {
|
||||
return false;
|
||||
}
|
||||
list.remove(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean removeFromArray(Object object, Field field, int index) {
|
||||
Object arrValue;
|
||||
try {
|
||||
arrValue = field.get(object);
|
||||
} catch (IllegalArgumentException | IllegalAccessException ex) {
|
||||
Logger.getLogger(ReflectionTools.class.getName()).log(Level.SEVERE, null, ex);
|
||||
return false;
|
||||
}
|
||||
Class componentClass = arrValue.getClass().getComponentType();
|
||||
int originalSize = Array.getLength(arrValue);
|
||||
Object copy = Array.newInstance(componentClass, originalSize - 1);
|
||||
int pos = 0;
|
||||
//copy all before index
|
||||
for (int i = 0; i < index; i++) {
|
||||
Array.set(copy, pos, Array.get(arrValue, i));
|
||||
pos++;
|
||||
}
|
||||
//copy all after index
|
||||
for (int i = index + 1; i < originalSize; i++) {
|
||||
Array.set(copy, pos, Array.get(arrValue, i));
|
||||
pos++;
|
||||
}
|
||||
try {
|
||||
field.set(object, copy);
|
||||
} catch (IllegalArgumentException | IllegalAccessException ex) {
|
||||
Logger.getLogger(ReflectionTools.class.getName()).log(Level.SEVERE, null, ex);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user