Added: FLA/FlashDevelop/IDEA export - A link to all classes (sound, font, images) is added so no class is missed during compilation

This commit is contained in:
Jindra Petřík
2024-08-18 09:47:53 +02:00
parent 58e61907f2
commit 9617c2ac2f
14 changed files with 201 additions and 51 deletions

View File

@@ -133,7 +133,7 @@ public class DecompilerPool {
}
boolean parallel = Configuration.parallelSpeedUp.get();
HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), true);
pack.toSource(abcIndex, writer, script == null ? null : script.traits.traits, new ConvertData(), ScriptExportMode.AS, parallel, false);
pack.toSource(abcIndex, writer, script == null ? null : script.traits.traits, new ConvertData(), ScriptExportMode.AS, parallel, false, false);
writer.finishHilights();
HighlightedText result = new HighlightedText(writer);

View File

@@ -297,9 +297,11 @@ public class ScriptPack extends AS3ClassTreeItem {
* @param convertData Convert data
* @param exportMode Export mode
* @param parallel Parallel
* @param exportAllClasses Export all classes - reference it in document
* class
* @throws InterruptedException On interrupt
*/
private void appendTo(AbcIndexing abcIndex, GraphTextWriter writer, List<Trait> traits, ConvertData convertData, ScriptExportMode exportMode, boolean parallel) throws InterruptedException {
private void appendTo(AbcIndexing abcIndex, GraphTextWriter writer, List<Trait> traits, ConvertData convertData, ScriptExportMode exportMode, boolean parallel, boolean exportAllClasses) throws InterruptedException {
boolean first = true;
//script initializer
int script_init = abc.script_info.get(scriptIndex).init_index;
@@ -307,21 +309,21 @@ public class ScriptPack extends AS3ClassTreeItem {
if (!isSimple && traitIndices.isEmpty()) {
for (Trait t : abc.script_info.get(scriptIndex).traits.traits) {
if (t instanceof TraitSlotConst) {
continue;
}
String fullName = t.getName(abc).getNameWithNamespace(abc.constants, false).toPrintableString(true);
writer.appendNoHilight("include \"" + fullName.replace(".", "/") + ".as\";").newLine();
}
writer.newLine();
}
}
for (int t : traitIndices) {
Trait trait = traits.get(t);
if (trait instanceof TraitSlotConst) {
continue;
}
@@ -342,7 +344,7 @@ public class ScriptPack extends AS3ClassTreeItem {
}
first = false;
}
List<DottedChain> fullyQualifiedNames = new ArrayList<>();
if (!first) {
writer.newLine();
@@ -354,16 +356,15 @@ public class ScriptPack extends AS3ClassTreeItem {
Trait.writeImports(null, script_init, abcIndex, scriptIndex, -1, true, abc, writer, ignorePackage, fullyQualifiedNames);
first = true;
//Slot const last
for (int t : traitIndices) {
Trait trait = traits.get(t);
if (!(trait instanceof TraitSlotConst)) {
continue;
}
if (convertData.assignedValues.containsKey((TraitSlotConst) trait)) {
continue;
}
@@ -384,19 +385,19 @@ public class ScriptPack extends AS3ClassTreeItem {
}
first = false;
}
if (bodyIndex != -1 && (isSimple || traitIndices.isEmpty())) {
//Note: There must be trait/method highlight even if the initializer is empty to TraitList in GUI to work correctly
writer.startTrait(GraphTextWriter.TRAIT_SCRIPT_INITIALIZER);
writer.startMethod(script_init, null);
if (exportMode != ScriptExportMode.AS_METHOD_STUBS) {
if (!scriptInitializerIsEmpty) {
if (!scriptInitializerIsEmpty) {
List<MethodBody> callStack = new ArrayList<>();
callStack.add(abc.bodies.get(bodyIndex));
if (!first) {
writer.newLine();
writer.newLine();
}
abc.bodies.get(bodyIndex).toString(callStack, abcIndex, path + "/.scriptinitializer", exportMode, abc, null, writer, fullyQualifiedNames, new HashSet<>());
abc.bodies.get(bodyIndex).toString(callStack, abcIndex, path + "/.scriptinitializer", exportMode, abc, null, writer, fullyQualifiedNames, new HashSet<>());
} else {
writer.append("");
}
@@ -408,6 +409,16 @@ public class ScriptPack extends AS3ClassTreeItem {
first = false;
}
}
if (exportAllClasses) {
String documentClass = abc.getSwf().getDocumentClass();
if (documentClass != null) {
if (path.toRawString().equals(documentClass)) {
writer.append("//Include all classes in the build").append("\r\n");
writer.append("function __ffdec_include_classes() { FFDecIncludeClasses; }");
}
}
}
}
/**
@@ -420,9 +431,10 @@ public class ScriptPack extends AS3ClassTreeItem {
* @param exportMode Export mode
* @param parallel Parallel
* @param ignoreFrameScripts Whether to ignore frame scripts
* @param exportAllClasses Export all classes
* @throws InterruptedException On interrupt
*/
public void toSource(AbcIndexing abcIndex, GraphTextWriter writer, final List<Trait> traits, final ConvertData convertData, final ScriptExportMode exportMode, final boolean parallel, boolean ignoreFrameScripts) throws InterruptedException {
public void toSource(AbcIndexing abcIndex, GraphTextWriter writer, final List<Trait> traits, final ConvertData convertData, final ScriptExportMode exportMode, final boolean parallel, boolean ignoreFrameScripts, boolean exportAllClasses) throws InterruptedException {
writer.suspendMeasure();
int timeout = Configuration.decompilationTimeoutFile.get();
try {
@@ -460,7 +472,7 @@ public class ScriptPack extends AS3ClassTreeItem {
}
writer.continueMeasure();
appendTo(abcIndex, writer, traits, convertData, exportMode, parallel);
appendTo(abcIndex, writer, traits, convertData, exportMode, parallel, exportAllClasses);
}
/**
@@ -492,7 +504,7 @@ public class ScriptPack extends AS3ClassTreeItem {
convertData.exportEmbed = exportSettings.exportEmbed;
convertData.exportEmbedFlaMode = exportSettings.exportEmbedFlaMode;
convertData.assetsDir = exportSettings.assetsDir;
toSource(abcIndex, writer2, abc.script_info.get(scriptIndex).traits.traits, convertData, exportSettings.mode, parallel, exportSettings.ignoreFrameScripts);
toSource(abcIndex, writer2, abc.script_info.get(scriptIndex).traits.traits, convertData, exportSettings.mode, parallel, exportSettings.ignoreFrameScripts, exportSettings.includeAllClasses);
} catch (FileNotFoundException ex) {
logger.log(Level.SEVERE, "The file path is probably too long", ex);
}

View File

@@ -1019,6 +1019,10 @@ public final class Configuration {
@ConfigurationDefaultBoolean(true)
@ConfigurationCategory("script")
public static ConfigurationItem<Boolean> warningAddFunction = null;
@ConfigurationDefaultBoolean(true)
@ConfigurationCategory("export")
public static ConfigurationItem<Boolean> linkAllClasses = null;
private enum OSId {
WINDOWS, OSX, UNIX

View File

@@ -81,6 +81,7 @@ import com.jpexs.decompiler.flash.tags.base.FontTag;
import com.jpexs.decompiler.flash.tags.base.ImageTag;
import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag;
import com.jpexs.decompiler.flash.tags.base.RemoveTag;
import com.jpexs.decompiler.flash.tags.base.SoundTag;
import com.jpexs.decompiler.graph.DottedChain;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.ScopeStack;
@@ -92,6 +93,7 @@ import com.jpexs.helpers.XmlPrettyFormat;
import com.jpexs.helpers.utf8.Utf8Helper;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -381,6 +383,7 @@ public class AS3ScriptExporter {
/**
* Export ActionScript 3 scripts.
*
* @param swf SWF
* @param handler AbortRetryIgnoreHandler
* @param outdir Output directory
@@ -405,6 +408,56 @@ public class AS3ScriptExporter {
int cnt = 1;
List<ExportPackTask> tasks = new ArrayList<>();
Set<String> files = new HashSet<>();
String documentClass = swf.getDocumentClass();
StringBuffer includeClassesBuilder = new StringBuffer();
String documentPkg = DottedChain.parseNoSuffix(documentClass).getWithoutLast().toPrintableString(true);
StringBuilder importsBuilder = new StringBuilder();
for (ScriptPack item : packs) {
if (!item.isSimple && Configuration.ignoreCLikePackages.get()) {
continue;
}
if (ignoredClasses.contains(item.getClassPath().toRawString())) {
continue;
}
if (flexClass != null && item.getClassPath().toRawString().equals(flexClass)) {
continue;
}
String rawClassName = item.getClassPath().toRawString();
CharacterTag character = swf.getCharacterByClass(rawClassName);
//For some reasons Sprites do not work...
boolean allowedType = (character instanceof SoundTag)
|| (character instanceof ImageTag)
|| (character instanceof FontTag);
if (allowedType) {
if (!item.getClassPath().packageStr.isTopLevel()) {
importsBuilder.append(" import ").append(item.getClassPath().toString()).append(";\r\n");
}
includeClassesBuilder.append(" ").append(item.getClassPath().toString()).append(";\r\n");
}
}
if (documentClass != null && !includeClassesBuilder.isEmpty()) {
StringBuilder prep = new StringBuilder();
prep.append(" /**\r\n");
prep.append(" * This class contains references to all decompiled sound/image/font classes.\r\n");
prep.append(" * It is needed for compilation otherwise some classes will be missed.\r\n");
prep.append(" */\r\n");
prep.append(" public class FFDecIncludeClasses\r\n");
prep.append(" {\r\n");
includeClassesBuilder.insert(0, prep);
}
//If no sound/image classes found, then do not include FFDecIncludeClasses at all
if (includeClassesBuilder.isEmpty()) {
exportSettings = exportSettings.clone();
exportSettings.includeAllClasses = false;
}
for (ScriptPack item : packs) {
if (!item.isSimple && Configuration.ignoreCLikePackages.get()) {
continue;
@@ -446,6 +499,35 @@ public class AS3ScriptExporter {
tasks.add(new ExportPackTask(swf.getAbcIndex(), handler, cnt++, packs.size(), item.getClassPath(), item, file, exportSettings, parallel, evl));
}
if (!includeClassesBuilder.isEmpty()) {
includeClassesBuilder.append(" }\r\n");
includeClassesBuilder.append("}\r\n");
StringBuilder prepend = new StringBuilder();
prepend.append("package ").append(documentPkg).append("\r\n");
prepend.append("{\r\n");
prepend.append(importsBuilder.toString());
prepend.append("\r\n");
includeClassesBuilder.insert(0, prepend.toString());
if (exportSettings.includeAllClasses) {
java.nio.file.Path outPath = new File(outdir).toPath();
if (!documentPkg.isEmpty()) {
outPath = outPath.resolve(documentPkg);
}
File ffdecIncludeFilePath = outPath.resolve("FFDecIncludeClasses.as").toFile();
try (FileOutputStream fos = new FileOutputStream(ffdecIncludeFilePath)) {
fos.write(Utf8Helper.getBytes(includeClassesBuilder.toString()));
} catch (FileNotFoundException ex) {
Logger.getLogger(AS3ScriptExporter.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(AS3ScriptExporter.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
if (!parallel || tasks.size() < 2) {
try {
CancellableWorker.call(new Callable<Void>() {

View File

@@ -18,6 +18,8 @@ package com.jpexs.decompiler.flash.exporters.settings;
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
import com.jpexs.decompiler.flash.helpers.FileTextWriter;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Script export settings.
@@ -71,6 +73,11 @@ public class ScriptExportSettings {
*/
public String assetsDir;
/**
* Modify main class to reference all classes
*/
public boolean includeAllClasses = true;
/**
* Constructor.
* @param mode Mode
@@ -88,7 +95,7 @@ public class ScriptExportSettings {
boolean exportEmbedFlaMode,
boolean resampleWav
) {
this(mode, singleFile, ignoreFrameScripts, exportEmbed, exportEmbedFlaMode, resampleWav, "/_assets/");
this(mode, singleFile, ignoreFrameScripts, exportEmbed, exportEmbedFlaMode, resampleWav, "/_assets/", false);
}
public ScriptExportSettings(
@@ -98,7 +105,8 @@ public class ScriptExportSettings {
boolean exportEmbed,
boolean exportEmbedFlaMode,
boolean resampleWav,
String assetsDir
String assetsDir,
boolean includeAllClasses
) {
this.mode = mode;
this.singleFile = singleFile;
@@ -107,6 +115,7 @@ public class ScriptExportSettings {
this.exportEmbedFlaMode = exportEmbedFlaMode;
this.resampleWav = resampleWav;
this.assetsDir = assetsDir;
this.includeAllClasses = includeAllClasses;
}
public String getFileExtension() {
@@ -127,4 +136,14 @@ public class ScriptExportSettings {
throw new Error("Unsupported script export mode: " + mode);
}
}
@Override
public ScriptExportSettings clone() {
try {
return (ScriptExportSettings) super.clone();
} catch (CloneNotSupportedException ex) {
//ignored
}
return null;
}
}

View File

@@ -343,7 +343,7 @@ public class SwfFlashDevelopExporter {
}
boolean parallel = Configuration.parallelSpeedUp.get();
ScriptExportSettings scriptExportSettings = new ScriptExportSettings(ScriptExportMode.AS, false, false, true, false, false);
ScriptExportSettings scriptExportSettings = new ScriptExportSettings(ScriptExportMode.AS, false, false, true, false, false, "/_assets/", Configuration.linkAllClasses.get());
swf.exportActionScript(handler, outFile.toPath().getParent().resolve(srcPath).toFile().getAbsolutePath(), scriptExportSettings, parallel, eventListener);
}
}

View File

@@ -316,7 +316,7 @@ public class SwfIntelliJIdeaExporter {
}
boolean parallel = Configuration.parallelSpeedUp.get();
ScriptExportSettings scriptExportSettings = new ScriptExportSettings(ScriptExportMode.AS, false, false, true, false, false);
ScriptExportSettings scriptExportSettings = new ScriptExportSettings(ScriptExportMode.AS, false, false, true, false, false, "/_assets/", Configuration.linkAllClasses.get());
swf.exportActionScript(handler, new File(outDir, "src").getAbsolutePath(), scriptExportSettings, parallel, eventListener);
}
}

View File

@@ -1463,16 +1463,16 @@ public class XFLConverter {
return date.getTime() / 1000;
}
private void convertLibrary(Set<CharacterTag> charactersExportedInFirstFrame, Map<CharacterTag, String> characterImportLinkageURL, Set<CharacterTag> characters, Reference<Integer> lastImportedId, Map<CharacterTag, String> characterNameMap, SWF swf, Map<CharacterTag, String> characterVariables, Map<CharacterTag, String> characterClasses, Map<CharacterTag, ScriptPack> characterScriptPacks, List<CharacterTag> nonLibraryShapes, String backgroundColor, ReadOnlyTagList tags, HashMap<String, byte[]> files, HashMap<String, byte[]> datfiles, FLAVersion flaVersion, XFLXmlWriter writer, Map<PlaceObjectTypeTag, MultiLevelClip> placeToMaskedSymbol, List<Integer> multiUsageMorphShapes, StatusStack statusStack) throws XMLStreamException {
private void convertLibrary(Reference<Integer> lastItemIdNumber, Set<CharacterTag> charactersExportedInFirstFrame, Map<CharacterTag, String> characterImportLinkageURL, Set<CharacterTag> characters, Reference<Integer> lastImportedId, Map<CharacterTag, String> characterNameMap, SWF swf, Map<CharacterTag, String> characterVariables, Map<CharacterTag, String> characterClasses, Map<CharacterTag, ScriptPack> characterScriptPacks, List<CharacterTag> nonLibraryShapes, String backgroundColor, ReadOnlyTagList tags, HashMap<String, byte[]> files, HashMap<String, byte[]> datfiles, FLAVersion flaVersion, XFLXmlWriter writer, Map<PlaceObjectTypeTag, MultiLevelClip> placeToMaskedSymbol, List<Integer> multiUsageMorphShapes, StatusStack statusStack) throws XMLStreamException {
statusStack.pushStatus("media");
convertMedia(charactersExportedInFirstFrame, lastImportedId, characterNameMap, characterImportLinkageURL, characters, swf, characterVariables, characterClasses, tags, files, datfiles, writer, statusStack);
convertMedia(lastItemIdNumber, charactersExportedInFirstFrame, lastImportedId, characterNameMap, characterImportLinkageURL, characters, swf, characterVariables, characterClasses, tags, files, datfiles, writer, statusStack);
statusStack.popStatus();
statusStack.pushStatus("symbols");
convertSymbols(charactersExportedInFirstFrame, characterImportLinkageURL, characters, lastImportedId, characterNameMap, swf, characterVariables, characterClasses, characterScriptPacks, nonLibraryShapes, backgroundColor, tags, files, flaVersion, writer, placeToMaskedSymbol, multiUsageMorphShapes, statusStack);
convertSymbols(lastItemIdNumber, charactersExportedInFirstFrame, characterImportLinkageURL, characters, lastImportedId, characterNameMap, swf, characterVariables, characterClasses, characterScriptPacks, nonLibraryShapes, backgroundColor, tags, files, flaVersion, writer, placeToMaskedSymbol, multiUsageMorphShapes, statusStack);
statusStack.popStatus();
}
private void convertSymbols(Set<CharacterTag> charactersExportedInFirstFrame, Map<CharacterTag, String> characterImportLinkageURL, Set<CharacterTag> characters, Reference<Integer> lastImportedId, Map<CharacterTag, String> characterNameMap, SWF swf, Map<CharacterTag, String> characterVariables, Map<CharacterTag, String> characterClasses, Map<CharacterTag, ScriptPack> characterScriptPacks, List<CharacterTag> nonLibraryShapes, String backgroundColor, ReadOnlyTagList tags, HashMap<String, byte[]> files, FLAVersion flaVersion, XFLXmlWriter writer, Map<PlaceObjectTypeTag, MultiLevelClip> placeToMaskedSymbol, List<Integer> multiUsageMorphShapes, StatusStack statusStack) throws XMLStreamException {
private void convertSymbols(Reference<Integer> lastItemIdNumber, Set<CharacterTag> charactersExportedInFirstFrame, Map<CharacterTag, String> characterImportLinkageURL, Set<CharacterTag> characters, Reference<Integer> lastImportedId, Map<CharacterTag, String> characterNameMap, SWF swf, Map<CharacterTag, String> characterVariables, Map<CharacterTag, String> characterClasses, Map<CharacterTag, ScriptPack> characterScriptPacks, List<CharacterTag> nonLibraryShapes, String backgroundColor, ReadOnlyTagList tags, HashMap<String, byte[]> files, FLAVersion flaVersion, XFLXmlWriter writer, Map<PlaceObjectTypeTag, MultiLevelClip> placeToMaskedSymbol, List<Integer> multiUsageMorphShapes, StatusStack statusStack) throws XMLStreamException {
//boolean hasSymbol = false;
Reference<Integer> nextClipId = new Reference<>(-1);
writer.writeStartElement("symbols");
@@ -1486,10 +1486,12 @@ public class XFLConverter {
statusStack.pushStatus(symbol.toString());
XFLXmlWriter symbolStr = new XFLXmlWriter();
String itemId = generateItemId(lastItemIdNumber);
symbolStr.writeStartElement("DOMSymbolItem", new String[]{
"xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance",
"xmlns", "http://ns.adobe.com/xfl/2008/",
"name", getSymbolName(lastImportedId, characterNameMap, swf, symbol),
"itemID", itemId,
"lastModified", Long.toString(getTimestamp(swf))}); //TODO:itemID
if (characterImportLinkageURL.containsKey(symbol)) {
symbolStr.writeAttribute("linkageImportForRS", "true");
@@ -1705,7 +1707,7 @@ public class XFLConverter {
}
final ScriptPack spriteScriptPack = characterScriptPacks.containsKey(sprite) ? characterScriptPacks.get(sprite) : null;
extractMultilevelClips(lastImportedId, characterNameMap, sprite.getTags(), writer, swf, nextClipId, nonLibraryShapes, backgroundColor, flaVersion, files, placeToMaskedSymbol, multiUsageMorphShapes, statusStack);
extractMultilevelClips(lastItemIdNumber, lastImportedId, characterNameMap, sprite.getTags(), writer, swf, nextClipId, nonLibraryShapes, backgroundColor, flaVersion, files, placeToMaskedSymbol, multiUsageMorphShapes, statusStack);
convertTimelines(lastImportedId, characterNameMap, swf, swf.getAbcIndex(), sprite, characterVariables.get(sprite), nonLibraryShapes, tags, sprite.getTags(), getSymbolName(lastImportedId, characterNameMap, swf, symbol), flaVersion, files, symbolStr, spriteScriptPack, placeToMaskedSymbol, multiUsageMorphShapes, statusStack);
@@ -1732,6 +1734,7 @@ public class XFLConverter {
// write symbLink
writer.writeStartElement("Include", new String[]{"href", symbolFile});
writer.writeAttribute("itemID", itemId);
if (itemIcon != null) {
writer.writeAttribute("itemIcon", itemIcon);
}
@@ -1747,11 +1750,11 @@ public class XFLConverter {
}
statusStack.pushStatus("extracting multilevel clips");
extractMultilevelClips(lastImportedId, characterNameMap, swf.getTags(), writer, swf, nextClipId, nonLibraryShapes, backgroundColor, flaVersion, files, placeToMaskedSymbol, multiUsageMorphShapes, statusStack);
extractMultilevelClips(lastItemIdNumber, lastImportedId, characterNameMap, swf.getTags(), writer, swf, nextClipId, nonLibraryShapes, backgroundColor, flaVersion, files, placeToMaskedSymbol, multiUsageMorphShapes, statusStack);
statusStack.popStatus();
statusStack.pushStatus("converting multiusage morphshapes");
extractMultiUsageMorphShapes(lastImportedId, characterNameMap, writer, swf, nonLibraryShapes, flaVersion, files, multiUsageMorphShapes, statusStack);
extractMultiUsageMorphShapes(lastItemIdNumber, lastImportedId, characterNameMap, writer, swf, nonLibraryShapes, flaVersion, files, multiUsageMorphShapes, statusStack);
statusStack.popStatus();
/*if (hasSymbol) {
@@ -1759,7 +1762,7 @@ public class XFLConverter {
writer.writeEndElement();
}
private void convertSoundMedia(Map<CharacterTag, String> characterImportLinkageURL, SWF swf, ReadOnlyTagList tags, SoundTag symbol, XFLXmlWriter writer, HashMap<String, byte[]> files, HashMap<String, byte[]> datfiles) throws XMLStreamException {
private void convertSoundMedia(Reference<Integer> lastItemIdNumber, Map<CharacterTag, String> characterImportLinkageURL, SWF swf, ReadOnlyTagList tags, SoundTag symbol, XFLXmlWriter writer, HashMap<String, byte[]> files, HashMap<String, byte[]> datfiles) throws XMLStreamException {
int soundFormat = 0;
int soundRate = 0;
boolean soundType = false;
@@ -1929,6 +1932,7 @@ public class XFLConverter {
files.put(symbolFile, data);
writer.writeStartElement("DOMSoundItem", new String[]{
"name", symbolFile,
"itemID", generateItemId(lastItemIdNumber),
"sourceLastImported", Long.toString(getTimestamp(swf)),
"externalFileSize", Integer.toString(data.length)});
if ((symbol instanceof CharacterTag) && characterImportLinkageURL.containsKey((CharacterTag) symbol)) {
@@ -1945,7 +1949,7 @@ public class XFLConverter {
writer.writeAttribute("sampleCount", soundSampleCount);
}
private void convertMedia(Set<CharacterTag> charactersExportedInFirstFrame, Reference<Integer> lastImportedId, Map<CharacterTag, String> characterNameMap, Map<CharacterTag, String> characterImportLinkageURL, Set<CharacterTag> characters, SWF swf, Map<CharacterTag, String> characterVariables, Map<CharacterTag, String> characterClasses, ReadOnlyTagList tags, HashMap<String, byte[]> files, HashMap<String, byte[]> datfiles, XFLXmlWriter writer, StatusStack statusStack) throws XMLStreamException {
private void convertMedia(Reference<Integer> lastItemIdNumber, Set<CharacterTag> charactersExportedInFirstFrame, Reference<Integer> lastImportedId, Map<CharacterTag, String> characterNameMap, Map<CharacterTag, String> characterImportLinkageURL, Set<CharacterTag> characters, SWF swf, Map<CharacterTag, String> characterVariables, Map<CharacterTag, String> characterClasses, ReadOnlyTagList tags, HashMap<String, byte[]> files, HashMap<String, byte[]> datfiles, XFLXmlWriter writer, StatusStack statusStack) throws XMLStreamException {
boolean hasMedia = false;
for (CharacterTag symbol : characters) {
if (symbol instanceof ImageTag
@@ -2003,8 +2007,9 @@ public class XFLConverter {
ImageFormat format = imageTag.getImageFormat();
String symbolFile = getSymbolName(lastImportedId, characterNameMap, swf, symbol, "Bitmap") + imageTag.getImageFormat().getExtension();
files.put(symbolFile, imageBytes);
writer.writeStartElement("DOMBitmapItem", new String[]{
writer.writeStartElement("DOMBitmapItem", new String[]{
"name", symbolFile,
"itemID", generateItemId(lastItemIdNumber),
"sourceLastImported", Long.toString(getTimestamp(swf)),
"externalFileSize", Integer.toString(imageBytes.length)});
@@ -2061,7 +2066,7 @@ public class XFLConverter {
statusStack.popStatus();
} else if (symbol instanceof DefineSoundTag) {
statusStack.pushStatus(symbol.toString());
convertSoundMedia(characterImportLinkageURL, swf, tags, (DefineSoundTag) symbol, writer, files, datfiles);
convertSoundMedia(lastItemIdNumber, characterImportLinkageURL, swf, tags, (DefineSoundTag) symbol, writer, files, datfiles);
if (characterImportLinkageURL.containsKey(symbol)) {
writer.writeAttribute("linkageImportForRS", "true");
@@ -2148,6 +2153,7 @@ public class XFLConverter {
files.put(symbolFile, data);
writer.writeStartElement("DOMVideoItem", new String[]{
"name", symbolFile,
"itemID", generateItemId(lastItemIdNumber),
"sourceLastImported", Long.toString(getTimestamp(swf)),
"externalFileSize", Integer.toString(data.length)});
if (characterImportLinkageURL.containsKey(symbol)) {
@@ -2188,7 +2194,7 @@ public class XFLConverter {
SoundStreamHeadTypeTag head = (SoundStreamHeadTypeTag) t;
for (SoundStreamFrameRange range : head.getRanges()) {
statusStack.pushStatus(range.toString());
convertSoundMedia(characterImportLinkageURL, swf, tags, range, writer, files, datfiles);
convertSoundMedia(lastItemIdNumber, characterImportLinkageURL, swf, tags, range, writer, files, datfiles);
writer.writeEndElement();
statusStack.popStatus();
}
@@ -2200,7 +2206,7 @@ public class XFLConverter {
SoundStreamHeadTypeTag head = (SoundStreamHeadTypeTag) st;
for (SoundStreamFrameRange range : head.getRanges()) {
statusStack.pushStatus(range.toString());
convertSoundMedia(characterImportLinkageURL, swf, sprite.getTags(), range, writer, files, datfiles);
convertSoundMedia(lastItemIdNumber, characterImportLinkageURL, swf, sprite.getTags(), range, writer, files, datfiles);
writer.writeEndElement();
statusStack.popStatus();
}
@@ -2675,7 +2681,7 @@ public class XFLConverter {
}
}
private static void convertFonts(Set<CharacterTag> charactersExportedInFirstFrame, Reference<Integer> lastImportedId, Map<CharacterTag, String> characterNameMap, SWF swf, Set<CharacterTag> characters, Map<CharacterTag, String> characterClasses, XFLXmlWriter writer, StatusStack statusStack) throws XMLStreamException {
private static void convertFonts(Reference<Integer> lastItemIdNumber, Set<CharacterTag> charactersExportedInFirstFrame, Reference<Integer> lastImportedId, Map<CharacterTag, String> characterNameMap, SWF swf, Set<CharacterTag> characters, Map<CharacterTag, String> characterClasses, XFLXmlWriter writer, StatusStack statusStack) throws XMLStreamException {
boolean hasFont = false;
int fontCounter = 0;
for (CharacterTag t : characters) {
@@ -2758,6 +2764,7 @@ public class XFLConverter {
fontCounter++;
writer.writeStartElement("DOMFontItem", new String[]{
"name", getSymbolName(lastImportedId, characterNameMap, swf, font, "Font"),
"itemID", generateItemId(lastItemIdNumber),
"font", fontName,
"size", "0",
"id", Integer.toString(fontCounter),
@@ -3159,7 +3166,9 @@ public class XFLConverter {
}
private void addExtractedClip(
Reference<Integer> lastImportedId, Map<CharacterTag, String> characterNameMap,
Reference<Integer> lastItemIdNumber,
Reference<Integer> lastImportedId,
Map<CharacterTag, String> characterNameMap,
ReadOnlyTagList timelineTags,
XFLXmlWriter writer,
SWF swf,
@@ -3174,7 +3183,7 @@ public class XFLConverter {
) throws XMLStreamException {
XFLXmlWriter symbolStr = new XFLXmlWriter();
extractMultilevelClips(lastImportedId, characterNameMap, timelineTags, writer, swf, nextClipId, nonLibraryShapes, backgroundColor, flaVersion, files, placeToMaskedSymbol, multiUsageMorphShapes, statusStack);
extractMultilevelClips(lastItemIdNumber, lastImportedId, characterNameMap, timelineTags, writer, swf, nextClipId, nonLibraryShapes, backgroundColor, flaVersion, files, placeToMaskedSymbol, multiUsageMorphShapes, statusStack);
if (nextClipId.getVal() < 0) {
nextClipId.setVal(swf.getNextCharacterId());
@@ -3183,11 +3192,12 @@ public class XFLConverter {
}
int objectId = nextClipId.getVal();
String itemId = generateItemId(lastItemIdNumber);
symbolStr.writeStartElement("DOMSymbolItem", new String[]{
"xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance",
"xmlns", "http://ns.adobe.com/xfl/2008/",
"name", getMaskedSymbolName(objectId),
"itemID", itemId,
"lastModified", Long.toString(getTimestamp(swf))});
symbolStr.writeAttribute("symbolType", "graphic");
@@ -3199,6 +3209,7 @@ public class XFLConverter {
files.put(symbolFile, Utf8Helper.getBytes(symbolStr2));
writer.writeStartElement("Include", new String[]{"href", symbolFile});
writer.writeAttribute("itemID", itemId);
writer.writeAttribute("itemIcon", "1");
writer.writeAttribute("loadImmediate", false);
if (flaVersion.ordinal() >= FLAVersion.CS5_5.ordinal()) {
@@ -3263,7 +3274,9 @@ public class XFLConverter {
}
private void extractMultiUsageMorphShapes(
Reference<Integer> lastImportedId, Map<CharacterTag, String> characterNameMap,
Reference<Integer> lastItemIdNumber,
Reference<Integer> lastImportedId,
Map<CharacterTag, String> characterNameMap,
XFLXmlWriter writer,
SWF swf,
List<CharacterTag> nonLibraryShapes,
@@ -3276,11 +3289,13 @@ public class XFLConverter {
for (int objectId : multiUsageMorphShapes) {
statusStack.pushStatus(swf.getCharacter(objectId).toString());
String itemId = generateItemId(lastItemIdNumber);
XFLXmlWriter symbolStr = new XFLXmlWriter();
symbolStr.writeStartElement("DOMSymbolItem", new String[]{
"xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance",
"xmlns", "http://ns.adobe.com/xfl/2008/",
"name", getSymbolName(lastImportedId, characterNameMap, swf, swf.getCharacter(objectId)),
"itemID", itemId,
"lastModified", Long.toString(getTimestamp(swf))});
symbolStr.writeAttribute("symbolType", "graphic");
@@ -3308,6 +3323,7 @@ public class XFLConverter {
files.put(symbolFile, Utf8Helper.getBytes(symbolStr2));
writer.writeStartElement("Include", new String[]{"href", symbolFile});
writer.writeAttribute("itemID", itemId);
writer.writeAttribute("itemIcon", "1");
writer.writeAttribute("loadImmediate", false);
if (flaVersion.ordinal() >= FLAVersion.CS5_5.ordinal()) {
@@ -3320,7 +3336,9 @@ public class XFLConverter {
}
private void extractMultilevelClips(
Reference<Integer> lastImportedId, Map<CharacterTag, String> characterNameMap,
Reference<Integer> lastItemIdNumber,
Reference<Integer> lastImportedId,
Map<CharacterTag, String> characterNameMap,
ReadOnlyTagList timelineTags,
XFLXmlWriter writer,
SWF swf,
@@ -3520,7 +3538,7 @@ public class XFLConverter {
//set timelined?
delegatedTimeline.add(showFrame);
}
addExtractedClip(lastImportedId, characterNameMap, new ReadOnlyTagList(delegatedTimeline), writer, swf, nextClipId, nonLibraryShapes, backgroundColor, flaVersion, files, placeToMaskedSymbol, multiUsageMorphShapes, statusStack);
addExtractedClip(lastItemIdNumber, lastImportedId, characterNameMap, new ReadOnlyTagList(delegatedTimeline), writer, swf, nextClipId, nonLibraryShapes, backgroundColor, flaVersion, files, placeToMaskedSymbol, multiUsageMorphShapes, statusStack);
placeToMaskedSymbol.put(secondPlace, new MultiLevelClip(secondPlace, nextClipId.getVal(), numFrames));
}
}
@@ -4670,6 +4688,7 @@ public class XFLConverter {
Set<CharacterTag> charactersExportedInFirstFrame = new LinkedIdentityHashSet<>();
Map<CharacterTag, String> characterImportLinkageURL = new IdentityHashMap<>();
Reference<Integer> lastItemIdNumber = new Reference<>(0);
int frame = 1;
for (Tag tag : swf.getTags()) {
if (tag instanceof ImportTag) {
@@ -4717,9 +4736,9 @@ public class XFLConverter {
}
}
}
convertFonts(charactersExportedInFirstFrame, lastImportedId, characterNameMap, swf, characters, characterClasses, domDocument, statusStack);
convertFonts(lastItemIdNumber, charactersExportedInFirstFrame, lastImportedId, characterNameMap, swf, characters, characterClasses, domDocument, statusStack);
convertLibrary(charactersExportedInFirstFrame, characterImportLinkageURL, characters, lastImportedId, characterNameMap, swf, characterVariables, characterClasses, characterScriptPacks, nonLibraryShapes, backgroundColor, swf.getTags(), files, datfiles, flaVersion, domDocument, placeToMaskedSymbol, multiUsageMorphShapes, statusStack);
convertLibrary(lastItemIdNumber, charactersExportedInFirstFrame, characterImportLinkageURL, characters, lastImportedId, characterNameMap, swf, characterVariables, characterClasses, characterScriptPacks, nonLibraryShapes, backgroundColor, swf.getTags(), files, datfiles, flaVersion, domDocument, placeToMaskedSymbol, multiUsageMorphShapes, statusStack);
//domDocument.writeStartElement("timelines");
ScriptPack documentScriptPack = null;
@@ -5203,7 +5222,7 @@ public class XFLConverter {
}
if (useAS3 && settings.exportScript) {
try {
ScriptExportSettings scriptExportSettings = new ScriptExportSettings(ScriptExportMode.AS, false, true, false, true, true);
ScriptExportSettings scriptExportSettings = new ScriptExportSettings(ScriptExportMode.AS, false, true, false, true, true, "/_assets/", Configuration.linkAllClasses.get());
swf.exportActionScript(handler, scriptsDir.getAbsolutePath(), scriptExportSettings, parallel, null);
} catch (Exception ex) {
logger.log(Level.SEVERE, "Error during ActionScript3 export", ex);
@@ -5365,7 +5384,14 @@ public class XFLConverter {
private static double twipToPixel(double tw) {
return tw / SWF.unitDivisor;
}
private static String generateItemId(Reference<Integer> lastItemIdNumber) {
lastItemIdNumber.setVal(lastItemIdNumber.getVal() + 1);
String epochHex = String.format("%1$08x", Math.round(System.currentTimeMillis() / 1000));
String numberHex = String.format("%1$08x", lastItemIdNumber.getVal());
return epochHex + "-" + numberHex;
}
private static class HTMLTextParser extends DefaultHandler {
public XFLXmlWriter result = new XFLXmlWriter();