AS3 editation with flex - not really working yet:

- needs fixing circular references, etc. (eg. editing class which references classes which references this class)
 - needs better errors displaying with jump to error line, etc.
This commit is contained in:
Jindra Petřík
2016-08-06 07:19:52 +02:00
parent c8951d9522
commit 8c5345cfd8
25 changed files with 1067 additions and 154 deletions
@@ -0,0 +1,152 @@
package com.jpexs.decompiler.flash.flexsdk;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.ScriptPack;
import com.jpexs.decompiler.flash.abc.types.InstanceInfo;
import com.jpexs.decompiler.flash.abc.types.ScriptInfo;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.exporters.script.LinkReportExporter;
import com.jpexs.decompiler.flash.exporters.swf.SwfToSwcExporter;
import com.jpexs.decompiler.flash.tags.ABCContainerTag;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.graph.DottedChain;
import com.jpexs.helpers.Helper;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.util.List;
public class As3ScriptReplacer extends MxmlcRunner {
private LinkReportExporter linkReporter;
public As3ScriptReplacer(String flexSdkPath, LinkReportExporter linkReporter) {
super(flexSdkPath);
this.linkReporter = linkReporter;
}
private static void deleteFolder(File folder) {
File[] files = folder.listFiles();
if (files != null) { //some JVMs return null for empty dirs
for (File f : files) {
if (f.isDirectory()) {
deleteFolder(f);
} else {
f.delete();
}
}
}
folder.delete();
}
private SWF recompileSWF(SWF swf) throws IOException, InterruptedException {
ByteArrayOutputStream swfOrigBaos = new ByteArrayOutputStream();
swf.saveTo(swfOrigBaos);
return new SWF(new ByteArrayInputStream(swfOrigBaos.toByteArray()), false, false);
}
private boolean isParentDeleted(ABC abc, List<ABC> allAbcs, DottedChain className) {
int class_index = abc.findClassByName(className);
if (class_index == -1) {
for (ABC a : allAbcs) {
class_index = abc.findClassByName(className);
if (class_index != -1) {
abc = a;
break;
}
}
if (class_index == -1) {
return false;
}
}
InstanceInfo ii = abc.instance_info.get(class_index);
if (ii.deleted) {
return true;
}
if (ii.super_index != 0 && isParentDeleted(abc, allAbcs, abc.constants.getMultiname(ii.super_index).getNameWithNamespace(abc.constants))) {
return true;
}
for (int iface : ii.interfaces) {
if (isParentDeleted(abc, allAbcs, abc.constants.getMultiname(iface).getNameWithNamespace(abc.constants))) {
return true;
}
}
return false;
}
public void replaceScript(SWF swf, ScriptPack oldPack, String txt) throws IOException, MxmlcException, InterruptedException {
if (!oldPack.isSimple) {
throw new IOException("Cannot compile such file"); //Alchemy, etc.
}
File tempDir = null;
try {
tempDir = Files.createTempDirectory("ffdec-mxmlc-replace").toFile();
File pkgDir = tempDir;
for (String pkgPart : oldPack.getClassPath().packageStr.toList()) {
if (!pkgPart.isEmpty()) {
pkgDir = new File(pkgDir, pkgPart);
}
}
pkgDir.mkdirs();
File scriptFileToCompile = new File(pkgDir, oldPack.getClassPath().className + ".as");
File compiledSwfFile = new File(pkgDir, "out.swf");
File swcFile = new File(pkgDir, "out.swc");
//Make copy without the old script
SWF swfCopy = recompileSWF(swf);
List<ScriptPack> copyPacks = swfCopy.getAS3Packs();
for (ScriptPack sp : copyPacks) {
if (sp.getClassPath().equals(oldPack.getClassPath())) {
sp.abc.script_info.get(sp.scriptIndex).delete(sp.abc, true);
((Tag) sp.abc.parentTag).setModified(true);
break;
}
}
//remove all subclasses
for (ScriptPack sp : copyPacks) {
DottedChain dc = sp.getPathPackage().add(sp.getPathScriptName());
if (isParentDeleted(sp.abc, sp.allABCs, dc)) {
sp.abc.script_info.get(sp.scriptIndex).delete(sp.abc, true);
}
}
SwfToSwcExporter swcExport = new SwfToSwcExporter();
swcExport.exportSwf(swfCopy, swcFile, true);
Helper.writeFile(scriptFileToCompile.getAbsolutePath(), txt.getBytes("UTF-8"));
mxmlc("-include-inheritance-dependencies-only", "-warnings=false", "-library-path", swcFile.getAbsolutePath(), "-source-path", tempDir.getAbsolutePath(), "-output", compiledSwfFile.getAbsolutePath(), "-debug=true", scriptFileToCompile.getAbsolutePath());
try (FileInputStream fis = new FileInputStream(compiledSwfFile)) {
SWF newSWF = new SWF(fis, false, false);
List<ABCContainerTag> newTags = newSWF.getAbcList();
ScriptInfo oldScriptInfo = oldPack.abc.script_info.get(oldPack.scriptIndex);
if (oldPack.isSimple) {
oldScriptInfo.delete(oldPack.abc, true);
} else {
//NOO
}
int oldTagIndex = swf.getTags().indexOf((Tag) oldPack.abc.parentTag);
if (oldPack.abc.script_info.size() == 1) {
swf.removeTag(oldTagIndex);
}
for (ABCContainerTag act : newTags) {
((Tag) act).setSwf(swf);
swf.addTag(oldTagIndex + 1, (Tag) act);
((Tag) act).setModified(true);
}
((Tag) oldPack.abc.parentTag).setModified(true);
swf.clearAbcListCache();
swf.clearScriptCache();
}
} finally {
if (tempDir != null && tempDir.exists()) {
//deleteFolder(tempDir);
}
}
}
}
@@ -0,0 +1,15 @@
package com.jpexs.decompiler.flash.flexsdk;
public class MxmlcException extends Exception {
private String mxmlcErrorOutput;
public MxmlcException(String mxmlcErrorOutput) {
this.mxmlcErrorOutput = mxmlcErrorOutput;
}
public String getMxmlcErrorOutput() {
return mxmlcErrorOutput;
}
}
@@ -0,0 +1,54 @@
package com.jpexs.decompiler.flash.flexsdk;
import com.jpexs.helpers.Helper;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.logging.Level;
import java.util.logging.Logger;
public class MxmlcRunner {
private String flexSdkPath;
public MxmlcRunner(String flexSdkPath) {
this.flexSdkPath = flexSdkPath;
}
public String getMxmlcPath() {
boolean isWin = System.getProperty("os.name").toLowerCase().contains("win");
return flexSdkPath + File.separator + "bin" + File.separator + "mxmlc" + (isWin ? ".exe" : "");
}
public void mxmlc(String... arguments) throws MxmlcException, InterruptedException, IOException {
String runArgs[] = new String[arguments.length + 1];
runArgs[0] = getMxmlcPath();
System.arraycopy(arguments, 0, runArgs, 1, arguments.length);
System.out.println("" + String.join(" ", runArgs));
Process proc = null;
try {
proc = Runtime.getRuntime().exec(runArgs);
Helper.readStream(proc.getInputStream());
String errstring = "";
try {
errstring = new String(Helper.readStream(proc.getErrorStream()), "UTF-8");
} catch (UnsupportedEncodingException ex) {
//should not happen
}
proc.waitFor();
int exitValue = proc.exitValue();
if (exitValue > 0) {
throw new MxmlcException(errstring);
}
} finally {
if (proc != null) {
try {
proc.destroy();
} catch (Exception ex2) {
//ignore
}
}
}
}
}