mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-05-26 06:57:26 +00:00
Added AS3 - Show Embed tag over asset classes (readonly)
Added AS3 - Checkbox for exporting assets embedded using `Embed` (-exportembed in commandline) Added FLA export - AS3 - Using `Embed` tag for DefineBinaryData, images not extending BitmapData
This commit is contained in:
@@ -326,6 +326,8 @@ public class ScriptPack extends AS3ClassTreeItem {
|
||||
FileTextWriter writer2 = exportSettings.singleFile ? exportSettings.singleFileWriter : writer;
|
||||
ConvertData convertData = new ConvertData();
|
||||
convertData.ignoreFrameScripts = exportSettings.ignoreFrameScripts;
|
||||
convertData.exportEmbed = exportSettings.exportEmbed;
|
||||
convertData.exportEmbedFlaMode = exportSettings.exportEmbedFlaMode;
|
||||
toSource(abcIndex, writer2, abc.script_info.get(scriptIndex).traits.traits, convertData, exportSettings.mode, parallel, exportSettings.ignoreFrameScripts);
|
||||
} catch (FileNotFoundException ex) {
|
||||
logger.log(Level.SEVERE, "The file path is probably too long", ex);
|
||||
|
||||
@@ -872,4 +872,21 @@ public final class AbcIndexing {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isInstanceOf(ABC abc, int classIndex, DottedChain searchClassName) {
|
||||
DottedChain clsName = abc.instance_info.get(classIndex).getName(abc.constants).getNameWithNamespace(abc.constants, false);
|
||||
if (searchClassName.equals(clsName)) {
|
||||
return true;
|
||||
}
|
||||
if (abc.instance_info.get(classIndex).super_index == 0) {
|
||||
return false;
|
||||
}
|
||||
DottedChain parentClassName = abc.constants.getMultiname(abc.instance_info.get(classIndex).super_index).getNameWithNamespace(abc.constants, false);
|
||||
|
||||
AbcIndexing.ClassIndex ci = findClass(new TypeItem(parentClassName), abc, null);
|
||||
if (ci == null) {
|
||||
return false;
|
||||
}
|
||||
return isInstanceOf(ci.abc, ci.index, searchClassName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -611,9 +611,15 @@ public class ActionScript3Parser {
|
||||
expected(s, lexer.yyline(), SymbolType.PARENT_CLOSE);
|
||||
s = lex();
|
||||
}
|
||||
metadata.add(en);
|
||||
expected(s, lexer.yyline(), SymbolType.BRACKET_CLOSE);
|
||||
s = lex();
|
||||
|
||||
/**
|
||||
* Skip Embed metadata - these are loaded automatically by the assignment in SymbolClass tag
|
||||
*/
|
||||
if (!"Embed".equals(name)) {
|
||||
metadata.add(en);
|
||||
}
|
||||
}
|
||||
lexer.pushback(s);
|
||||
return metadata;
|
||||
|
||||
@@ -34,6 +34,10 @@ public class ConvertData {
|
||||
public boolean thisHasDefaultToPrimitive;
|
||||
|
||||
public boolean ignoreFrameScripts;
|
||||
|
||||
public boolean exportEmbed;
|
||||
|
||||
public boolean exportEmbedFlaMode;
|
||||
|
||||
public ConvertData() {
|
||||
deobfuscationMode = Configuration.autoDeobfuscate.get() ? 1 : 0;
|
||||
|
||||
@@ -21,7 +21,17 @@ import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Traits;
|
||||
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
|
||||
import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType;
|
||||
import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag;
|
||||
import com.jpexs.decompiler.flash.tags.DefineFont4Tag;
|
||||
import com.jpexs.decompiler.flash.tags.DefineFontAlignZonesTag;
|
||||
import com.jpexs.decompiler.flash.tags.DefineSoundTag;
|
||||
import com.jpexs.decompiler.flash.tags.DefineSpriteTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterIdTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.FontTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ImageTag;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Internal;
|
||||
import com.jpexs.decompiler.flash.types.sound.SoundFormat;
|
||||
import com.jpexs.decompiler.graph.DottedChain;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import java.util.List;
|
||||
@@ -80,7 +90,101 @@ public class InstanceInfo {
|
||||
return "name_index=" + abc.constants.getMultiname(name_index).toString(abc.constants, fullyQualifiedNames) + " super_index=" + supIndexStr + " flags=" + flags + " protectedNS=" + protectedNS + " interfaces=" + Helper.intArrToString(interfaces) + " method_index=" + iinit_index + "\r\n" + instance_traits.toString(abc, fullyQualifiedNames);
|
||||
}
|
||||
|
||||
public GraphTextWriter getClassHeaderStr(GraphTextWriter writer, ABC abc, List<DottedChain> fullyQualifiedNames, boolean allowPrivate) {
|
||||
public GraphTextWriter getClassHeaderStr(GraphTextWriter writer, ABC abc, List<DottedChain> fullyQualifiedNames, boolean allowPrivate, boolean allowEmbed) {
|
||||
|
||||
final String ASSETS_DIR = "/_assets/";
|
||||
if (allowEmbed) {
|
||||
if (abc.getSwf() != null) {
|
||||
String className = getName(abc.constants).getNameWithNamespace(abc.constants, false).toRawString();
|
||||
CharacterTag ct = abc.getSwf().getCharacterByClass(className);
|
||||
if (ct != null) {
|
||||
if (ct instanceof DefineBinaryDataTag) {
|
||||
writer.appendNoHilight("[Embed(source=\"" + ASSETS_DIR + ct.getCharacterExportFileName() + ".bin\", mimeType=\"application/octet-stream\")]").newLine();
|
||||
}
|
||||
if (ct instanceof ImageTag) {
|
||||
ImageTag it = (ImageTag) ct;
|
||||
writer.appendNoHilight("[Embed(source=\"" + ASSETS_DIR + ct.getCharacterExportFileName() + ((ImageTag) ct).getImageFormat().getExtension() + "\")]").newLine();
|
||||
}
|
||||
if (ct instanceof DefineSpriteTag) {
|
||||
writer.appendNoHilight("[Embed(source=\"" + ASSETS_DIR + "assets.swf\", symbol=\"" + className + "\")]").newLine();
|
||||
}
|
||||
if (ct instanceof DefineSoundTag) {
|
||||
//should be mp3, otherwise it won't work. Should we convert this?
|
||||
DefineSoundTag st = (DefineSoundTag) ct;
|
||||
writer.appendNoHilight("[Embed(source=\"" + ASSETS_DIR + ct.getCharacterExportFileName() + "." + (st.getSoundFormat().formatId == SoundFormat.FORMAT_MP3 ? "mp3" : "wav") + "\")]").newLine();
|
||||
}
|
||||
if (ct instanceof FontTag) {
|
||||
FontTag ft = (FontTag) ct;
|
||||
|
||||
boolean hasFontAlignZones = false;
|
||||
List<CharacterIdTag> sameIdTags = ft.getSwf().getCharacterIdTags(ft.getFontId());
|
||||
for (CharacterIdTag sit : sameIdTags) {
|
||||
if (sit instanceof DefineFontAlignZonesTag) {
|
||||
hasFontAlignZones = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
writer.appendNoHilight("[Embed(source=\"" + ASSETS_DIR + ct.getCharacterExportFileName() + ".ttf\",").newLine();
|
||||
writer.appendNoHilight("fontName=\"" + ft.getFontName() + "\",").newLine();
|
||||
writer.appendNoHilight("mimeType=\"application/x-font\",").newLine();
|
||||
writer.appendNoHilight("fontWeight=\"" + (ft.isBold() ? "bold" : "normal") + "\",").newLine();
|
||||
writer.appendNoHilight("fontStyle=\"" + (ft.isItalic() ? "italic" : "normal") + "\",").newLine();
|
||||
String fontChars = ft.getCharacters();
|
||||
if (!fontChars.isEmpty()) {
|
||||
Character firstC = null;
|
||||
Character lastC = null;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < fontChars.length(); i++) {
|
||||
char c = fontChars.charAt(i);
|
||||
if (firstC == null) {
|
||||
firstC = c;
|
||||
lastC = c;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (lastC + 1 != c) {
|
||||
if (!sb.isEmpty()) {
|
||||
sb.append(",");
|
||||
}
|
||||
if (firstC == lastC) {
|
||||
sb.append(String.format("U+%04X", (int) firstC));
|
||||
} else {
|
||||
sb.append(String.format("U+%04X-%04X", (int) firstC, (int) lastC));
|
||||
}
|
||||
firstC = c;
|
||||
}
|
||||
lastC = c;
|
||||
}
|
||||
if (!sb.isEmpty()) {
|
||||
sb.append(",");
|
||||
}
|
||||
if (firstC == lastC) {
|
||||
sb.append(String.format("U+%04X", (int) firstC));
|
||||
} else {
|
||||
sb.append(String.format("U+%04X-%04X", (int) firstC, (int) lastC));
|
||||
}
|
||||
writer.appendNoHilight("unicodeRange=\"").appendNoHilight(sb.toString()).appendNoHilight("\",").newLine();
|
||||
}
|
||||
writer.appendNoHilight("advancedAntiAliasing=\"" + (hasFontAlignZones ? "true" : "false") + "\",").newLine();
|
||||
writer.appendNoHilight("embedAsCFF=\"false\"").newLine();
|
||||
writer.appendNoHilight(")]").newLine();
|
||||
}
|
||||
|
||||
if (ct instanceof DefineFont4Tag) {
|
||||
DefineFont4Tag ft4 = (DefineFont4Tag)ct;
|
||||
writer.appendNoHilight("[Embed(source=\"" + ASSETS_DIR + ct.getCharacterExportFileName() + ".cff\",").newLine();
|
||||
writer.appendNoHilight("fontName=\"" + ft4.fontName + "\",").newLine();
|
||||
writer.appendNoHilight("mimeType=\"application/x-font\",").newLine();
|
||||
writer.appendNoHilight("fontWeight=\"" + (ft4.fontFlagsBold ? "bold" : "normal") + "\",").newLine();
|
||||
writer.appendNoHilight("fontStyle=\"" + (ft4.fontFlagsItalic ? "italic" : "normal") + "\",").newLine();
|
||||
writer.appendNoHilight("embedAsCFF=\"true\"").newLine();
|
||||
writer.appendNoHilight(")]").newLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String modifiers;
|
||||
Namespace ns = abc.constants.getMultiname(name_index).getNamespace(abc.constants);
|
||||
modifiers = ns.getPrefix(abc);
|
||||
@@ -104,7 +208,7 @@ public class InstanceInfo {
|
||||
|
||||
writer.appendNoHilight(modifiers + objType);
|
||||
String classTypeName = abc.constants.getMultiname(name_index).getNameWithNamespace(abc.constants, true).toRawString();
|
||||
|
||||
|
||||
writer.hilightSpecial(abc.constants.getMultiname(name_index).getName(abc.constants, null/* No full names here*/, false, true), HighlightSpecialType.CLASS_NAME, classTypeName);
|
||||
|
||||
if (super_index > 0) {
|
||||
|
||||
@@ -40,6 +40,10 @@ import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
|
||||
import com.jpexs.decompiler.flash.helpers.NulWriter;
|
||||
import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType;
|
||||
import com.jpexs.decompiler.flash.search.MethodId;
|
||||
import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag;
|
||||
import com.jpexs.decompiler.flash.tags.DefineFont4Tag;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ImageTag;
|
||||
import com.jpexs.decompiler.graph.DottedChain;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.ScopeStack;
|
||||
@@ -109,7 +113,7 @@ public class TraitClass extends Trait implements TraitWithSlot {
|
||||
|
||||
@Override
|
||||
public GraphTextWriter toStringHeader(Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, GraphTextWriter writer, List<DottedChain> fullyQualifiedNames, boolean parallel, boolean insideInterface) {
|
||||
abc.instance_info.get(class_info).getClassHeaderStr(writer, abc, fullyQualifiedNames, false);
|
||||
abc.instance_info.get(class_info).getClassHeaderStr(writer, abc, fullyQualifiedNames, false, false /*??*/);
|
||||
return writer;
|
||||
}
|
||||
|
||||
@@ -117,13 +121,15 @@ public class TraitClass extends Trait implements TraitWithSlot {
|
||||
public void convertHeader(Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, NulWriter writer, List<DottedChain> fullyQualifiedNames, boolean parallel) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public GraphTextWriter toString(AbcIndexing abcIndex, Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, GraphTextWriter writer, List<DottedChain> fullyQualifiedNames, boolean parallel, boolean insideInterface) throws InterruptedException {
|
||||
|
||||
InstanceInfo instanceInfo = abc.instance_info.get(class_info);
|
||||
|
||||
boolean isInterface = instanceInfo.isInterface();
|
||||
|
||||
|
||||
boolean isInterface = instanceInfo.isInterface();
|
||||
|
||||
Multiname instanceInfoMultiname = instanceInfo.getName(abc.constants);
|
||||
DottedChain packageName = instanceInfoMultiname.getNamespace(abc.constants).getName(abc.constants); //assume not null name
|
||||
|
||||
@@ -132,11 +138,42 @@ public class TraitClass extends Trait implements TraitWithSlot {
|
||||
|
||||
String instanceInfoName = instanceInfoMultiname.getName(abc.constants, fullyQualifiedNames, false, true);
|
||||
|
||||
|
||||
getMetaData(parent, convertData, abc, writer);
|
||||
|
||||
boolean allowEmbed = true;
|
||||
|
||||
if (convertData.exportEmbedFlaMode) {
|
||||
allowEmbed = false;
|
||||
if (abc.getSwf() != null) {
|
||||
CharacterTag ct = abc.getSwf().getCharacterByClass(instanceInfoMultiname.getNameWithNamespace(abc.constants, false).toRawString());
|
||||
if (ct == null) {
|
||||
allowEmbed = false;
|
||||
} else {
|
||||
if (ct instanceof DefineBinaryDataTag) {
|
||||
allowEmbed = true;
|
||||
}
|
||||
|
||||
if (ct instanceof ImageTag) {
|
||||
allowEmbed = true;
|
||||
if (abcIndex.isInstanceOf(abc, class_info, DottedChain.parseNoSuffix("flash.display.BitmapData"))) {
|
||||
allowEmbed = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ct instanceof DefineFont4Tag) {
|
||||
allowEmbed = true;
|
||||
}
|
||||
|
||||
if (ct.getClassNames().size() > 1) {
|
||||
allowEmbed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//class header
|
||||
instanceInfo.getClassHeaderStr(writer, abc, fullyQualifiedNames, false);
|
||||
writer.endTrait();
|
||||
instanceInfo.getClassHeaderStr(writer, abc, fullyQualifiedNames, false, allowEmbed);
|
||||
writer.endTrait();
|
||||
writer.startBlock();
|
||||
writer.startClass(class_info);
|
||||
|
||||
@@ -177,7 +214,7 @@ public class TraitClass extends Trait implements TraitWithSlot {
|
||||
//instance initializer - constructor
|
||||
if (!instanceInfo.isInterface()) {
|
||||
String modifier = "public ";
|
||||
Multiname m = abc.constants.getMultiname(instanceInfo.name_index);
|
||||
Multiname m = abc.constants.getMultiname(instanceInfo.name_index);
|
||||
|
||||
writer.newLine();
|
||||
writer.startTrait(GraphTextWriter.TRAIT_INSTANCE_INITIALIZER);
|
||||
@@ -209,7 +246,7 @@ public class TraitClass extends Trait implements TraitWithSlot {
|
||||
//instance methods
|
||||
instanceInfo.instance_traits.toString(abcIndex, new Class[]{TraitClass.class, TraitFunction.class, TraitMethodGetterSetter.class}, this, convertData, path +/*packageName +*/ "/" + instanceInfoName, abc, false, exportMode, false, scriptIndex, class_info, writer, fullyQualifiedNames, parallel, convertData.ignoreFrameScripts ? frameTraitNames : new ArrayList<>(), isInterface);
|
||||
|
||||
writer.endClass();
|
||||
writer.endClass();
|
||||
writer.endBlock(); // class
|
||||
writer.newLine();
|
||||
return writer;
|
||||
@@ -236,8 +273,8 @@ public class TraitClass extends Trait implements TraitWithSlot {
|
||||
}
|
||||
} else {
|
||||
convertData.thisHasDefaultToPrimitive = true;
|
||||
}
|
||||
ScopeStack newScopeStack = (ScopeStack)scopeStack.clone();
|
||||
}
|
||||
ScopeStack newScopeStack = (ScopeStack) scopeStack.clone();
|
||||
//class initializer
|
||||
int bodyIndex = abc.findBodyIndex(classInfo.cinit_index);
|
||||
if (bodyIndex != -1) {
|
||||
@@ -245,27 +282,27 @@ public class TraitClass extends Trait implements TraitWithSlot {
|
||||
List<Traits> ts = new ArrayList<>();
|
||||
ts.add(classInfo.static_traits);
|
||||
List<MethodBody> callStack = new ArrayList<>();
|
||||
callStack.add(abc.bodies.get(bodyIndex));
|
||||
|
||||
callStack.add(abc.bodies.get(bodyIndex));
|
||||
|
||||
if (!abc.instance_info.get(class_info).isInterface()) {
|
||||
AbcIndexing.ClassIndex cls = abcIndex.findClass(AbcIndexing.multinameToType(abc.instance_info.get(class_info).name_index, abc.constants), abc, scriptIndex);
|
||||
List<AbcIndexing.ClassIndex> clsList = new ArrayList<>();
|
||||
cls = cls.parent;
|
||||
while(cls != null) {
|
||||
while (cls != null) {
|
||||
clsList.add(0, cls);
|
||||
cls = cls.parent;
|
||||
}
|
||||
for (AbcIndexing.ClassIndex cls2: clsList) {
|
||||
for (AbcIndexing.ClassIndex cls2 : clsList) {
|
||||
newScopeStack.push(new ClassAVM2Item(cls2.abc.instance_info.get(cls2.index).getName(cls2.abc.constants).getNameWithNamespace(cls2.abc.constants, true)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
abc.bodies.get(bodyIndex).convert(callStack, abcIndex, convertData, path +/*packageName +*/ "/" + instanceInfoName + ".staticinitializer", exportMode, true, classInfo.cinit_index, scriptIndex, class_info, abc, this, newScopeStack, GraphTextWriter.TRAIT_CLASS_INITIALIZER, writer, fullyQualifiedNames, ts, true, new HashSet<>());
|
||||
|
||||
newScopeStack.push(new ClassAVM2Item(abc.instance_info.get(class_info).getName(abc.constants)));
|
||||
|
||||
newScopeStack.push(new ClassAVM2Item(abc.instance_info.get(class_info).getName(abc.constants)));
|
||||
classInitializerIsEmpty = !writer.getMark();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//constructor - instance initializer
|
||||
if (!instanceInfo.isInterface()) {
|
||||
bodyIndex = abc.findBodyIndex(instanceInfo.iinit_index);
|
||||
@@ -274,7 +311,7 @@ public class TraitClass extends Trait implements TraitWithSlot {
|
||||
ts.add(instanceInfo.instance_traits);
|
||||
MethodBody constructorBody = abc.bodies.get(bodyIndex);
|
||||
List<MethodBody> callStack = new ArrayList<>();
|
||||
callStack.add(constructorBody);
|
||||
callStack.add(constructorBody);
|
||||
constructorBody.convert(callStack, abcIndex, convertData, path +/*packageName +*/ "/" + instanceInfoName + ".initializer", exportMode, false, instanceInfo.iinit_index, scriptIndex, class_info, abc, this, new ScopeStack(), GraphTextWriter.TRAIT_INSTANCE_INITIALIZER, writer, fullyQualifiedNames, ts, true, new HashSet<>());
|
||||
|
||||
if (convertData.ignoreFrameScripts) {
|
||||
@@ -372,7 +409,7 @@ public class TraitClass extends Trait implements TraitWithSlot {
|
||||
writer.appendNoHilight("instance ").hilightSpecial(abc.constants.multinameToString(ii.name_index), HighlightSpecialType.INSTANCE_NAME).newLine();
|
||||
writer.indent();
|
||||
writer.appendNoHilight("extends ").hilightSpecial(abc.constants.multinameToString(ii.super_index), HighlightSpecialType.EXTENDS).newLine();
|
||||
for(int iface : ii.interfaces) {
|
||||
for (int iface : ii.interfaces) {
|
||||
writer.appendNoHilight("implements ").hilightSpecial(abc.constants.multinameToString(iface), HighlightSpecialType.IMPLEMENTS).newLine();
|
||||
}
|
||||
if ((ii.flags & InstanceInfo.CLASS_SEALED) == InstanceInfo.CLASS_SEALED) {
|
||||
@@ -386,7 +423,7 @@ public class TraitClass extends Trait implements TraitWithSlot {
|
||||
}
|
||||
if ((ii.flags & InstanceInfo.CLASS_PROTECTEDNS) == InstanceInfo.CLASS_PROTECTEDNS) {
|
||||
writer.appendNoHilight("flag PROTECTEDNS").newLine();
|
||||
}
|
||||
}
|
||||
if ((ii.flags & InstanceInfo.CLASS_NON_NULLABLE) == InstanceInfo.CLASS_NON_NULLABLE) {
|
||||
writer.appendNoHilight("flag NON_NULLABLE").newLine();
|
||||
}
|
||||
@@ -396,7 +433,7 @@ public class TraitClass extends Trait implements TraitWithSlot {
|
||||
writer.unindent();
|
||||
writer.appendNoHilight("end ; instance").newLine();
|
||||
writer.unindent();
|
||||
writer.appendNoHilight("end ; class").newLine();
|
||||
writer.appendNoHilight("end ; class").newLine();
|
||||
return writer;
|
||||
}
|
||||
|
||||
|
||||
@@ -915,6 +915,10 @@ public final class Configuration {
|
||||
@ConfigurationName("warning.cannotencrypt")
|
||||
public static ConfigurationItem<Boolean> warningCannotEncrypt = null;
|
||||
|
||||
@ConfigurationDefaultBoolean(true)
|
||||
@ConfigurationCategory("export")
|
||||
public static ConfigurationItem<Boolean> lastExportEnableEmbed = null;
|
||||
|
||||
private enum OSId {
|
||||
WINDOWS, OSX, UNIX
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@ import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -342,7 +343,7 @@ public class PreviewExporter {
|
||||
Frame fn = (Frame) treeItem;
|
||||
Timelined parent = fn.timeline.timelined;
|
||||
|
||||
Set<Integer> doneCharacters = new HashSet<>();
|
||||
Set<Integer> doneCharacters = new LinkedHashSet<>();
|
||||
for (Tag t : parent.getTags()) {
|
||||
if (t instanceof FileAttributesTag || t instanceof SetBackgroundColorTag) {
|
||||
continue;
|
||||
@@ -353,7 +354,7 @@ public class PreviewExporter {
|
||||
continue;
|
||||
}
|
||||
|
||||
Set<Integer> needed = new HashSet<>();
|
||||
Set<Integer> needed = new LinkedHashSet<>();
|
||||
t.getNeededCharactersDeep(needed);
|
||||
for (int n : needed) {
|
||||
if (!doneCharacters.contains(n)) {
|
||||
|
||||
@@ -18,7 +18,10 @@ package com.jpexs.decompiler.flash.exporters.script;
|
||||
|
||||
import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler;
|
||||
import com.jpexs.decompiler.flash.EventListener;
|
||||
import com.jpexs.decompiler.flash.ReadOnlyTagList;
|
||||
import com.jpexs.decompiler.flash.RetryTask;
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.abc.ScriptPack;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.CallPropertyAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.CoerceAVM2Item;
|
||||
@@ -41,9 +44,42 @@ import com.jpexs.decompiler.flash.abc.types.traits.TraitClass;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.TraitMethodGetterSetter;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.ecma.EcmaScript;
|
||||
import com.jpexs.decompiler.flash.exporters.BinaryDataExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.Font4Exporter;
|
||||
import com.jpexs.decompiler.flash.exporters.FontExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.ImageExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.SoundExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.BinaryDataExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.Font4ExportMode;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.FontExportMode;
|
||||
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 com.jpexs.decompiler.flash.exporters.settings.BinaryDataExportSettings;
|
||||
import com.jpexs.decompiler.flash.exporters.settings.Font4ExportSettings;
|
||||
import com.jpexs.decompiler.flash.exporters.settings.FontExportSettings;
|
||||
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.helpers.NulWriter;
|
||||
import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag;
|
||||
import com.jpexs.decompiler.flash.tags.DefineFont4Tag;
|
||||
import com.jpexs.decompiler.flash.tags.DefineSoundTag;
|
||||
import com.jpexs.decompiler.flash.tags.DefineSpriteTag;
|
||||
import com.jpexs.decompiler.flash.tags.EndTag;
|
||||
import com.jpexs.decompiler.flash.tags.FileAttributesTag;
|
||||
import com.jpexs.decompiler.flash.tags.SetBackgroundColorTag;
|
||||
import com.jpexs.decompiler.flash.tags.ShowFrameTag;
|
||||
import com.jpexs.decompiler.flash.tags.SymbolClassTag;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterIdTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
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.types.RGB;
|
||||
import com.jpexs.decompiler.graph.DottedChain;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.ScopeStack;
|
||||
import com.jpexs.helpers.CancellableWorker;
|
||||
@@ -51,10 +87,14 @@ import com.jpexs.helpers.Helper;
|
||||
import com.jpexs.helpers.Path;
|
||||
import com.jpexs.helpers.XmlPrettyFormat;
|
||||
import com.jpexs.helpers.utf8.Utf8Helper;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -115,7 +155,7 @@ public class AS3ScriptExporter {
|
||||
int name2 = ((FullMultinameAVM2Item) cap.propertyName).multinameIndex;
|
||||
for (Trait ct : pack.abc.instance_info.get(cindex).instance_traits.traits) {
|
||||
if (ct.name_index == name2 && (ct instanceof TraitMethodGetterSetter)) {
|
||||
tagContent.append(handleMxmlMethod(abcIndex,namespaces, pack, cindex, (TraitMethodGetterSetter) ct));
|
||||
tagContent.append(handleMxmlMethod(abcIndex, namespaces, pack, cindex, (TraitMethodGetterSetter) ct));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -433,6 +473,129 @@ public class AS3ScriptExporter {
|
||||
}
|
||||
}
|
||||
|
||||
if (exportSettings.exportEmbedFlaMode || exportSettings.exportEmbed) {
|
||||
final String ASSETS_DIR = outdir + "/_assets/";
|
||||
List<Tag> exportTagList = new ArrayList<>();
|
||||
List<DefineSpriteTag> spriteTagList = new ArrayList<>();
|
||||
|
||||
for (ScriptPack item : packs) {
|
||||
if (!item.isSimple && Configuration.ignoreCLikePackages.get()) {
|
||||
continue;
|
||||
}
|
||||
String className = item.getClassPath().toRawString();
|
||||
CharacterTag ct = swf.getCharacterByClass(className);
|
||||
if (ct == null) {
|
||||
continue;
|
||||
}
|
||||
if (ct instanceof DefineBinaryDataTag) {
|
||||
exportTagList.add(ct);
|
||||
}
|
||||
if (ct instanceof ImageTag) {
|
||||
int classIndex = item.abc.findClassByName(className);
|
||||
if (exportSettings.exportEmbedFlaMode && classIndex != -1 && swf.getAbcIndex().isInstanceOf(item.abc, classIndex, DottedChain.parseNoSuffix("flash.display.BitmapData"))) {
|
||||
continue;
|
||||
}
|
||||
exportTagList.add(ct);
|
||||
}
|
||||
if (!exportSettings.exportEmbedFlaMode) {
|
||||
if (ct instanceof DefineSpriteTag) {
|
||||
spriteTagList.add((DefineSpriteTag) ct);
|
||||
}
|
||||
if (ct instanceof DefineSoundTag) {
|
||||
exportTagList.add(ct);
|
||||
}
|
||||
if (ct instanceof FontTag) {
|
||||
exportTagList.add(ct);
|
||||
}
|
||||
}
|
||||
if (ct instanceof DefineFont4Tag) {
|
||||
exportTagList.add(ct);
|
||||
}
|
||||
}
|
||||
ReadOnlyTagList rttl = new ReadOnlyTagList(exportTagList);
|
||||
try {
|
||||
BinaryDataExporter bde = new BinaryDataExporter();
|
||||
bde.exportBinaryData(handler, ASSETS_DIR, rttl, new BinaryDataExportSettings(BinaryDataExportMode.RAW), evl);
|
||||
ImageExporter ie = new ImageExporter();
|
||||
ie.exportImages(handler, ASSETS_DIR, rttl, new ImageExportSettings(ImageExportMode.PNG_GIF_JPEG), evl);
|
||||
SoundExporter se = new SoundExporter();
|
||||
se.exportSounds(handler, ASSETS_DIR, rttl, new SoundExportSettings(SoundExportMode.MP3_WAV), evl);
|
||||
FontExporter fe = new FontExporter();
|
||||
fe.exportFonts(handler, ASSETS_DIR, rttl, new FontExportSettings(FontExportMode.TTF), evl);
|
||||
Font4Exporter f4e = new Font4Exporter();
|
||||
f4e.exportFonts(handler, ASSETS_DIR, rttl, new Font4ExportSettings(Font4ExportMode.CFF), evl);
|
||||
|
||||
if (!spriteTagList.isEmpty()) {
|
||||
new RetryTask(() -> {
|
||||
try (FileOutputStream fos = new FileOutputStream(ASSETS_DIR + "/assets.swf")) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
SWFOutputStream sos2 = new SWFOutputStream(baos, swf.version, swf.getCharset());
|
||||
sos2.writeRECT(swf.displayRect);
|
||||
sos2.writeFIXED8(swf.frameRate);
|
||||
sos2.writeUI16(1);
|
||||
FileAttributesTag fa = swf.getFileAttributes();
|
||||
if (fa != null) {
|
||||
fa.writeTag(sos2);
|
||||
}
|
||||
SetBackgroundColorTag setBgColorTag = swf.getBackgroundColor();
|
||||
if (setBgColorTag != null) {
|
||||
setBgColorTag.writeTag(sos2);
|
||||
}
|
||||
|
||||
Set<Integer> neededCharacters = new LinkedHashSet<>();
|
||||
List<Integer> symbolClassIds = new ArrayList<>();
|
||||
List<String> symbolClassNames = new ArrayList<>();
|
||||
for (DefineSpriteTag st : spriteTagList) {
|
||||
st.getNeededCharactersDeep(neededCharacters);
|
||||
neededCharacters.add(st.spriteId);
|
||||
}
|
||||
for (int n : neededCharacters) {
|
||||
CharacterTag ct = (CharacterTag) swf.getCharacter(n);
|
||||
if (ct == null) {
|
||||
continue;
|
||||
}
|
||||
ct.writeTag(sos2);
|
||||
for (String cls : ct.getClassNames()) {
|
||||
symbolClassIds.add(ct.getCharacterId());
|
||||
symbolClassNames.add(cls);
|
||||
}
|
||||
List<CharacterIdTag> cidTags = swf.getCharacterIdTags(n);
|
||||
for (CharacterIdTag t : cidTags) {
|
||||
if (t instanceof PlaceObjectTypeTag) {
|
||||
continue;
|
||||
}
|
||||
if (t instanceof RemoveTag) {
|
||||
continue;
|
||||
}
|
||||
((Tag) t).writeTag(sos2);
|
||||
}
|
||||
}
|
||||
|
||||
SymbolClassTag sc = new SymbolClassTag(swf);
|
||||
sc.names = symbolClassNames;
|
||||
sc.tags = symbolClassIds;
|
||||
sc.writeTag(sos2);
|
||||
|
||||
new ShowFrameTag(swf).writeTag(sos2);
|
||||
new EndTag(swf).writeTag(sos2);
|
||||
|
||||
SWFOutputStream sos = new SWFOutputStream(fos, swf.version, swf.getCharset());
|
||||
sos.write("FWS".getBytes());
|
||||
sos.write(swf.version);
|
||||
byte data[] = baos.toByteArray();
|
||||
long fileSize = sos.getPos() + data.length + 4;
|
||||
sos.writeUI32(fileSize);
|
||||
sos.write(data);
|
||||
}
|
||||
}, handler).run();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(AS3ScriptExporter.class.getName()).log(Level.SEVERE, null, ex);
|
||||
} catch (InterruptedException ex) {
|
||||
Logger.getLogger(AS3ScriptExporter.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,11 +34,23 @@ public class ScriptExportSettings {
|
||||
public FileTextWriter singleFileWriter;
|
||||
|
||||
public boolean ignoreFrameScripts;
|
||||
|
||||
public boolean exportEmbed;
|
||||
|
||||
public boolean exportEmbedFlaMode;
|
||||
|
||||
public ScriptExportSettings(ScriptExportMode mode, boolean singleFile, boolean ignoreFrameScripts) {
|
||||
public ScriptExportSettings(
|
||||
ScriptExportMode mode,
|
||||
boolean singleFile,
|
||||
boolean ignoreFrameScripts,
|
||||
boolean exportEmbed,
|
||||
boolean exportEmbedFlaMode
|
||||
) {
|
||||
this.mode = mode;
|
||||
this.singleFile = singleFile;
|
||||
this.ignoreFrameScripts = ignoreFrameScripts;
|
||||
this.exportEmbed = exportEmbed;
|
||||
this.exportEmbedFlaMode = exportEmbedFlaMode;
|
||||
}
|
||||
|
||||
public String getFileExtension() {
|
||||
|
||||
@@ -297,7 +297,7 @@ public class MxmlcAs3ScriptReplacer extends MxmlcRunner implements As3ScriptRepl
|
||||
//This compiled code won't be used at all in original SWF,
|
||||
//it is used only by Flex to properly compile current script
|
||||
AS3ScriptExporter ex = new AS3ScriptExporter();
|
||||
ex.exportActionScript3(swfCopy, null, tempDir.getAbsolutePath(), removedPacks, new ScriptExportSettings(ScriptExportMode.AS_METHOD_STUBS, false, false), false, null);
|
||||
ex.exportActionScript3(swfCopy, null, tempDir.getAbsolutePath(), removedPacks, new ScriptExportSettings(ScriptExportMode.AS_METHOD_STUBS, false, false, false /* ??? FIXME */, false), false, null);
|
||||
|
||||
//now really remove the classes from SWF copy
|
||||
for (ABC a : modAbcs) {
|
||||
|
||||
@@ -52,7 +52,7 @@ public class AS3ScriptImporter {
|
||||
return importCount;
|
||||
}
|
||||
try {
|
||||
File file = pack.getExportFile(scriptsFolder, new ScriptExportSettings(ScriptExportMode.AS, false, false));
|
||||
File file = pack.getExportFile(scriptsFolder, new ScriptExportSettings(ScriptExportMode.AS, false, false, false, false));
|
||||
if (file.exists()) {
|
||||
Openable openable = pack.getOpenable();
|
||||
SWF swf = (openable instanceof SWF) ? (SWF) openable : ((ABC)openable).getSwf();
|
||||
|
||||
@@ -71,6 +71,7 @@ import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
|
||||
import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter;
|
||||
import com.jpexs.decompiler.flash.helpers.NulWriter;
|
||||
import com.jpexs.decompiler.flash.helpers.StringBuilderTextWriter;
|
||||
import com.jpexs.decompiler.flash.tags.ABCContainerTag;
|
||||
import com.jpexs.decompiler.flash.tags.CSMTextSettingsTag;
|
||||
import com.jpexs.decompiler.flash.tags.DefineButton2Tag;
|
||||
import com.jpexs.decompiler.flash.tags.DefineButtonCxformTag;
|
||||
@@ -148,6 +149,7 @@ import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord;
|
||||
import com.jpexs.decompiler.flash.types.sound.MP3FRAME;
|
||||
import com.jpexs.decompiler.flash.types.sound.MP3SOUNDDATA;
|
||||
import com.jpexs.decompiler.flash.types.sound.SoundFormat;
|
||||
import com.jpexs.decompiler.graph.DottedChain;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.ScopeStack;
|
||||
@@ -1871,8 +1873,22 @@ public class XFLConverter {
|
||||
break;
|
||||
}
|
||||
if (characterClasses.containsKey(symbol.getCharacterId())) {
|
||||
writer.writeAttribute("linkageExportForAS", true);
|
||||
writer.writeAttribute("linkageClassName", characterClasses.get(symbol.getCharacterId()));
|
||||
String className = characterClasses.get(symbol.getCharacterId());
|
||||
boolean isBitmapData = false;
|
||||
for (ABCContainerTag c : swf.getAbcList()) {
|
||||
int classIndex = c.getABC().findClassByName(className);
|
||||
if (classIndex != -1) {
|
||||
if (swf.getAbcIndex().isInstanceOf(c.getABC(), classIndex, DottedChain.parseNoSuffix("flash.display.BitmapData"))) {
|
||||
isBitmapData = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isBitmapData) {
|
||||
writer.writeAttribute("linkageExportForAS", true);
|
||||
writer.writeAttribute("linkageClassName", characterClasses.get(symbol.getCharacterId()));
|
||||
}
|
||||
//if it's not BitmapData, then it should use Embed
|
||||
}
|
||||
writer.writeAttribute("quality", 50);
|
||||
writer.writeAttribute("href", symbolFile);
|
||||
@@ -4152,7 +4168,7 @@ public class XFLConverter {
|
||||
}
|
||||
if (useAS3 && settings.exportScript) {
|
||||
try {
|
||||
ScriptExportSettings scriptExportSettings = new ScriptExportSettings(ScriptExportMode.AS, false, true);
|
||||
ScriptExportSettings scriptExportSettings = new ScriptExportSettings(ScriptExportMode.AS, false, true, false, true);
|
||||
swf.exportActionScript(handler, scriptsDir.getAbsolutePath(), scriptExportSettings, parallel, null);
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.SEVERE, "Error during ActionScript3 export", ex);
|
||||
|
||||
Reference in New Issue
Block a user