mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-05-22 13:26:27 +00:00
feat(xml export): allow external as1/2 scripts, images and defineSounds (#2707)
This commit is contained in:
@@ -1240,6 +1240,10 @@ public final class Configuration {
|
||||
@ConfigurationDefaultBoolean(true)
|
||||
@ConfigurationCategory("display")
|
||||
public static ConfigurationItem<Boolean> showLoadingSpinner = null;
|
||||
|
||||
@ConfigurationDefaultString("")
|
||||
@ConfigurationName("xmlExport.formats")
|
||||
public static ConfigurationItem<String> lastSelectedXmlExportFormats = null;
|
||||
|
||||
private static Map<String, String> configurationDescriptions = new LinkedHashMap<>();
|
||||
private static Map<String, String> configurationTitles = new LinkedHashMap<>();
|
||||
|
||||
@@ -56,6 +56,41 @@ import javax.imageio.ImageIO;
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ImageExporter {
|
||||
|
||||
|
||||
private static ImageFormat getExportFormat(ImageTag imageTag, ImageExportSettings settings) {
|
||||
ImageFormat fileFormat = imageTag.getOriginalImageFormat();
|
||||
boolean hasSeparateAlpha = false;
|
||||
if (imageTag instanceof HasSeparateAlphaChannel) {
|
||||
HasSeparateAlphaChannel hsac = (HasSeparateAlphaChannel) imageTag;
|
||||
hasSeparateAlpha = hsac.hasAlphaChannel();
|
||||
}
|
||||
if (settings.mode == ImageExportMode.PNG_GIF_JPEG && hasSeparateAlpha) {
|
||||
fileFormat = ImageFormat.PNG;
|
||||
}
|
||||
if (settings.mode == ImageExportMode.PNG) {
|
||||
fileFormat = ImageFormat.PNG;
|
||||
}
|
||||
|
||||
if (settings.mode == ImageExportMode.JPEG) {
|
||||
fileFormat = ImageFormat.JPEG;
|
||||
}
|
||||
|
||||
if (settings.mode == ImageExportMode.BMP) {
|
||||
fileFormat = ImageFormat.BMP;
|
||||
}
|
||||
|
||||
if (settings.mode == ImageExportMode.WEBP) {
|
||||
fileFormat = ImageFormat.WEBP;
|
||||
}
|
||||
return fileFormat;
|
||||
}
|
||||
|
||||
public static String getExportExtension(ImageTag imageTag, ImageExportSettings settings) {
|
||||
ImageFormat fileFormat = getExportFormat(imageTag, settings);
|
||||
|
||||
return ImageHelper.getImageFormatString(fileFormat);
|
||||
}
|
||||
|
||||
public List<File> exportImages(AbortRetryIgnoreHandler handler, String outdir, ReadOnlyTagList tags, ImageExportSettings settings, EventListener evl) throws IOException, InterruptedException {
|
||||
List<File> ret = new ArrayList<>();
|
||||
@@ -90,31 +125,9 @@ public class ImageExporter {
|
||||
|
||||
final ImageTag imageTag = (ImageTag) t;
|
||||
|
||||
ImageFormat fileFormat = imageTag.getOriginalImageFormat();
|
||||
ImageFormat originalFormat = fileFormat;
|
||||
boolean hasSeparateAlpha = false;
|
||||
if (imageTag instanceof HasSeparateAlphaChannel) {
|
||||
HasSeparateAlphaChannel hsac = (HasSeparateAlphaChannel) imageTag;
|
||||
hasSeparateAlpha = hsac.hasAlphaChannel();
|
||||
}
|
||||
if (settings.mode == ImageExportMode.PNG_GIF_JPEG && hasSeparateAlpha) {
|
||||
fileFormat = ImageFormat.PNG;
|
||||
}
|
||||
if (settings.mode == ImageExportMode.PNG) {
|
||||
fileFormat = ImageFormat.PNG;
|
||||
}
|
||||
|
||||
if (settings.mode == ImageExportMode.JPEG) {
|
||||
fileFormat = ImageFormat.JPEG;
|
||||
}
|
||||
|
||||
if (settings.mode == ImageExportMode.BMP) {
|
||||
fileFormat = ImageFormat.BMP;
|
||||
}
|
||||
|
||||
if (settings.mode == ImageExportMode.WEBP) {
|
||||
fileFormat = ImageFormat.WEBP;
|
||||
}
|
||||
|
||||
ImageFormat originalFormat = imageTag.getOriginalImageFormat();
|
||||
ImageFormat fileFormat = getExportFormat(imageTag, settings);
|
||||
|
||||
final File file = new File(outdir + File.separator + Helper.makeFileName(imageTag.getCharacterExportFileName() + "." + ImageHelper.getImageFormatString(fileFormat)));
|
||||
|
||||
|
||||
@@ -64,6 +64,27 @@ import java.util.Set;
|
||||
*/
|
||||
public class SoundExporter {
|
||||
|
||||
public static String getExportExtension(SoundTag soundTag, SoundExportSettings settings) {
|
||||
String ext = "wav";
|
||||
SoundFormat fmt = soundTag.getSoundFormat();
|
||||
switch (fmt.getNativeExportFormat()) {
|
||||
case MP3:
|
||||
if (settings.mode.hasMP3()) {
|
||||
ext = "mp3";
|
||||
}
|
||||
break;
|
||||
case FLV:
|
||||
if (settings.mode.hasFlv()) {
|
||||
ext = "flv";
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (settings.mode == SoundExportMode.FLV) {
|
||||
ext = "flv";
|
||||
}
|
||||
return ext;
|
||||
}
|
||||
|
||||
public List<File> exportSounds(AbortRetryIgnoreHandler handler, String outdir, ReadOnlyTagList tags, final SoundExportSettings settings, EventListener evl) throws IOException, InterruptedException {
|
||||
List<SoundTag> sounds = new ArrayList<>();
|
||||
for (Tag t : tags) {
|
||||
@@ -72,7 +93,7 @@ public class SoundExporter {
|
||||
}
|
||||
}
|
||||
return exportSounds(handler, outdir, sounds, settings, evl);
|
||||
}
|
||||
}
|
||||
|
||||
public List<File> exportSounds(AbortRetryIgnoreHandler handler, String outdir, List<SoundTag> tags, final SoundExportSettings settings, EventListener evl) throws IOException, InterruptedException {
|
||||
List<File> ret = new ArrayList<>();
|
||||
@@ -97,24 +118,7 @@ public class SoundExporter {
|
||||
evl.handleExportingEvent("sound", currentIndex, tags.size(), st.getName());
|
||||
}
|
||||
|
||||
String ext = ".wav";
|
||||
SoundFormat fmt = st.getSoundFormat();
|
||||
switch (fmt.getNativeExportFormat()) {
|
||||
case MP3:
|
||||
if (settings.mode.hasMP3()) {
|
||||
ext = ".mp3";
|
||||
}
|
||||
break;
|
||||
case FLV:
|
||||
if (settings.mode.hasFlv()) {
|
||||
ext = ".flv";
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (settings.mode == SoundExportMode.FLV) {
|
||||
ext = ".flv";
|
||||
}
|
||||
|
||||
String ext = "." + getExportExtension(st, settings);
|
||||
final File file = new File(outdir + File.separator + Helper.makeFileName(st.getCharacterExportFileName()) + ext);
|
||||
new RetryTask(() -> {
|
||||
try (OutputStream os = new BufferedOutputStream(new FileOutputStream(file))) {
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2026 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.exporters.settings;
|
||||
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ImageExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.SoundExportMode;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class XmlSwfExportSettings {
|
||||
public ScriptExportMode as12ExportMode;
|
||||
public ImageExportMode imageExportMode;
|
||||
public SoundExportMode defineSoundExportMode;
|
||||
|
||||
public XmlSwfExportSettings() {
|
||||
}
|
||||
|
||||
public XmlSwfExportSettings(ScriptExportMode as12ExportMode, ImageExportMode imageExportMode, SoundExportMode defineSoundExportMode) {
|
||||
if (as12ExportMode != null && as12ExportMode != ScriptExportMode.AS) {
|
||||
throw new IllegalArgumentException("Unsupported script export mode");
|
||||
}
|
||||
this.as12ExportMode = as12ExportMode;
|
||||
if (
|
||||
imageExportMode != null
|
||||
&& imageExportMode != ImageExportMode.PNG_GIF_JPEG
|
||||
&& imageExportMode != ImageExportMode.PNG_GIF_JPEG_ALPHA
|
||||
) {
|
||||
throw new IllegalArgumentException("Unsupported image export mode");
|
||||
}
|
||||
this.imageExportMode = imageExportMode;
|
||||
if (defineSoundExportMode != null && defineSoundExportMode != SoundExportMode.MP3_WAV_FLV) {
|
||||
throw new IllegalArgumentException("Unsupported sound export mode");
|
||||
}
|
||||
this.defineSoundExportMode = defineSoundExportMode;
|
||||
}
|
||||
}
|
||||
@@ -16,12 +16,31 @@
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.exporters.swf;
|
||||
|
||||
import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler;
|
||||
import com.jpexs.decompiler.flash.ApplicationInfo;
|
||||
import com.jpexs.decompiler.flash.EventListener;
|
||||
import com.jpexs.decompiler.flash.ReadOnlyTagList;
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.exporters.ImageExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.SoundExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ImageExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.script.AS2ScriptExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.settings.ImageExportSettings;
|
||||
import com.jpexs.decompiler.flash.exporters.settings.ScriptExportSettings;
|
||||
import com.jpexs.decompiler.flash.exporters.settings.SoundExportSettings;
|
||||
import com.jpexs.decompiler.flash.exporters.settings.XmlSwfExportSettings;
|
||||
import com.jpexs.decompiler.flash.helpers.InternalClass;
|
||||
import com.jpexs.decompiler.flash.helpers.LazyObject;
|
||||
import com.jpexs.decompiler.flash.tags.DefineButtonTag;
|
||||
import com.jpexs.decompiler.flash.tags.DefineSoundTag;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.tags.UnknownTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ASMSource;
|
||||
import com.jpexs.decompiler.flash.tags.base.ButtonAction;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ImageTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.SoundTag;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Conditional;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Internal;
|
||||
import com.jpexs.decompiler.flash.types.annotations.parser.AnnotationParseException;
|
||||
@@ -39,8 +58,12 @@ import java.io.Writer;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
@@ -62,9 +85,11 @@ public class SwfXmlExporter {
|
||||
*/
|
||||
public static final int XML_EXPORT_VERSION_MAJOR = 2;
|
||||
|
||||
public static final int XML_EXPORT_VERSION_MAJOR_WITH_EXTERNAL_FILES = 3;
|
||||
|
||||
/**
|
||||
* XML export version minor.
|
||||
*
|
||||
*
|
||||
* Version 2 - export only fields that meet conditions
|
||||
*/
|
||||
public static final int XML_EXPORT_VERSION_MINOR = 2;
|
||||
@@ -81,16 +106,100 @@ public class SwfXmlExporter {
|
||||
* @throws IOException On I/O error
|
||||
*/
|
||||
public void exportXml(SWF swf, File outFile) throws IOException {
|
||||
exportXml(swf, outFile, new XmlSwfExportSettings(), null, new AbortRetryIgnoreHandler() {
|
||||
@Override
|
||||
public int handle(Throwable thrown) {
|
||||
return AbortRetryIgnoreHandler.ABORT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbortRetryIgnoreHandler getNewInstance() {
|
||||
return this;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports SWF to XML.
|
||||
*
|
||||
* @param swf SWF to export
|
||||
* @param outFile Target file to save to
|
||||
* @param settings Export settings
|
||||
* @param evl Event listener
|
||||
* @param handler Abort/Retry/Ignore handler
|
||||
*
|
||||
* @throws IOException On I/O error
|
||||
*/
|
||||
public void exportXml(SWF swf, File outFile, XmlSwfExportSettings settings, EventListener evl, AbortRetryIgnoreHandler handler) throws IOException {
|
||||
try {
|
||||
File tmp = File.createTempFile("FFDEC", "XML");
|
||||
|
||||
String assetsDirName = outFile.getName();
|
||||
if (assetsDirName.contains(".")) {
|
||||
assetsDirName = assetsDirName.substring(0, assetsDirName.lastIndexOf("."));
|
||||
}
|
||||
assetsDirName = assetsDirName + "_assets";
|
||||
|
||||
Map<ASMSource, String> asmExternalFiles = new HashMap<>();
|
||||
if (settings.as12ExportMode != null) {
|
||||
Map<String, ASMSource> externalNameToAsm = swf.getASMs(true);
|
||||
Set<String> existingNames = new HashSet<>();
|
||||
for (String key : externalNameToAsm.keySet()) {
|
||||
ASMSource asm = externalNameToAsm.get(key);
|
||||
String currentOutDir = key + "/";
|
||||
currentOutDir = new File(currentOutDir).getParentFile().toString();
|
||||
currentOutDir = currentOutDir.replace("\\", "/");
|
||||
if (!"/".equals(currentOutDir)) {
|
||||
currentOutDir += "/";
|
||||
}
|
||||
String name = Helper.makeFileName(asm.getExportFileName());
|
||||
int i = 1;
|
||||
String baseName = name;
|
||||
while (existingNames.contains(currentOutDir + name)) {
|
||||
i++;
|
||||
name = baseName + "_" + i;
|
||||
}
|
||||
existingNames.add(currentOutDir + name);
|
||||
asmExternalFiles.put(asm, assetsDirName + "/scripts" + currentOutDir + name + ".as");
|
||||
}
|
||||
}
|
||||
|
||||
Map<Tag, String> tagExternalFiles = new IdentityHashMap<>();
|
||||
List<Tag> imagesList = new ArrayList<>();
|
||||
if (settings.imageExportMode != null) {
|
||||
ImageExportSettings imageExportSetttings = new ImageExportSettings(settings.imageExportMode);
|
||||
Map<Integer, CharacterTag> chars = swf.getCharacters(false);
|
||||
for (int charId : chars.keySet()) {
|
||||
CharacterTag ch = chars.get(charId);
|
||||
if (ch instanceof ImageTag) {
|
||||
ImageTag imageTag = (ImageTag) ch;
|
||||
tagExternalFiles.put(imageTag, assetsDirName + "/images/" + Helper.makeFileName(imageTag.getCharacterExportFileName()) + "." + ImageExporter.getExportExtension(imageTag, imageExportSetttings));
|
||||
imagesList.add(imageTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<SoundTag> soundList = new ArrayList<>();
|
||||
if (settings.defineSoundExportMode != null) {
|
||||
SoundExportSettings soundExportSetttings = new SoundExportSettings(settings.defineSoundExportMode);
|
||||
Map<Integer, CharacterTag> chars = swf.getCharacters(false);
|
||||
for (int charId : chars.keySet()) {
|
||||
CharacterTag ch = chars.get(charId);
|
||||
if (ch instanceof DefineSoundTag) {
|
||||
DefineSoundTag soundTag = (DefineSoundTag) ch;
|
||||
tagExternalFiles.put(soundTag, assetsDirName + "/sounds/" + Helper.makeFileName(soundTag.getCharacterExportFileName()) + "." + SoundExporter.getExportExtension(soundTag, soundExportSetttings));
|
||||
soundList.add(soundTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try (Writer writer = new Utf8OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(tmp)))) {
|
||||
XMLStreamWriter xmlWriter = XMLOutputFactory.newInstance().createXMLStreamWriter(writer);
|
||||
|
||||
xmlWriter.writeStartDocument();
|
||||
xmlWriter.writeComment("\r\nWARNING: The structure of this XML is not final.\r\nIn later versions of FFDec it can be changed.\r\nMake sure you use compatible reader/writer based on _xmlExportMajor/_xmlExportMinor keys.\r\n");
|
||||
|
||||
exportXml(swf, xmlWriter);
|
||||
exportXml(asmExternalFiles, tagExternalFiles, swf, xmlWriter);
|
||||
|
||||
xmlWriter.writeEndDocument();
|
||||
xmlWriter.flush();
|
||||
@@ -106,6 +215,27 @@ public class SwfXmlExporter {
|
||||
logger.log(Level.SEVERE, "Cannot prettyformat XML");
|
||||
}
|
||||
tmp.delete();
|
||||
|
||||
if (settings.as12ExportMode != null) {
|
||||
AS2ScriptExporter exporter = new AS2ScriptExporter();
|
||||
exporter.exportActionScript2(swf, handler, outFile.getParentFile().toPath().resolve(assetsDirName + "/scripts").toFile().getAbsolutePath(), new ScriptExportSettings(settings.as12ExportMode, false, false, false, false), true, evl);
|
||||
}
|
||||
if (settings.imageExportMode != null) {
|
||||
ImageExporter exporter = new ImageExporter();
|
||||
try {
|
||||
exporter.exportImages(handler, outFile.getParentFile().toPath().resolve(assetsDirName + "/images").toFile().getAbsolutePath(), new ReadOnlyTagList(imagesList), new ImageExportSettings(settings.imageExportMode), evl);
|
||||
} catch (InterruptedException ex) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (settings.defineSoundExportMode != null) {
|
||||
SoundExporter exporter = new SoundExporter();
|
||||
try {
|
||||
exporter.exportSounds(handler, outFile.getParentFile().toPath().resolve(assetsDirName + "/sounds").toFile().getAbsolutePath(), soundList, new SoundExportSettings(settings.defineSoundExportMode), evl);
|
||||
} catch (InterruptedException ex) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (XMLStreamException ex) {
|
||||
logger.log(Level.SEVERE, null, ex);
|
||||
}
|
||||
@@ -114,13 +244,30 @@ public class SwfXmlExporter {
|
||||
/**
|
||||
* Exports SWF to XML.
|
||||
*
|
||||
* @param asmExternalFiles ASM external files
|
||||
* @param tagExternalFiles Tag external files
|
||||
* @param swf SWF to export
|
||||
* @param writer XML writer
|
||||
* @throws IOException On I/O error
|
||||
* @throws XMLStreamException On XML error
|
||||
*/
|
||||
public void exportXml(SWF swf, XMLStreamWriter writer) throws IOException, XMLStreamException {
|
||||
generateXml(swf, null, writer, "swf", swf, false);
|
||||
private void exportXml(
|
||||
Map<ASMSource, String> asmExternalFiles,
|
||||
Map<Tag, String> tagExternalFiles,
|
||||
SWF swf,
|
||||
XMLStreamWriter writer
|
||||
) throws IOException, XMLStreamException {
|
||||
generateXml(
|
||||
asmExternalFiles.isEmpty() && tagExternalFiles.isEmpty() ? XML_EXPORT_VERSION_MAJOR : XML_EXPORT_VERSION_MAJOR_WITH_EXTERNAL_FILES,
|
||||
asmExternalFiles,
|
||||
tagExternalFiles,
|
||||
swf,
|
||||
null,
|
||||
writer,
|
||||
"swf",
|
||||
swf,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
public List<Field> getSwfFieldsCached(Class cls) {
|
||||
@@ -173,7 +320,17 @@ public class SwfXmlExporter {
|
||||
return cls != null && (cls.isArray() || List.class.isAssignableFrom(cls));
|
||||
}
|
||||
|
||||
private void generateXml(SWF swf, Tag currentTag, XMLStreamWriter writer, String name, Object obj, boolean isListItem) throws XMLStreamException {
|
||||
private void generateXml(
|
||||
int major,
|
||||
Map<ASMSource, String> asmExternalFiles,
|
||||
Map<Tag, String> tagExternalFiles,
|
||||
SWF swf,
|
||||
Tag currentTag,
|
||||
XMLStreamWriter writer,
|
||||
String name,
|
||||
Object obj,
|
||||
boolean isListItem
|
||||
) throws XMLStreamException {
|
||||
Class cls = obj != null ? obj.getClass() : null;
|
||||
|
||||
/*if (obj != null && cls == String.class) {
|
||||
@@ -221,7 +378,7 @@ public class SwfXmlExporter {
|
||||
writer.writeStartElement(name);
|
||||
int length = Array.getLength(value);
|
||||
for (int i = 0; i < length; i++) {
|
||||
generateXml(swf, currentTag, writer, "item", Array.get(value, i), true);
|
||||
generateXml(major, asmExternalFiles, tagExternalFiles, swf, currentTag, writer, "item", Array.get(value, i), true);
|
||||
}
|
||||
writer.writeEndElement();
|
||||
} else if (obj != null) {
|
||||
@@ -239,16 +396,12 @@ public class SwfXmlExporter {
|
||||
writer.writeStartElement(name);
|
||||
|
||||
if (obj instanceof SWF) {
|
||||
writer.writeAttribute("_xmlExportMajor", "" + XML_EXPORT_VERSION_MAJOR);
|
||||
writer.writeAttribute("_xmlExportMajor", "" + major);
|
||||
writer.writeAttribute("_xmlExportMinor", "" + XML_EXPORT_VERSION_MINOR);
|
||||
writer.writeAttribute("_generator", ApplicationInfo.applicationVerName);
|
||||
swf = (SWF) obj;
|
||||
}
|
||||
|
||||
if (obj instanceof Tag) {
|
||||
currentTag = (Tag) obj;
|
||||
}
|
||||
|
||||
writer.writeAttribute("type", clazz.getSimpleName());
|
||||
|
||||
if (obj instanceof UnknownTag) {
|
||||
@@ -258,8 +411,23 @@ public class SwfXmlExporter {
|
||||
writer.writeAttribute("charset", ((SWF) obj).getCharset());
|
||||
}
|
||||
|
||||
boolean isExternal = false;
|
||||
|
||||
if (obj instanceof Tag) {
|
||||
currentTag = (Tag) obj;
|
||||
|
||||
if (tagExternalFiles.containsKey((Tag) obj)) {
|
||||
writer.writeAttribute("_externalFile", tagExternalFiles.get((Tag) obj));
|
||||
isExternal = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (Field f : fields) {
|
||||
//Multiline multilineA = f.getAnnotation(Multiline.class);
|
||||
//Multiline multilineA = f.getAnnotation(Multiline.class);
|
||||
|
||||
if (isExternal && !"characterID".equals(f.getName()) && !"soundId".equals(f.getName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Conditional cond = f.getAnnotation(Conditional.class);
|
||||
if (cond != null) {
|
||||
@@ -297,7 +465,26 @@ public class SwfXmlExporter {
|
||||
|
||||
try {
|
||||
f.setAccessible(true);
|
||||
generateXml(swf, currentTag, writer, f.getName(), f.get(obj), false);
|
||||
Object value = f.get(obj);
|
||||
|
||||
if ("actionBytes".equals(f.getName())) {
|
||||
if (obj instanceof ASMSource && asmExternalFiles.containsKey((ASMSource) obj)) {
|
||||
value = new ByteArrayRange("00");
|
||||
writer.writeAttribute("_externalActions", asmExternalFiles.get((ASMSource) obj));
|
||||
} else if (obj instanceof DefineButtonTag) {
|
||||
for (ASMSource s : asmExternalFiles.keySet()) {
|
||||
if (s instanceof ButtonAction) {
|
||||
ButtonAction ba = (ButtonAction) s;
|
||||
if (ba.getSourceTag() == obj) {
|
||||
value = new ByteArrayRange("00");
|
||||
writer.writeAttribute("_externalActions", asmExternalFiles.get(s));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
generateXml(major, asmExternalFiles, tagExternalFiles, swf, currentTag, writer, f.getName(), value, false);
|
||||
} catch (IllegalArgumentException | IllegalAccessException ex) {
|
||||
logger.log(Level.SEVERE, null, ex);
|
||||
}
|
||||
|
||||
@@ -44,7 +44,6 @@ public class AS2ScriptImporter {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(AS2ScriptImporter.class.getName());
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
@@ -52,8 +51,58 @@ public class AS2ScriptImporter {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports actionScript 1/2 (not P-code) from given file
|
||||
*
|
||||
* @param fileName File to import
|
||||
* @param asm Target to import into
|
||||
* @param listener Import listener
|
||||
* @return True on success
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public boolean importActionScript(String fileName, ASMSource asm, ScriptImporterProgressListener listener) throws InterruptedException {
|
||||
asm.getSwf().informListeners("importing_as", fileName);
|
||||
String txt = Helper.readTextFile(fileName);
|
||||
|
||||
ActionScript2Parser par = new ActionScript2Parser(asm.getSwf(), asm);
|
||||
boolean errored = false;
|
||||
try {
|
||||
asm.setActions(par.actionsFromString(txt, asm.getSwf().getCharset()));
|
||||
} catch (ValueTooLargeException ex) {
|
||||
logger.log(Level.SEVERE, "Script or some of its functions are too large, file: {0}", fileName);
|
||||
errored = true;
|
||||
} catch (ActionParseException ex) {
|
||||
logger.log(Level.SEVERE, "%error% on line %line%, file: %file%".replace("%error%", ex.text).replace("%line%", Long.toString(ex.line)).replace("%file%", fileName), ex);
|
||||
errored = true;
|
||||
} catch (CompilationException ex) {
|
||||
logger.log(Level.SEVERE, "%error% on line %line%, file: %file%".replace("%error%", ex.text).replace("%line%", Long.toString(ex.line)).replace("%file%", fileName), ex);
|
||||
errored = true;
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.SEVERE, "error during script import, file: %file%".replace("%file%", fileName), ex);
|
||||
errored = true;
|
||||
} catch (InterruptedException ex) {
|
||||
throw ex;
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.SEVERE, "error during script import, file: %file%".replace("%file%", fileName), ex);
|
||||
errored = true;
|
||||
}
|
||||
|
||||
if (!errored) {
|
||||
asm.setModified();
|
||||
if (listener != null) {
|
||||
listener.scriptImported();
|
||||
}
|
||||
} else {
|
||||
if (listener != null) {
|
||||
listener.scriptImportError();
|
||||
}
|
||||
}
|
||||
return !errored;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports scripts from given folder.
|
||||
*
|
||||
* @param scriptsFolder Folder with scripts
|
||||
* @param asms Map of ASMSource objects
|
||||
* @return Number of imported scripts
|
||||
@@ -65,6 +114,7 @@ public class AS2ScriptImporter {
|
||||
|
||||
/**
|
||||
* Imports scripts from given folder.
|
||||
*
|
||||
* @param scriptsFolder Folder with scripts
|
||||
* @param asms Map of ASMSource objects
|
||||
* @param listener Progress listener
|
||||
@@ -104,42 +154,12 @@ public class AS2ScriptImporter {
|
||||
|
||||
String fileName = Path.combine(currentOutDir, name) + ".as";
|
||||
if (new File(fileName).exists()) {
|
||||
asm.getSwf().informListeners("importing_as", fileName);
|
||||
String txt = Helper.readTextFile(fileName);
|
||||
|
||||
ActionScript2Parser par = new ActionScript2Parser(asm.getSwf(), asm);
|
||||
boolean errored = false;
|
||||
try {
|
||||
asm.setActions(par.actionsFromString(txt, asm.getSwf().getCharset()));
|
||||
} catch (ValueTooLargeException ex) {
|
||||
logger.log(Level.SEVERE, "Script or some of its functions are too large, file: {0}", fileName);
|
||||
errored = true;
|
||||
} catch (ActionParseException ex) {
|
||||
logger.log(Level.SEVERE, "%error% on line %line%, file: %file%".replace("%error%", ex.text).replace("%line%", Long.toString(ex.line)).replace("%file%", fileName), ex);
|
||||
errored = true;
|
||||
} catch (CompilationException ex) {
|
||||
logger.log(Level.SEVERE, "%error% on line %line%, file: %file%".replace("%error%", ex.text).replace("%line%", Long.toString(ex.line)).replace("%file%", fileName), ex);
|
||||
errored = true;
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.SEVERE, "error during script import, file: %file%".replace("%file%", fileName), ex);
|
||||
errored = true;
|
||||
if (importActionScript(fileName, asm, listener)) {
|
||||
importCount++;
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
return importCount;
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.SEVERE, "error during script import, file: %file%".replace("%file%", fileName), ex);
|
||||
errored = true;
|
||||
}
|
||||
|
||||
if (!errored) {
|
||||
asm.setModified();
|
||||
importCount++;
|
||||
if (listener != null) {
|
||||
listener.scriptImported();
|
||||
}
|
||||
} else {
|
||||
if (listener != null) {
|
||||
listener.scriptImportError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,11 +37,17 @@ import com.jpexs.decompiler.flash.abc.types.traits.TraitMethodGetterSetter;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Traits;
|
||||
import com.jpexs.decompiler.flash.amf.amf3.Amf3Value;
|
||||
import com.jpexs.decompiler.flash.exporters.swf.SwfXmlExporter;
|
||||
import com.jpexs.decompiler.flash.tags.CSMSettingsTag;
|
||||
import com.jpexs.decompiler.flash.tags.DefineButtonTag;
|
||||
import com.jpexs.decompiler.flash.tags.DefineSoundTag;
|
||||
import com.jpexs.decompiler.flash.tags.DefineSpriteTag;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.tags.TagTypeInfo;
|
||||
import com.jpexs.decompiler.flash.tags.UnknownTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ASMSource;
|
||||
import com.jpexs.decompiler.flash.tags.base.ImageTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.SoundImportException;
|
||||
import com.jpexs.decompiler.flash.types.ALPHABITMAPDATA;
|
||||
import com.jpexs.decompiler.flash.types.ALPHACOLORMAPDATA;
|
||||
import com.jpexs.decompiler.flash.types.ARGB;
|
||||
@@ -108,12 +114,16 @@ 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.decompiler.flash.types.sound.SoundFormat;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.HashArrayList;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import com.jpexs.helpers.IdentityKey;
|
||||
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.InputStream;
|
||||
import java.io.Reader;
|
||||
@@ -124,7 +134,9 @@ import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
@@ -145,7 +157,12 @@ public class SwfXmlImporter {
|
||||
/**
|
||||
* Maximum XML import version major.
|
||||
*/
|
||||
public static final int MAX_XML_IMPORT_VERSION_MAJOR = 2;
|
||||
public static final int MAX_XML_IMPORT_VERSION_MAJOR = 3;
|
||||
|
||||
/**
|
||||
* Minimum version for using external files - attributes _externalActions, _externalFile
|
||||
*/
|
||||
public static final int XML_IMPORT_VERSION_MAJOR_WITH_EXTERNAL_FILES = 3;
|
||||
|
||||
private static final Logger logger = Logger.getLogger(SwfXmlImporter.class.getName());
|
||||
|
||||
@@ -221,11 +238,15 @@ public class SwfXmlImporter {
|
||||
* Imports SWF from input stream.
|
||||
* @param swf SWF object
|
||||
* @param in Input stream
|
||||
* @param directory Directory where XML resides for external files resolving
|
||||
* @throws IOException On I/O error
|
||||
*/
|
||||
public void importSwf(SWF swf, InputStream in) throws IOException {
|
||||
public void importSwf(SWF swf, InputStream in, File directory) throws IOException {
|
||||
XMLInputFactory xmlFactory = XMLInputFactory.newInstance();
|
||||
|
||||
Map<IdentityKey<Object>, String> asmExternalActions = new LinkedHashMap<>();
|
||||
Map<IdentityKey<Tag>, String> tagExternalFiles = new LinkedHashMap<>();
|
||||
|
||||
try {
|
||||
try (Reader reader = new Utf8InputStreamReader(new BufferedInputStream(in))) {
|
||||
XMLStreamReader xmlReader = xmlFactory.createXMLStreamReader(reader);
|
||||
@@ -233,7 +254,7 @@ public class SwfXmlImporter {
|
||||
xmlReader.nextTag();
|
||||
xmlReader.require(XMLStreamConstants.START_ELEMENT, null, "swf");
|
||||
|
||||
processElement(xmlReader, swf, swf, null, MAX_XML_IMPORT_VERSION_MAJOR);
|
||||
processElement(xmlReader, swf, swf, null, MAX_XML_IMPORT_VERSION_MAJOR, asmExternalActions, tagExternalFiles);
|
||||
}
|
||||
|
||||
swf.clearAllCache();
|
||||
@@ -241,16 +262,78 @@ public class SwfXmlImporter {
|
||||
} catch (XMLStreamException ex) {
|
||||
logger.log(Level.SEVERE, null, ex);
|
||||
}
|
||||
|
||||
if (!asmExternalActions.isEmpty()) {
|
||||
for (IdentityKey<Object> objKey : asmExternalActions.keySet()) {
|
||||
ASMSource asm = null;
|
||||
String fileName = asmExternalActions.get(objKey);
|
||||
Object obj = objKey.get();
|
||||
if (obj instanceof ASMSource) {
|
||||
asm = (ASMSource) obj;
|
||||
}
|
||||
if (obj instanceof DefineButtonTag) {
|
||||
DefineButtonTag defineButton = (DefineButtonTag) obj;
|
||||
asm = defineButton.getSubItems().get(0);
|
||||
}
|
||||
if (asm != null) {
|
||||
AS2ScriptImporter importer = new AS2ScriptImporter();
|
||||
try {
|
||||
importer.importActionScript(directory.toPath().resolve(fileName).toFile().getAbsolutePath(), asm, null);
|
||||
} catch (InterruptedException ex) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!tagExternalFiles.isEmpty()) {
|
||||
for (IdentityKey<Tag> tagKey : tagExternalFiles.keySet()) {
|
||||
String fileName = tagExternalFiles.get(tagKey);
|
||||
Tag tag = tagKey.get();
|
||||
if (tag == null) {
|
||||
continue;
|
||||
}
|
||||
if (tag instanceof ImageTag) {
|
||||
ImageTag imageTag = (ImageTag) tag;
|
||||
ImageImporter importer = new ImageImporter();
|
||||
importer.importImage(imageTag, Helper.readFile(directory.toPath().resolve(fileName).toFile().getAbsolutePath()), -1);
|
||||
String baseName = new File(fileName).getName();
|
||||
if (baseName.contains(".")) {
|
||||
baseName = baseName.substring(0, baseName.lastIndexOf("."));
|
||||
}
|
||||
String alphaFile = new File(fileName).getParentFile().getAbsolutePath() + "/" + baseName + ".alpha.png";
|
||||
|
||||
if (new File(alphaFile).exists()) {
|
||||
importer.importImageAlpha(imageTag, Helper.readFile(alphaFile));
|
||||
}
|
||||
} else if (tag instanceof DefineSoundTag) {
|
||||
DefineSoundTag defineSoundTag = (DefineSoundTag) tag;
|
||||
SoundImporter importer = new SoundImporter();
|
||||
int format = SoundFormat.FORMAT_UNCOMPRESSED_LITTLE_ENDIAN;
|
||||
if (fileName.toLowerCase(Locale.ENGLISH).endsWith(".mp3")) {
|
||||
format = SoundFormat.FORMAT_MP3;
|
||||
}
|
||||
try (FileInputStream fis = new FileInputStream(directory.toPath().resolve(fileName).toFile().getAbsolutePath())) {
|
||||
importer.importDefineSound(defineSoundTag, fis, format);
|
||||
} catch (SoundImportException ex) {
|
||||
logger.log(Level.SEVERE, "Cannot import sound", ex);
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.SEVERE, "Cannot read sound", ex);
|
||||
}
|
||||
} else {
|
||||
logger.log(Level.WARNING, "Unrecognized tag type for external file: {0}", tag.getTagName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setSwfAndTimelined(SWF swf) {
|
||||
for (Tag t : swf.getTags()) {
|
||||
t.setSwf(swf);
|
||||
t.setSwf(swf, true);
|
||||
t.setTimelined(swf);
|
||||
if (t instanceof DefineSpriteTag) {
|
||||
DefineSpriteTag s = (DefineSpriteTag) t;
|
||||
for (Tag st : s.getTags()) {
|
||||
st.setSwf(swf);
|
||||
st.setSwf(swf, true);
|
||||
st.setTimelined(s);
|
||||
}
|
||||
}
|
||||
@@ -269,7 +352,7 @@ public class SwfXmlImporter {
|
||||
XMLInputFactory xmlFactory = XMLInputFactory.newInstance();
|
||||
try {
|
||||
XMLStreamReader reader = xmlFactory.createXMLStreamReader(new StringReader(xml));
|
||||
return processObject(reader, requiredType, swf, null, 1);
|
||||
return processObject(reader, requiredType, swf, null, 1, new HashMap<>(), new HashMap<>());
|
||||
} catch (IllegalArgumentException | IllegalAccessException | NoSuchMethodException | InstantiationException
|
||||
| InvocationTargetException | XMLStreamException ex) {
|
||||
Logger.getLogger(SwfXmlImporter.class.getName()).log(Level.SEVERE, null, ex);
|
||||
@@ -311,7 +394,7 @@ public class SwfXmlImporter {
|
||||
}*/
|
||||
}
|
||||
|
||||
private void processElement(XMLStreamReader reader, Object obj, SWF swf, Tag tag, int xmlExportMajor) throws XMLStreamException {
|
||||
private void processElement(XMLStreamReader reader, Object obj, SWF swf, Tag tag, int xmlExportMajor, Map<IdentityKey<Object>, String> asmExternalActions, Map<IdentityKey<Tag>, String> tagExternalFiles) throws XMLStreamException {
|
||||
// Check if element started and start if needed
|
||||
if (!reader.isStartElement()) {
|
||||
reader.nextTag();
|
||||
@@ -369,6 +452,30 @@ public class SwfXmlImporter {
|
||||
if (name.equals("reserved3") && "FileAttributesTag".equals(attributes.get("type"))) {
|
||||
name = "reservedB";
|
||||
}
|
||||
|
||||
if (name.equals("_externalActions")) {
|
||||
if (xmlExportMajor < XML_IMPORT_VERSION_MAJOR_WITH_EXTERNAL_FILES) {
|
||||
logger.log(Level.WARNING, "For _externalActions attribute _xmlExportMajor must be >= 3. The attribute is ignored.");
|
||||
continue;
|
||||
}
|
||||
asmExternalActions.put(new IdentityKey<>(obj), val);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (obj instanceof Tag && name.equals("_externalFile")) {
|
||||
if (xmlExportMajor < XML_IMPORT_VERSION_MAJOR_WITH_EXTERNAL_FILES) {
|
||||
logger.log(Level.WARNING, "For _externalFile attribute _xmlExportMajor must be >= 3. The attribute is ignored.");
|
||||
continue;
|
||||
}
|
||||
tagExternalFiles.put(new IdentityKey<>((Tag) obj), val);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (name.equals("actionBytes") && attributes.containsKey("_externalActions")) {
|
||||
if (xmlExportMajor >= XML_IMPORT_VERSION_MAJOR_WITH_EXTERNAL_FILES) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!name.equals("type")) {
|
||||
try {
|
||||
@@ -397,7 +504,7 @@ public class SwfXmlImporter {
|
||||
// Check for list item elements
|
||||
reader.nextTag();
|
||||
while (reader.isStartElement()) {
|
||||
Object childObj = processObject(reader, reqType, swf, tag, xmlExportMajor);
|
||||
Object childObj = processObject(reader, reqType, swf, tag, xmlExportMajor, asmExternalActions, tagExternalFiles);
|
||||
list.add(childObj);
|
||||
|
||||
reader.nextTag();
|
||||
@@ -414,7 +521,7 @@ public class SwfXmlImporter {
|
||||
|
||||
setFieldValue(field, obj, value);
|
||||
} else {
|
||||
Object childObj = processObject(reader, null, swf, tag, xmlExportMajor);
|
||||
Object childObj = processObject(reader, null, swf, tag, xmlExportMajor, asmExternalActions, tagExternalFiles);
|
||||
setFieldValue(field, obj, childObj);
|
||||
}
|
||||
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException
|
||||
@@ -432,7 +539,7 @@ public class SwfXmlImporter {
|
||||
}
|
||||
}
|
||||
|
||||
private Object processObject(XMLStreamReader reader, Class requiredType, SWF swf, Tag tag, int xmlExportMajor) throws IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InstantiationException, InvocationTargetException, XMLStreamException {
|
||||
private Object processObject(XMLStreamReader reader, Class requiredType, SWF swf, Tag tag, int xmlExportMajor, Map<IdentityKey<Object>, String> asmExternalActions, Map<IdentityKey<Tag>, String> tagExternalFiles) throws IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InstantiationException, InvocationTargetException, XMLStreamException {
|
||||
// Check if element started and start if needed
|
||||
if (!reader.isStartElement()) {
|
||||
reader.nextTag();
|
||||
@@ -465,7 +572,7 @@ public class SwfXmlImporter {
|
||||
tag = (Tag) childObj;
|
||||
}
|
||||
|
||||
processElement(reader, childObj, swf, tag, xmlExportMajor);
|
||||
processElement(reader, childObj, swf, tag, xmlExportMajor, asmExternalActions, tagExternalFiles);
|
||||
ret = childObj;
|
||||
} else {
|
||||
String isNullAttr = attributes.get("isNull");
|
||||
|
||||
@@ -377,4 +377,17 @@ public class DefineButton2Tag extends ButtonTag implements ASMSourceContainer {
|
||||
needed.add(rec.characterId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSwf(SWF swf, boolean deep) {
|
||||
super.setSwf(swf, deep);
|
||||
|
||||
if (deep) {
|
||||
if (actions != null) {
|
||||
for (BUTTONCONDACTION action : actions) {
|
||||
action.setSourceTag(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,5 +329,5 @@ public class DefineButtonTag extends ButtonTag implements ASMSourceContainer {
|
||||
for (BUTTONRECORD rec : characters) {
|
||||
needed.add(rec.characterId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.amf.amf3.Amf3Value;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.types.CLIPACTIONRECORD;
|
||||
import com.jpexs.decompiler.flash.types.CLIPACTIONS;
|
||||
import com.jpexs.decompiler.flash.types.ColorTransform;
|
||||
import com.jpexs.decompiler.flash.types.MATRIX;
|
||||
@@ -361,4 +362,19 @@ public abstract class PlaceObjectTypeTag extends Tag implements CharacterIdTag,
|
||||
result += "_" + getDepth();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSwf(SWF swf, boolean deep) {
|
||||
super.setSwf(swf, deep);
|
||||
|
||||
if (deep) {
|
||||
CLIPACTIONS clipActions = getClipActions();
|
||||
if (clipActions != null) {
|
||||
for (CLIPACTIONRECORD rec : clipActions.clipActionRecords) {
|
||||
rec.setParentClipActions(clipActions);
|
||||
rec.setSourceTag(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
44
libsrc/ffdec_lib/src/com/jpexs/helpers/IdentityKey.java
Normal file
44
libsrc/ffdec_lib/src/com/jpexs/helpers/IdentityKey.java
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2026 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.helpers;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class IdentityKey<T> {
|
||||
private final T value;
|
||||
|
||||
public IdentityKey(T value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return System.identityHashCode(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof IdentityKey
|
||||
&& ((IdentityKey<?>) obj).value == value;
|
||||
}
|
||||
|
||||
public T get() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -98,7 +98,7 @@ public class SwfXmlExportImportTest extends FileTestBase {
|
||||
|
||||
SWF swf2 = new SWF();
|
||||
try ( FileInputStream fis = new FileInputStream(outFile)) {
|
||||
new SwfXmlImporter().importSwf(swf2, fis);
|
||||
new SwfXmlImporter().importSwf(swf2, fis, outFile.getParentFile());
|
||||
}
|
||||
|
||||
if (swf.getTags().size() != swf2.getTags().size()) {
|
||||
|
||||
@@ -102,6 +102,7 @@ import com.jpexs.decompiler.flash.exporters.settings.SoundExportSettings;
|
||||
import com.jpexs.decompiler.flash.exporters.settings.SpriteExportSettings;
|
||||
import com.jpexs.decompiler.flash.exporters.settings.SymbolClassExportSettings;
|
||||
import com.jpexs.decompiler.flash.exporters.settings.TextExportSettings;
|
||||
import com.jpexs.decompiler.flash.exporters.settings.XmlSwfExportSettings;
|
||||
import com.jpexs.decompiler.flash.exporters.swf.SwfToSwcExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.swf.SwfXmlExporter;
|
||||
import com.jpexs.decompiler.flash.flexsdk.MxmlcAs3ScriptReplacer;
|
||||
@@ -701,7 +702,7 @@ public class CommandLineArgumentParser {
|
||||
parseDecrypt(args);
|
||||
System.exit(0);
|
||||
} else if (command.equals("swf2xml")) {
|
||||
parseSwf2Xml(args, charset);
|
||||
parseSwf2Xml(args, charset, handler);
|
||||
System.exit(0);
|
||||
} else if (command.equals("xml2swf")) {
|
||||
parseXml2Swf(args, charset);
|
||||
@@ -2711,15 +2712,58 @@ public class CommandLineArgumentParser {
|
||||
System.exit(result ? 0 : 1);
|
||||
}
|
||||
|
||||
private static void parseSwf2Xml(Stack<String> args, String charset) {
|
||||
private static void parseSwf2Xml(Stack<String> args, String charset, AbortRetryIgnoreHandler handler) {
|
||||
if (args.size() < 2) {
|
||||
badArguments("swf2xml");
|
||||
}
|
||||
|
||||
ScriptExportMode scriptExportMode = null;
|
||||
ImageExportMode imageExportMode = null;
|
||||
SoundExportMode soundExportMode = null;
|
||||
|
||||
String arg = args.pop();
|
||||
if ("-external".equals(arg.toLowerCase(Locale.ENGLISH))) {
|
||||
if (args.size() < 3) {
|
||||
badArguments("swf2xml");
|
||||
}
|
||||
String ext = args.pop();
|
||||
String[] parts = ext.split(",", -1);
|
||||
|
||||
for (String part : parts) {
|
||||
switch (part) {
|
||||
case "as12script":
|
||||
case "as12script:as":
|
||||
scriptExportMode = ScriptExportMode.AS;
|
||||
break;
|
||||
case "image:png_gif_jpeg":
|
||||
imageExportMode = ImageExportMode.PNG_GIF_JPEG;
|
||||
break;
|
||||
case "image":
|
||||
case "image:png_gif_jpeg_alpha":
|
||||
imageExportMode = ImageExportMode.PNG_GIF_JPEG_ALPHA;
|
||||
break;
|
||||
case "definesound":
|
||||
case "definesound:mp3_wav_flv":
|
||||
soundExportMode = SoundExportMode.MP3_WAV_FLV;
|
||||
break;
|
||||
case "all":
|
||||
scriptExportMode = ScriptExportMode.AS;
|
||||
imageExportMode = ImageExportMode.PNG_GIF_JPEG_ALPHA;
|
||||
soundExportMode = SoundExportMode.MP3_WAV_FLV;
|
||||
break;
|
||||
default:
|
||||
System.err.println("Unsupported external value: \"" + part + "\"");
|
||||
badArguments("swf2xml");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
args.push(arg);
|
||||
}
|
||||
|
||||
try {
|
||||
try (StdInAwareFileInputStream is = new StdInAwareFileInputStream(args.pop())) {
|
||||
SWF swf = new SWF(is, Configuration.parallelSpeedUp.get(), charset);
|
||||
new SwfXmlExporter().exportXml(swf, new File(args.pop()));
|
||||
new SwfXmlExporter().exportXml(swf, new File(args.pop()), new XmlSwfExportSettings(scriptExportMode, imageExportMode, soundExportMode), null, handler);
|
||||
} catch (FileNotFoundException ex) {
|
||||
System.err.println("File not found.");
|
||||
System.exit(1);
|
||||
@@ -2738,8 +2782,10 @@ public class CommandLineArgumentParser {
|
||||
|
||||
try {
|
||||
SWF swf = new SWF(charset);
|
||||
try (StdInAwareFileInputStream in = new StdInAwareFileInputStream(args.pop())) {
|
||||
new SwfXmlImporter().importSwf(swf, in);
|
||||
String fileName = args.pop();
|
||||
try (StdInAwareFileInputStream in = new StdInAwareFileInputStream(fileName)) {
|
||||
File file = new File(StdInAwareFileInputStream.STDIN_PATH.equals(fileName) ? "." : fileName);
|
||||
new SwfXmlImporter().importSwf(swf, in, file.getParentFile());
|
||||
}
|
||||
try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(new File(args.pop())))) {
|
||||
swf.saveTo(fos);
|
||||
|
||||
@@ -72,9 +72,19 @@ alias /?
|
||||
Decrypt HARMAN Air encrypted file.
|
||||
Decrypt HARMAN Air encrypted file <infile> and saves it to <outfile>.
|
||||
|
||||
-swf2xml <infile> <outfile>
|
||||
-swf2xml [-external <formats>] <infile> <outfile>
|
||||
Convert SWF to XML.
|
||||
Convert the <infile> SWF to <outfile> XML file.
|
||||
-external parameter sets which items will be available externally
|
||||
Values for <formats>: Use comma separated list of following:
|
||||
as12script:as
|
||||
as12script (same as "as12script:as")
|
||||
image:png_gif_jpeg
|
||||
image:png_gif_jpeg_alpha
|
||||
image (same as "image:png_gif_jpeg_alpha")
|
||||
definesound:mp3_wav_flv
|
||||
definesound (same as "definesound:mp3_wav_flv")
|
||||
all (same as "as12script,image,definesound")
|
||||
|
||||
-xml2swf <infile> <outfile>
|
||||
Convert XML to SWF.
|
||||
@@ -448,7 +458,7 @@ Pre-options:
|
||||
When it has .bin extension, legacy storage is used.
|
||||
|
||||
-onerror (abort|retry <N>|ignore)
|
||||
Applies to: -export, -importScript
|
||||
Applies to: -export, -importScript, -swf2xml
|
||||
Error handling mode.
|
||||
"abort" stops the exporting
|
||||
"retry" tries the exporting N times
|
||||
|
||||
@@ -92,6 +92,7 @@ import com.jpexs.decompiler.flash.exporters.settings.SoundExportSettings;
|
||||
import com.jpexs.decompiler.flash.exporters.settings.SpriteExportSettings;
|
||||
import com.jpexs.decompiler.flash.exporters.settings.SymbolClassExportSettings;
|
||||
import com.jpexs.decompiler.flash.exporters.settings.TextExportSettings;
|
||||
import com.jpexs.decompiler.flash.exporters.settings.XmlSwfExportSettings;
|
||||
import com.jpexs.decompiler.flash.exporters.swf.SwfFlashDevelopExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.swf.SwfIntelliJIdeaExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.swf.SwfJavaExporter;
|
||||
@@ -4618,6 +4619,12 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
|
||||
public void exportSwfXml(List<TreeItem> items) {
|
||||
View.checkAccess();
|
||||
|
||||
|
||||
XmlExportDialog dialog = new XmlExportDialog(Main.getDefaultDialogsOwner());
|
||||
if (dialog.showExportDialog() != AppDialog.OK_OPTION) {
|
||||
return;
|
||||
}
|
||||
|
||||
Set<SWF> usedOpenables = new LinkedHashSet<>();
|
||||
Set<OpenableList> usedOpenableLists = new HashSet<>();
|
||||
|
||||
@@ -4678,6 +4685,9 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
|
||||
return;
|
||||
}
|
||||
selFile = Helper.fixDialogFile(fc.getSelectedFile()).getAbsolutePath();
|
||||
|
||||
Configuration.lastExportDir.set(new File(selFile).getParentFile().getAbsolutePath());
|
||||
|
||||
if (!selFile.toLowerCase(Locale.ENGLISH).endsWith(".xml")) {
|
||||
selFile = selFile + ".xml";
|
||||
}
|
||||
@@ -4714,7 +4724,8 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
|
||||
try {
|
||||
new RetryTask(() -> {
|
||||
File outFile = new File(selFile2);
|
||||
new SwfXmlExporter().exportXml(openable, outFile);
|
||||
XmlSwfExportSettings settings = new XmlSwfExportSettings(dialog.getEnumValue(ScriptExportMode.class), dialog.getEnumValue(ImageExportMode.class), dialog.getEnumValue(SoundExportMode.class));
|
||||
new SwfXmlExporter().exportXml(openable, outFile, settings, openable.getExportEventListener(), new GuiAbortRetryIgnoreHandler());
|
||||
}, handler).run();
|
||||
|
||||
} catch (IOException ex) {
|
||||
@@ -4760,7 +4771,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
|
||||
File selfile = Helper.fixDialogFile(selectedFile);
|
||||
try {
|
||||
try (FileInputStream fis = new FileInputStream(selfile)) {
|
||||
new SwfXmlImporter().importSwf(swf, fis);
|
||||
new SwfXmlImporter().importSwf(swf, fis, selfile.getParentFile());
|
||||
}
|
||||
swf.clearAllCache();
|
||||
swf.assignExportNamesToSymbols();
|
||||
@@ -4769,8 +4780,9 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
Main.stopWork();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void renameIdentifiers(final Openable openable) {
|
||||
|
||||
279
src/com/jpexs/decompiler/flash/gui/XmlExportDialog.java
Normal file
279
src/com/jpexs/decompiler/flash/gui/XmlExportDialog.java
Normal file
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2026 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.decompiler.flash.gui;
|
||||
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ImageExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.SoundExportMode;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Container;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import javax.swing.ComboBoxModel;
|
||||
import javax.swing.DefaultComboBoxModel;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingConstants;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class XmlExportDialog extends AppDialog {
|
||||
private int result = ERROR_OPTION;
|
||||
|
||||
private final Map<Class<? extends Enum>, JComboBox<ComboValue>> combos = new HashMap<>();
|
||||
|
||||
private final Map<Class<? extends Enum>, String> enumNames = new HashMap<>();
|
||||
|
||||
private final List<Object> allDefaults = Arrays.asList(ScriptExportMode.AS, ImageExportMode.PNG_GIF_JPEG_ALPHA, SoundExportMode.MP3_WAV_FLV);
|
||||
|
||||
public XmlExportDialog(Window owner) {
|
||||
super(owner);
|
||||
|
||||
enumNames.put(ScriptExportMode.class, "as12script");
|
||||
enumNames.put(ImageExportMode.class, "image");
|
||||
enumNames.put(SoundExportMode.class, "definesound");
|
||||
setTitle(translate("dialog.title"));
|
||||
JPanel buttonsPanel = new JPanel(new FlowLayout());
|
||||
JButton okButton = new JButton(translate("button.ok"));
|
||||
okButton.addActionListener(this::okButtonActionPerformed);
|
||||
JButton cancelButton = new JButton(translate("button.cancel"));
|
||||
cancelButton.addActionListener(this::cancelButtonActionPerformed);
|
||||
buttonsPanel.add(okButton);
|
||||
buttonsPanel.add(cancelButton);
|
||||
|
||||
JPanel centralPanel = new JPanel(new GridBagLayout());
|
||||
GridBagConstraints gbc = new GridBagConstraints();
|
||||
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 0;
|
||||
gbc.insets = new Insets(1, 2, 1, 2);
|
||||
|
||||
JLabel selectLabel = new JLabel(translate("selectExternal"));
|
||||
gbc.gridwidth = 4;
|
||||
centralPanel.add(selectLabel, gbc);
|
||||
|
||||
gbc.gridwidth = 1;
|
||||
gbc.gridy++;
|
||||
|
||||
DefaultComboBoxModel<ComboValue> as12ScriptsModel = new DefaultComboBoxModel<>();
|
||||
as12ScriptsModel.addElement(new ComboValue(null, translate("xml")));
|
||||
as12ScriptsModel.addElement(new ComboValue(ScriptExportMode.AS, translateExport("scripts.as")));
|
||||
|
||||
addComboRow(centralPanel, gbc, translate("as12scripts"), "as", as12ScriptsModel, ScriptExportMode.class);
|
||||
|
||||
DefaultComboBoxModel<ComboValue> imageModel = new DefaultComboBoxModel<>();
|
||||
imageModel.addElement(new ComboValue(null, translate("xml")));
|
||||
imageModel.addElement(new ComboValue(ImageExportMode.PNG_GIF_JPEG, translateExport("images.png_gif_jpeg")));
|
||||
imageModel.addElement(new ComboValue(ImageExportMode.PNG_GIF_JPEG_ALPHA, translateExport("images.png_gif_jpeg_alpha")));
|
||||
|
||||
addComboRow(centralPanel, gbc, translateExport("images"), "image", imageModel, ImageExportMode.class);
|
||||
|
||||
DefaultComboBoxModel<ComboValue> soundModel = new DefaultComboBoxModel<>();
|
||||
soundModel.addElement(new ComboValue(null, translate("xml")));
|
||||
soundModel.addElement(new ComboValue(SoundExportMode.MP3_WAV_FLV, translateExport("sounds.mp3_wav_flv")));
|
||||
|
||||
addComboRow(centralPanel, gbc, translate("defineSound"), "sound", soundModel, SoundExportMode.class);
|
||||
|
||||
|
||||
|
||||
String config = Configuration.lastSelectedXmlExportFormats.get();
|
||||
if (!config.isEmpty()) {
|
||||
String[] parts = config.split(",", -1);
|
||||
for (String part : parts) {
|
||||
String[] parts2 = part.split("\\.", -1);
|
||||
if (parts2.length != 2) {
|
||||
continue;
|
||||
}
|
||||
String name = parts2[0];
|
||||
String value = parts2[1];
|
||||
for (Class cls : combos.keySet()) {
|
||||
if (enumNames.get(cls).equals(name)) {
|
||||
JComboBox<ComboValue> combo = combos.get(cls);
|
||||
DefaultComboBoxModel<ComboValue> model = (DefaultComboBoxModel<ComboValue>) combo.getModel();
|
||||
for (int i = 0; i < model.getSize(); i++) {
|
||||
ComboValue cv = model.getElementAt(i);
|
||||
if (cv.value == null && value.equals("none")) {
|
||||
combo.setSelectedIndex(0);
|
||||
break;
|
||||
}
|
||||
if (cv.value != null && cv.value.toString().toLowerCase(Locale.ENGLISH).equals(value)) {
|
||||
combo.setSelectedIndex(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JButton allButton = new JButton(translate("all"));
|
||||
allButton.addActionListener(this::allButtonActionPerformed);
|
||||
|
||||
JButton noneButton = new JButton(translate("none"));
|
||||
noneButton.addActionListener(this::noneButtonActionPerformed);
|
||||
|
||||
|
||||
gbc.gridx = 2;
|
||||
gbc.insets = new Insets(5, 2, 1, 2);
|
||||
gbc.anchor = GridBagConstraints.CENTER;
|
||||
centralPanel.add(noneButton, gbc);
|
||||
gbc.gridx++;
|
||||
centralPanel.add(allButton, gbc);
|
||||
|
||||
Container cnt = getContentPane();
|
||||
cnt.setLayout(new BorderLayout());
|
||||
cnt.add(centralPanel, BorderLayout.CENTER);
|
||||
cnt.add(buttonsPanel, BorderLayout.SOUTH);
|
||||
|
||||
pack();
|
||||
View.centerScreen(this);
|
||||
View.setWindowIcon(this, "exportxml");
|
||||
getRootPane().setDefaultButton(okButton);
|
||||
setModal(true);
|
||||
}
|
||||
|
||||
private void addComboRow(JPanel centralPanel, GridBagConstraints gbc, String label, String icon, ComboBoxModel<ComboValue> model, Class<? extends Enum> enumClass) {
|
||||
gbc.fill = GridBagConstraints.NONE;
|
||||
|
||||
JLabel scriptsLabel = new JLabel(label);
|
||||
scriptsLabel.setIcon(View.getIcon(icon + "16"));
|
||||
scriptsLabel.setHorizontalTextPosition(SwingConstants.LEFT);
|
||||
gbc.anchor = GridBagConstraints.LINE_END;
|
||||
centralPanel.add(scriptsLabel, gbc);
|
||||
|
||||
gbc.gridx++;
|
||||
JLabel arrowLabel = new JLabel(translateExport("arrow"));
|
||||
gbc.insets = new Insets(1, 5, 1, 5);
|
||||
gbc.anchor = GridBagConstraints.CENTER;
|
||||
centralPanel.add(arrowLabel, gbc);
|
||||
|
||||
gbc.insets = new Insets(1, 2, 1, 2);
|
||||
|
||||
gbc.gridx++;
|
||||
gbc.gridwidth = 2;
|
||||
JComboBox<ComboValue> combo = new JComboBox<>(model);
|
||||
gbc.anchor = GridBagConstraints.LINE_START;
|
||||
gbc.fill = GridBagConstraints.BOTH;
|
||||
|
||||
combos.put(enumClass, combo);
|
||||
|
||||
centralPanel.add(combo, gbc);
|
||||
gbc.gridy++;
|
||||
gbc.gridwidth = 1;
|
||||
gbc.gridx = 0;
|
||||
gbc.fill = GridBagConstraints.NONE;
|
||||
}
|
||||
|
||||
|
||||
public <T extends Enum<T>> T getEnumValue(Class<T> cls) {
|
||||
if (!combos.containsKey(cls)) {
|
||||
return null;
|
||||
}
|
||||
ComboValue cv = (ComboValue) combos.get(cls).getSelectedItem();
|
||||
if (cv == null) {
|
||||
return null;
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
T ret = (T) cv.value;
|
||||
return ret;
|
||||
}
|
||||
|
||||
private void okButtonActionPerformed(ActionEvent evt) {
|
||||
|
||||
List<String> vals = new ArrayList<>();
|
||||
for (Class cls : combos.keySet()) {
|
||||
String name = enumNames.get(cls);
|
||||
ComboValue cv = (ComboValue) combos.get(cls).getSelectedItem();
|
||||
if (cv == null || cv.value == null) {
|
||||
vals.add(name + "." + "none");
|
||||
} else {
|
||||
vals.add(name + "." + cv.value.toString().toLowerCase());
|
||||
}
|
||||
}
|
||||
Configuration.lastSelectedXmlExportFormats.set(String.join(",", vals));
|
||||
|
||||
result = OK_OPTION;
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
private void noneButtonActionPerformed(ActionEvent evt) {
|
||||
for (Class cls : combos.keySet()) {
|
||||
JComboBox<ComboValue> combo = combos.get(cls);
|
||||
combo.setSelectedIndex(0);
|
||||
}
|
||||
}
|
||||
|
||||
private void allButtonActionPerformed(ActionEvent evt) {
|
||||
for (Class cls : combos.keySet()) {
|
||||
JComboBox<ComboValue> combo = combos.get(cls);
|
||||
DefaultComboBoxModel<ComboValue> model = (DefaultComboBoxModel<ComboValue>) combo.getModel();
|
||||
for (int i = 0; i < model.getSize(); i++) {
|
||||
ComboValue value = model.getElementAt(i);
|
||||
if (value.value != null && allDefaults.contains(value.value)) {
|
||||
combo.setSelectedIndex(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void cancelButtonActionPerformed(ActionEvent evt) {
|
||||
result = CANCEL_OPTION;
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
public int showExportDialog() {
|
||||
setVisible(true);
|
||||
return result;
|
||||
}
|
||||
|
||||
private String translateExport(String key) {
|
||||
return AppDialog.translateForDialog(key, ExportDialog.class);
|
||||
}
|
||||
|
||||
private class ComboValue {
|
||||
|
||||
public Object value;
|
||||
public String text;
|
||||
|
||||
public ComboValue(Object value, String text) {
|
||||
this.value = value;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -698,3 +698,6 @@ config.description.useMinimumStrokeWidth1Px = Use 1 pixel as minimal stroke widt
|
||||
#after 26.0.0
|
||||
config.name.showLoadingSpinner = Show loading spinner
|
||||
config.description.showLoadingSpinner = Displays animated loading indicator in status bar
|
||||
|
||||
config.name.xmlExport.formats = (Internal) Xml export external formats
|
||||
config.description.xmlExport.formats = Last used Xml export external formats.
|
||||
@@ -694,3 +694,10 @@ config.description.msaaGridForExport = Velikost m\u0159\u00ed\u017eky v\u00edcen
|
||||
|
||||
config.name.useMinimumStrokeWidth1Px = Minim\u00e1ln\u00ed \u0161\u00ed\u0159ka tahu 1 pixel (jako ve Flashi)
|
||||
config.description.useMinimumStrokeWidth1Px = Pou\u017e\u00edt 1 pixel jako minim\u00e1ln\u00ed \u0161\u00ed\u0159ku tahu. Flash vykresluje tahy t\u00edmto zp\u016fsobem. Vypn\u011bte pro umo\u017en\u011bn\u00ed ten\u010d\u00edch tah\u016f.
|
||||
|
||||
#after 26.0.0
|
||||
config.name.showLoadingSpinner = Zobrazit indik\u00e1tor na\u010d\u00edt\u00e1n\u00ed
|
||||
config.description.showLoadingSpinner = Zobraz\u00ed animovan\u00fd indik\u00e1tor na\u010d\u00edt\u00e1n\u00ed ve stavov\u00e9m \u0159\u00e1dku
|
||||
|
||||
config.name.xmlExport.formats = (Intern\u00ed) Form\u00e1ty extern\u00edho XML exportu
|
||||
config.description.xmlExport.formats = Naposledy pou\u017eit\u00e9 form\u00e1ty extern\u00edho XML exportu.
|
||||
@@ -623,3 +623,10 @@ config.description.msaaGridForExport = Rastergr\u00f6\u00dfe NxN pro Multisample
|
||||
|
||||
config.name.useMinimumStrokeWidth1Px = Minimale Strichbreite von 1 Pixel (wie in Flash)
|
||||
config.description.useMinimumStrokeWidth1Px = 1 Pixel als minimale Strichbreite verwenden. Flash rendert Striche auf diese Weise. Deaktivieren, um d\u00fcnnere Striche zu erm\u00f6glichen.
|
||||
|
||||
#after 26.0.0
|
||||
config.name.showLoadingSpinner = Ladeanzeige anzeigen
|
||||
config.description.showLoadingSpinner = Zeigt eine animierte Ladeanzeige in der Statusleiste an
|
||||
|
||||
config.name.xmlExport.formats = (Intern) Formate f\u00fcr externen XML-Export
|
||||
config.description.xmlExport.formats = Zuletzt verwendete Formate f\u00fcr externen XML-Export.
|
||||
@@ -694,3 +694,10 @@ config.description.msaaGridForExport = Ve\u013ekos\u0165 mrie\u017eky viacn\u00e
|
||||
|
||||
config.name.useMinimumStrokeWidth1Px = Minim\u00e1lna \u0161\u00edrka \u0165ahu 1 pixel (ako vo Flashi)
|
||||
config.description.useMinimumStrokeWidth1Px = Pou\u017ei\u0165 1 pixel ako minim\u00e1lnu \u0161\u00edrku \u0165ahu. Flash vykres\u013euje \u0165ahy t\u00fdmto sp\u00f4sobom. Vypnite pre umo\u017enenie ten\u0161\u00edch \u0165ahov.
|
||||
|
||||
#after 26.0.0
|
||||
config.name.showLoadingSpinner = Zobrazi\u0165 indik\u00e1tor na\u010d\u00edtania
|
||||
config.description.showLoadingSpinner = Zobraz\u00ed animovan\u00fd indik\u00e1tor na\u010d\u00edtania v stavovom riadku
|
||||
|
||||
config.name.xmlExport.formats = (Intern\u00e9) Form\u00e1ty extern\u00e9ho XML exportu
|
||||
config.description.xmlExport.formats = Naposledy pou\u017eit\u00e9 form\u00e1ty extern\u00e9ho XML exportu.
|
||||
@@ -0,0 +1,12 @@
|
||||
dialog.title = Export XML
|
||||
button.ok = OK
|
||||
button.cancel = Cancel
|
||||
|
||||
selectExternal = Select items which will be available externally:
|
||||
|
||||
all = Select all
|
||||
none = Select none
|
||||
|
||||
as12scripts = AS1/2 scripts
|
||||
defineSound = DefineSounds
|
||||
xml = XML (no external)
|
||||
@@ -0,0 +1,12 @@
|
||||
dialog.title = Exportovat XML
|
||||
button.ok = OK
|
||||
button.cancel = Storno
|
||||
|
||||
selectExternal = Vyberte polo\u017eky, kter\u00e9 budou dostupn\u00e9 extern\u011b:
|
||||
|
||||
all = Vybrat v\u0161e
|
||||
none = Nevybrat nic
|
||||
|
||||
as12scripts = AS1/2 skripty
|
||||
defineSound = DefineSounds
|
||||
xml = XML (ne extern\u00ed)
|
||||
@@ -0,0 +1,12 @@
|
||||
dialog.title = XML exportieren
|
||||
button.ok = OK
|
||||
button.cancel = Abbrechen
|
||||
|
||||
selectExternal = W\u00e4hlen Sie die Elemente aus, die extern verf\u00fcgbar sein sollen:
|
||||
|
||||
all = Alles ausw\u00e4hlen
|
||||
none = Nichts ausw\u00e4hlen
|
||||
|
||||
as12scripts = AS1/2-Skripte
|
||||
defineSound = DefineSounds
|
||||
xml = XML (nicht extern)
|
||||
@@ -0,0 +1,12 @@
|
||||
dialog.title = Exportova\u0165 XML
|
||||
button.ok = OK
|
||||
button.cancel = Zru\u0161i\u0165
|
||||
|
||||
selectExternal = Vyberte polo\u017eky, ktor\u00e9 bud\u00fa dostupn\u00e9 externe:
|
||||
|
||||
all = Vybra\u0165 v\u0161etko
|
||||
none = Nevybra\u0165 ni\u010d
|
||||
|
||||
as12scripts = AS1/2 skripty
|
||||
defineSound = DefineSounds
|
||||
xml = XML (nie extern\u00e9)
|
||||
Reference in New Issue
Block a user