mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-09-25 12:30:52 +00:00
merge
This commit is contained in:
@@ -75,6 +75,7 @@ import com.jpexs.decompiler.flash.tags.base.BoundedTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterIdTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.Container;
|
||||
import com.jpexs.decompiler.flash.tags.base.ContainerItem;
|
||||
import com.jpexs.decompiler.flash.tags.base.DrawableTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ImageTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag;
|
||||
@@ -610,7 +611,7 @@ public class SWF {
|
||||
|
||||
public List<File> exportActionScript2(AbortRetryIgnoreHandler handler, String outdir, boolean isPcode, boolean parallel, EventListener evl) throws IOException {
|
||||
List<File> ret = new ArrayList<>();
|
||||
List<Object> list2 = new ArrayList<>();
|
||||
List<ContainerItem> list2 = new ArrayList<>();
|
||||
list2.addAll(tags);
|
||||
List<TagNode> list = createASTagList(list2, null);
|
||||
|
||||
@@ -684,13 +685,13 @@ public class SWF {
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static List<TagNode> createASTagList(List<Object> list, Object parent) {
|
||||
public static List<TagNode> createASTagList(List<? extends ContainerItem> list, Object parent) {
|
||||
List<TagNode> ret = new ArrayList<>();
|
||||
int frame = 1;
|
||||
List<TagNode> frames = new ArrayList<>();
|
||||
|
||||
List<ExportAssetsTag> exportAssetsTags = new ArrayList<>();
|
||||
for (Object t : list) {
|
||||
for (ContainerItem t : list) {
|
||||
if (t instanceof ExportAssetsTag) {
|
||||
exportAssetsTags.add((ExportAssetsTag) t);
|
||||
}
|
||||
@@ -722,7 +723,7 @@ public class SWF {
|
||||
if (((Container) t).getItemCount() > 0) {
|
||||
|
||||
TagNode tti = new TagNode(t);
|
||||
List<Object> subItems = ((Container) t).getSubItems();
|
||||
List<ContainerItem> subItems = ((Container) t).getSubItems();
|
||||
|
||||
tti.subItems = createASTagList(subItems, t);
|
||||
addNode = tti;
|
||||
@@ -870,9 +871,9 @@ public class SWF {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void populateSoundStreamBlocks(List<Object> tags, Tag head, List<SoundStreamBlockTag> output) {
|
||||
public static void populateSoundStreamBlocks(List<? extends ContainerItem> tags, Tag head, List<SoundStreamBlockTag> output) {
|
||||
boolean found = false;
|
||||
for (Object t : tags) {
|
||||
for (ContainerItem t : tags) {
|
||||
if (t == head) {
|
||||
found = true;
|
||||
continue;
|
||||
@@ -892,8 +893,8 @@ public class SWF {
|
||||
}
|
||||
}
|
||||
|
||||
public void populateVideoFrames(int streamId, List<Object> tags, HashMap<Integer, VideoFrameTag> output) {
|
||||
for (Object t : tags) {
|
||||
public void populateVideoFrames(int streamId, List<? extends ContainerItem> tags, HashMap<Integer, VideoFrameTag> output) {
|
||||
for (ContainerItem t : tags) {
|
||||
if (t instanceof VideoFrameTag) {
|
||||
output.put(((VideoFrameTag) t).frameNum, (VideoFrameTag) t);
|
||||
}
|
||||
@@ -934,8 +935,7 @@ public class SWF {
|
||||
if (t instanceof SoundStreamHeadTypeTag) {
|
||||
SoundStreamHeadTypeTag shead = (SoundStreamHeadTypeTag) t;
|
||||
List<SoundStreamBlockTag> blocks = new ArrayList<>();
|
||||
List<Object> objs = new ArrayList<Object>(this.tags);
|
||||
populateSoundStreamBlocks(objs, t, blocks);
|
||||
populateSoundStreamBlocks(this.tags, t, blocks);
|
||||
if ((shead.getSoundFormat() == DefineSoundTag.FORMAT_ADPCM) && wave) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
for (int b = 0; b < blocks.size(); b++) {
|
||||
@@ -1087,7 +1087,8 @@ public class SWF {
|
||||
if (t instanceof SoundStreamHeadTypeTag) {
|
||||
final SoundStreamHeadTypeTag shead = (SoundStreamHeadTypeTag) t;
|
||||
final List<SoundStreamBlockTag> blocks = new ArrayList<>();
|
||||
List<Object> objs = new ArrayList<Object>(this.tags);
|
||||
List<ContainerItem> objs = new ArrayList<>();
|
||||
objs.addAll(this.tags);
|
||||
populateSoundStreamBlocks(objs, t, blocks);
|
||||
if ((shead.getSoundFormat() == DefineSoundTag.FORMAT_ADPCM) && wave) {
|
||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
@@ -1157,8 +1158,7 @@ public class SWF {
|
||||
|
||||
public byte[] exportMovie(DefineVideoStreamTag videoStream) throws IOException {
|
||||
HashMap<Integer, VideoFrameTag> frames = new HashMap<>();
|
||||
List<Object> os = new ArrayList<Object>(this.tags);
|
||||
populateVideoFrames(videoStream.characterID, os, frames);
|
||||
populateVideoFrames(videoStream.characterID, this.tags, frames);
|
||||
if (frames.isEmpty()) {
|
||||
return new byte[0];
|
||||
}
|
||||
@@ -1723,9 +1723,9 @@ public class SWF {
|
||||
}
|
||||
private HashMap<ASMSource, List<Action>> actionsMap = new HashMap<>();
|
||||
|
||||
private void getVariables(List<Object> objs, String path) {
|
||||
private void getVariables(List<ContainerItem> objs, String path) {
|
||||
List<String> processed = new ArrayList<>();
|
||||
for (Object o : objs) {
|
||||
for (ContainerItem o : objs) {
|
||||
if (o instanceof ASMSource) {
|
||||
String infPath = path + "/" + o.toString();
|
||||
int pos = 1;
|
||||
@@ -1893,7 +1893,7 @@ public class SWF {
|
||||
allVariableNames = new ArrayList<>();
|
||||
allStrings = new HashMap<>();
|
||||
|
||||
List<Object> objs = new ArrayList<>();
|
||||
List<ContainerItem> objs = new ArrayList<>();
|
||||
int ret = 0;
|
||||
objs.addAll(tags);
|
||||
getVariables(objs, "");
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.action.ActionGraphSource;
|
||||
import com.jpexs.decompiler.flash.action.ActionListReader;
|
||||
import com.jpexs.decompiler.flash.action.StoreTypeAction;
|
||||
import com.jpexs.decompiler.flash.action.model.ConstantPool;
|
||||
import com.jpexs.decompiler.flash.action.model.DirectValueActionItem;
|
||||
@@ -31,8 +31,8 @@ import com.jpexs.decompiler.flash.action.swf6.*;
|
||||
import com.jpexs.decompiler.flash.action.swf7.*;
|
||||
import com.jpexs.decompiler.flash.ecma.EcmaScript;
|
||||
import com.jpexs.decompiler.flash.ecma.Null;
|
||||
import com.jpexs.decompiler.flash.helpers.Highlighting;
|
||||
import com.jpexs.decompiler.flash.tags.*;
|
||||
import com.jpexs.decompiler.flash.tags.base.ASMSource;
|
||||
import com.jpexs.decompiler.flash.types.*;
|
||||
import com.jpexs.decompiler.flash.types.filters.BEVELFILTER;
|
||||
import com.jpexs.decompiler.flash.types.filters.BLURFILTER;
|
||||
@@ -63,9 +63,11 @@ import java.io.InputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Queue;
|
||||
import java.util.Scanner;
|
||||
import java.util.Stack;
|
||||
import java.util.concurrent.Callable;
|
||||
@@ -241,8 +243,8 @@ public class SWFInputStream extends InputStream {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
int r;
|
||||
while (true) {
|
||||
r = read();
|
||||
if (r <= 0) {
|
||||
r = readEx();
|
||||
if (r == 0) {
|
||||
return new String(baos.toByteArray(), "utf8");
|
||||
}
|
||||
baos.write(r);
|
||||
@@ -539,461 +541,11 @@ public class SWFInputStream extends InputStream {
|
||||
|
||||
public List<Action> readActionList(List<DisassemblyListener> listeners, long containerSWFOffset, String path) throws IOException {
|
||||
ReReadableInputStream rri = new ReReadableInputStream(this);
|
||||
return readActionList(listeners, containerSWFOffset, rri, version, 0, -1, path);
|
||||
return ActionListReader.readActionList(listeners, containerSWFOffset, rri, version, 0, -1, path);
|
||||
}
|
||||
|
||||
public List<Action> readActionList(List<DisassemblyListener> listeners, long containerSWFOffset, ReReadableInputStream rri, int maxlen, String path) throws IOException {
|
||||
return readActionList(listeners, containerSWFOffset, rri, version, rri.getPos(), rri.getPos() + maxlen, path);
|
||||
}
|
||||
|
||||
private static List<Object> prepareLocalBranch(List<Object> localData) {
|
||||
@SuppressWarnings("unchecked")
|
||||
HashMap<Integer, String> regNames = (HashMap<Integer, String>) localData.get(0);
|
||||
@SuppressWarnings("unchecked")
|
||||
HashMap<String, GraphTargetItem> variables = (HashMap<String, GraphTargetItem>) localData.get(1);
|
||||
@SuppressWarnings("unchecked")
|
||||
HashMap<String, GraphTargetItem> functions = (HashMap<String, GraphTargetItem>) localData.get(2);
|
||||
List<Object> ret = new ArrayList<>();
|
||||
ret.add(new HashMap<Integer, String>(regNames));
|
||||
ret.add(new HashMap<String, GraphTargetItem>(variables));
|
||||
ret.add(new HashMap<String, GraphTargetItem>(functions));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads list of actions from the stream. Reading ends with
|
||||
* ActionEndFlag(=0) or end of the stream.
|
||||
*
|
||||
* @param listeners
|
||||
* @param address
|
||||
* @param ip
|
||||
* @param rri
|
||||
* @param version
|
||||
* @param containerSWFOffset
|
||||
* @param endip
|
||||
* @param path
|
||||
* @return List of actions
|
||||
* @throws IOException
|
||||
*/
|
||||
public static List<Action> readActionList(List<DisassemblyListener> listeners, long containerSWFOffset, ReReadableInputStream rri, int version, int ip, int endip, String path) throws IOException {
|
||||
List<Action> retdups = new ArrayList<>();
|
||||
ConstantPool cpool = new ConstantPool();
|
||||
|
||||
Stack<GraphTargetItem> stack = new Stack<>();
|
||||
|
||||
List<Object> localData = Helper.toList(new HashMap<Integer, String>(), new HashMap<String, GraphTargetItem>(), new HashMap<String, GraphTargetItem>());
|
||||
|
||||
|
||||
SWFInputStream sis = new SWFInputStream(rri, version);
|
||||
boolean goesPrev = false;
|
||||
int method = 1;
|
||||
/*try {
|
||||
goesPrev = readActionListAtPos(false, localData, stack, cpool, sis, rri, ip, retdups, ip);
|
||||
} catch (Exception ex) {
|
||||
method = 2;
|
||||
goesPrev = readActionListAtPos(true, localData, stack, cpool, sis, rri, ip, retdups, ip);
|
||||
}*/
|
||||
goesPrev = readActionListAtPos(listeners, new ArrayList<GraphTargetItem>(), new HashMap<Long, List<GraphSourceItemContainer>>(), containerSWFOffset, localData, stack, cpool, sis, rri, ip, retdups, ip, endip, path, new HashMap<Integer, Integer>(), false, new HashMap<Integer, HashMap<String, GraphTargetItem>>());
|
||||
|
||||
if (goesPrev) {
|
||||
} else {
|
||||
if (!retdups.isEmpty()) {
|
||||
for (int i = 0; i < ip; i++) {
|
||||
retdups.remove(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
List<Action> ret = new ArrayList<>();
|
||||
Action last = null;
|
||||
for (Action a : retdups) {
|
||||
if (a != last) {
|
||||
ret.add(a);
|
||||
}
|
||||
last = a;
|
||||
}
|
||||
for (int i = 0; i < retdups.size(); i++) {
|
||||
Action a = retdups.get(i);
|
||||
if (a instanceof ActionEnd) {
|
||||
if (i < retdups.size() - 1) {
|
||||
ActionJump jmp = new ActionJump(0);
|
||||
jmp.setJumpOffset(retdups.size() - i - jmp.getBytes(version).length);
|
||||
a.replaceWith = jmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//List<ConstantPool> pools;
|
||||
if (Configuration.getConfig("removeNops", true)) {
|
||||
ret = Action.removeNops(0, ret, version, 0, path);
|
||||
}
|
||||
//pools = getConstantPool(listeners, new ActionGraphSource(ret, version, new HashMap<Integer, String>(), new HashMap<String, GraphTargetItem>(), new HashMap<String, GraphTargetItem>()), 0, version, path);
|
||||
|
||||
/*if (pools.size() == 1) {
|
||||
Action.setConstantPool(ret, pools.get(0));
|
||||
}*/
|
||||
if (goesPrev && (!DEOBFUSCATION_ALL_CODE_IN_PREVIOUS_TAG)) {
|
||||
ActionJump aj = new ActionJump(ip);
|
||||
int skip = aj.getBytes(version).length;
|
||||
for (GraphSourceItem s : ret) {
|
||||
|
||||
if (s instanceof Action) {
|
||||
Action a = (Action) s;
|
||||
a.setAddress(a.getAddress() + skip, version);
|
||||
}
|
||||
}
|
||||
ret.add(0, aj);
|
||||
}
|
||||
String s = null;
|
||||
List<Action> reta = new ArrayList<>();
|
||||
for (Object o : ret) {
|
||||
if (o instanceof Action) {
|
||||
reta.add((Action) o);
|
||||
}
|
||||
}
|
||||
return reta;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static boolean readActionListAtPos(List<DisassemblyListener> listeners, List<GraphTargetItem> output, HashMap<Long, List<GraphSourceItemContainer>> containers, long containerSWFOffset, List<Object> localData, Stack<GraphTargetItem> stack, ConstantPool cpool, SWFInputStream sis, ReReadableInputStream rri, int ip, List<Action> ret, int startIp, int endip, String path, Map<Integer, Integer> visited, boolean indeterminate, Map<Integer, HashMap<String, GraphTargetItem>> decisionStates) throws IOException {
|
||||
boolean debugMode = false;
|
||||
boolean decideBranch = false;
|
||||
|
||||
boolean deobfuscate = Configuration.getConfig("autoDeobfuscate", true);
|
||||
boolean retv = false;
|
||||
rri.setPos(ip);
|
||||
Action a;
|
||||
long filePos = rri.getPos();
|
||||
Scanner sc = new Scanner(System.in, "utf-8");
|
||||
int prevIp = ip;
|
||||
loopip:
|
||||
while (((endip == -1) || (endip > ip)) && (a = sis.readAction(rri, cpool)) != null) {
|
||||
if (!visited.containsKey(ip)) {
|
||||
visited.put(ip, 0);
|
||||
}
|
||||
int curVisited = visited.get(ip);
|
||||
curVisited++;
|
||||
visited.put(ip, curVisited);
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
listeners.get(i).progress("Reading", rri.getCount(), rri.length());
|
||||
}
|
||||
if ((ip < ret.size()) && (!(ret.get(ip) instanceof ActionNop))) {
|
||||
a = ret.get(ip);
|
||||
if (a.getAddress() != ip) {
|
||||
Logger.getLogger(SWFInputStream.class.getName()).log(Level.SEVERE, "Jump to the middle of the instruction ip " + ip + " ins " + a.getASMSource(new ArrayList<GraphSourceItem>(), new ArrayList<Long>(), new ArrayList<String>(), SWF.DEFAULT_VERSION, false));
|
||||
}
|
||||
}
|
||||
a.containerSWFOffset = containerSWFOffset;
|
||||
a.setAddress(prevIp, SWF.DEFAULT_VERSION, false);
|
||||
int info = a.actionLength + 1 + ((a.actionCode > 0x80) ? 2 : 0);
|
||||
byte b[] = a.getBytes(sis.version);
|
||||
int infoCorrect = info;
|
||||
/*if (b.length != infoCorrect) {
|
||||
throw new RuntimeException("Wrong length "+a.toString()+" info:"+infoCorrect+" actual:"+b.length+" datalen:"+(infoCorrect-info));
|
||||
}*/
|
||||
//int actual = a.getBytes(sis.version).length;
|
||||
if ((!(a instanceof ActionStore)) && (!(a instanceof GraphSourceItemContainer))) {
|
||||
int change = info - (rri.getPos() - ip);
|
||||
if (change > 0) {
|
||||
a.afterInsert = new ActionJump(change);
|
||||
}
|
||||
} else {
|
||||
info = rri.getPos() - ip;
|
||||
}
|
||||
if (ip < startIp) {
|
||||
retv = true;
|
||||
}
|
||||
|
||||
|
||||
/*if(a instanceof ActionConstantPool){
|
||||
throw new IllegalArgumentException("CP found");
|
||||
} */
|
||||
if (a instanceof ActionPush) {
|
||||
if (cpool != null) {
|
||||
((ActionPush) a).constantPool = cpool.constants;
|
||||
cpool.count++;
|
||||
}
|
||||
}
|
||||
if (a instanceof ActionDefineFunction) {
|
||||
if (cpool != null) {
|
||||
//((ActionDefineFunction) a).setConstantPool(cpool.constants);
|
||||
cpool.count++;
|
||||
}
|
||||
}
|
||||
if (a instanceof ActionDefineFunction2) {
|
||||
if (cpool != null) {
|
||||
//((ActionDefineFunction2) a).setConstantPool(cpool.constants);
|
||||
cpool.count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (debugMode) {
|
||||
//if(a instanceof ActionIf){
|
||||
String atos = a.getASMSource(new ArrayList<GraphSourceItem>(), new ArrayList<Long>(), cpool.constants, sis.version, false);
|
||||
if (a instanceof GraphSourceItemContainer) {
|
||||
atos = a.toString();
|
||||
}
|
||||
System.err.println("readActionListAtPos ip: " + (ip - startIp) + " (0x" + Helper.formatAddress(ip - startIp) + ") " + " action(len " + a.actionLength + "): " + atos + (a.isIgnored() ? " (ignored)" : "") + " stack:" + Helper.stackToString(stack, Helper.toList(cpool)) + " " + Helper.byteArrToString(a.getBytes(SWF.DEFAULT_VERSION)));
|
||||
@SuppressWarnings("unchecked")
|
||||
HashMap<String, GraphTargetItem> vars = (HashMap<String, GraphTargetItem>) localData.get(1);
|
||||
System.err.print("variables: ");
|
||||
for (Entry<String, GraphTargetItem> v : vars.entrySet()) {
|
||||
System.err.print("'" + v + "' = " + v.getValue().toString(false, cpool) + ", ");
|
||||
}
|
||||
System.err.println();
|
||||
String add = "";
|
||||
if (a instanceof ActionIf) {
|
||||
add = " change: " + ((ActionIf) a).getJumpOffset();
|
||||
}
|
||||
if (a instanceof ActionJump) {
|
||||
add = " change: " + ((ActionJump) a).getJumpOffset();
|
||||
}
|
||||
System.err.println(add);
|
||||
}
|
||||
long newFilePos = rri.getPos();
|
||||
long actionLen = newFilePos - filePos;
|
||||
|
||||
ensureCapacity(ret, ip);
|
||||
int newip = -1;
|
||||
|
||||
if (a instanceof ActionConstantPool) {
|
||||
if (cpool == null) {
|
||||
cpool = new ConstantPool();
|
||||
}
|
||||
cpool.setNew(((ActionConstantPool) a).constantPool);
|
||||
}
|
||||
ActionIf aif = null;
|
||||
boolean goaif = false;
|
||||
if (!a.isIgnored()) {
|
||||
String varname = null;
|
||||
if (a instanceof StoreTypeAction) {
|
||||
StoreTypeAction sta = (StoreTypeAction) a;
|
||||
varname = sta.getVariableName(stack, cpool);
|
||||
}
|
||||
|
||||
try {
|
||||
if (a instanceof ActionIf) {
|
||||
aif = (ActionIf) a;
|
||||
|
||||
GraphTargetItem top = null;
|
||||
if (deobfuscate) {
|
||||
top = stack.pop();
|
||||
}
|
||||
int nip = rri.getPos() + aif.getJumpOffset();
|
||||
|
||||
if (decideBranch) {
|
||||
System.out.print("newip " + nip + ", ");
|
||||
System.out.print("Action: jump(j),ignore(i),compute(c)?");
|
||||
String next = sc.next();
|
||||
if (next.equals("j")) {
|
||||
newip = rri.getPos() + aif.getJumpOffset();
|
||||
rri.setPos(newip);
|
||||
|
||||
} else if (next.equals("i")) {
|
||||
} else if (next.equals("c")) {
|
||||
goaif = true;
|
||||
}
|
||||
} else if (deobfuscate && top.isCompileTime() && (!top.hasSideEffect())) {
|
||||
((ActionIf) a).compileTime = true;
|
||||
if (debugMode) {
|
||||
System.err.print("is compiletime -> ");
|
||||
}
|
||||
if (EcmaScript.toBoolean(top.getResult())) {
|
||||
newip = rri.getPos() + aif.getJumpOffset();
|
||||
aif.jumpUsed = true;
|
||||
if (aif.ignoreUsed) {
|
||||
aif.compileTime = false;
|
||||
}
|
||||
if (debugMode) {
|
||||
System.err.println("jump");
|
||||
}
|
||||
} else {
|
||||
aif.ignoreUsed = true;
|
||||
if (aif.jumpUsed) {
|
||||
aif.compileTime = false;
|
||||
}
|
||||
if (debugMode) {
|
||||
System.err.println("ignore");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (debugMode) {
|
||||
System.err.println("goaif");
|
||||
}
|
||||
//throw new RuntimeException("goaif");
|
||||
goaif = true;
|
||||
}
|
||||
} else if (a instanceof ActionJump) {
|
||||
newip = rri.getPos() + ((ActionJump) a).getJumpOffset();
|
||||
//if(newip>=0){
|
||||
//rri.setPos(newip);
|
||||
//}
|
||||
} else if (!(a instanceof GraphSourceItemContainer)) {
|
||||
if (deobfuscate) {
|
||||
//return in for..in, TODO:Handle this better way
|
||||
if (((a instanceof ActionEquals) || (a instanceof ActionEquals2)) && (stack.size() == 1) && (stack.peek() instanceof DirectValueActionItem)) {
|
||||
stack.push(new DirectValueActionItem(null, 0, new Null(), new ArrayList<String>()));
|
||||
}
|
||||
if ((a instanceof ActionStoreRegister) && stack.isEmpty()) {
|
||||
stack.push(new DirectValueActionItem(null, 0, new Null(), new ArrayList<String>()));
|
||||
}
|
||||
a.translate(localData, stack, output, Graph.SOP_USE_STATIC/*Graph.SOP_SKIP_STATIC*/, path);
|
||||
}
|
||||
}
|
||||
} catch (RuntimeException ex) {
|
||||
/*if (!enableVariables) {
|
||||
throw ex;
|
||||
}*/
|
||||
log.log(Level.SEVERE, "Disassembly exception", ex);
|
||||
break;
|
||||
}
|
||||
|
||||
HashMap<String, GraphTargetItem> vars = (HashMap<String, GraphTargetItem>) localData.get(1);
|
||||
if (varname != null) {
|
||||
GraphTargetItem varval = vars.get(varname);
|
||||
if (varval != null && varval.isCompileTime() && indeterminate) {
|
||||
vars.put(varname, new NotCompileTimeItem(null, varval));
|
||||
}
|
||||
}
|
||||
}
|
||||
int nopos = -1;
|
||||
for (int i = 0; i < actionLen; i++) {
|
||||
ensureCapacity(ret, ip + i);
|
||||
if (a instanceof ActionNop) {
|
||||
int prevPos = (int) a.getAddress();
|
||||
a = new ActionNop();
|
||||
a.setAddress(prevPos, SWF.DEFAULT_VERSION);
|
||||
nopos++;
|
||||
if (nopos > 0) {
|
||||
a.setAddress(a.getAddress() + 1, SWF.DEFAULT_VERSION);
|
||||
}
|
||||
|
||||
}
|
||||
ret.set(ip + i, a);
|
||||
}
|
||||
|
||||
if (a instanceof GraphSourceItemContainer) {
|
||||
GraphSourceItemContainer cnt = (GraphSourceItemContainer) a;
|
||||
if (a instanceof Action) {
|
||||
long endAddr = a.getAddress() + cnt.getHeaderSize();
|
||||
/*if(!containers.containsKey(endAddr)){
|
||||
containers.put(endAddr, new ArrayList<ActionContainer>());
|
||||
}
|
||||
containers.get(endAddr).add((ActionContainer)a);
|
||||
*/
|
||||
String cntName = cnt.getName();
|
||||
List<List<GraphTargetItem>> output2s = new ArrayList<>();
|
||||
for (long size : cnt.getContainerSizes()) {
|
||||
if (size == 0) {
|
||||
output2s.add(new ArrayList<GraphTargetItem>());
|
||||
continue;
|
||||
}
|
||||
List<Object> localData2;
|
||||
List<GraphTargetItem> output2 = new ArrayList<>();
|
||||
if ((cnt instanceof ActionDefineFunction) || (cnt instanceof ActionDefineFunction2)) {
|
||||
localData2 = Helper.toList(new HashMap<Integer, String>(), new HashMap<String, GraphTargetItem>(), new HashMap<String, GraphTargetItem>());
|
||||
} else {
|
||||
localData2 = localData;
|
||||
}
|
||||
readActionListAtPos(listeners, output2, containers, containerSWFOffset, localData2, new Stack<GraphTargetItem>(), cpool, sis, rri, (int) endAddr, ret, startIp, (int) (endAddr + size), path + (cntName == null ? "" : "/" + cntName), visited, indeterminate, decisionStates);
|
||||
output2s.add(output2);
|
||||
endAddr += size;
|
||||
}
|
||||
if (deobfuscate) {
|
||||
cnt.translateContainer(output2s, stack, output, (HashMap<Integer, String>) localData.get(0), (HashMap<String, GraphTargetItem>) localData.get(1), (HashMap<String, GraphTargetItem>) localData.get(2));
|
||||
}
|
||||
ip = (int) endAddr;
|
||||
prevIp = ip;
|
||||
rri.setPos(ip);
|
||||
filePos = rri.getPos();
|
||||
continue;
|
||||
}
|
||||
//infoCorrect += ((ActionContainer) a).getDataLength();
|
||||
}
|
||||
|
||||
if (a instanceof ActionEnd) {
|
||||
break;
|
||||
}
|
||||
if (newip > -1) {
|
||||
ip = newip;
|
||||
} else {
|
||||
ip = ip + info; //(int) actionLen;
|
||||
}
|
||||
rri.setPos(ip);
|
||||
filePos = rri.getPos();
|
||||
if (goaif) {
|
||||
aif.ignoreUsed = true;
|
||||
aif.jumpUsed = true;
|
||||
indeterminate = true;
|
||||
|
||||
HashMap<String, GraphTargetItem> vars = (HashMap<String, GraphTargetItem>) localData.get(1);
|
||||
boolean stateChanged = false;
|
||||
if (decisionStates.containsKey(ip)) {
|
||||
HashMap<String, GraphTargetItem> oldstate = decisionStates.get(ip);
|
||||
if (oldstate.size() != vars.size()) {
|
||||
stateChanged = true;
|
||||
} else {
|
||||
for (String k : vars.keySet()) {
|
||||
if (!oldstate.containsKey(k)) {
|
||||
stateChanged = true;
|
||||
break;
|
||||
}
|
||||
if (!vars.get(k).isCompileTime() && oldstate.get(k).isCompileTime()) {
|
||||
stateChanged = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
HashMap<String, GraphTargetItem> curstate = new HashMap<>();
|
||||
curstate.putAll(vars);
|
||||
decisionStates.put(ip, curstate);
|
||||
|
||||
if ((!stateChanged) && curVisited > 1) {
|
||||
List<Integer> branches = new ArrayList<>();
|
||||
branches.add(rri.getPos() + aif.getJumpOffset());
|
||||
branches.add(rri.getPos());
|
||||
for (int br : branches) {
|
||||
int visc = 0;
|
||||
if (visited.containsKey(br)) {
|
||||
visc = visited.get(br);
|
||||
}
|
||||
if (visc == 0) {//<curVisited){
|
||||
ip = br;
|
||||
prevIp = ip;
|
||||
rri.setPos(br);
|
||||
filePos = rri.getPos();
|
||||
continue loopip;
|
||||
}
|
||||
}
|
||||
break loopip;
|
||||
}
|
||||
|
||||
int oldPos = rri.getPos();
|
||||
@SuppressWarnings("unchecked")
|
||||
Stack<GraphTargetItem> substack = (Stack<GraphTargetItem>) stack.clone();
|
||||
if (readActionListAtPos(listeners, output, containers, containerSWFOffset, prepareLocalBranch(localData), substack, cpool, sis, rri, rri.getPos() + aif.getJumpOffset(), ret, startIp, endip, path, visited, indeterminate, decisionStates)) {
|
||||
retv = true;
|
||||
}
|
||||
rri.setPos(oldPos);
|
||||
}
|
||||
prevIp = ip;
|
||||
if (a.isExit()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (DisassemblyListener listener : listeners) {
|
||||
listener.progress("Reading", rri.getCount(), rri.length());
|
||||
}
|
||||
return retv;
|
||||
}
|
||||
|
||||
private static void ensureCapacity(List<Action> ret, int index) {
|
||||
int pos = ret.size();
|
||||
while (ret.size() <= index) {
|
||||
Action a = new ActionNop();
|
||||
a.setAddress(pos++, SWF.DEFAULT_VERSION);
|
||||
ret.add(a);
|
||||
}
|
||||
return ActionListReader.readActionList(listeners, containerSWFOffset, rri, version, rri.getPos(), rri.getPos() + maxlen, path);
|
||||
}
|
||||
|
||||
private static void dumpTag(PrintStream out, int version, Tag tag, int level) {
|
||||
@@ -1076,7 +628,7 @@ public class SWFInputStream extends InputStream {
|
||||
|
||||
/**
|
||||
* Reads list of tags from the stream. Reading ends with End tag(=0) or end
|
||||
* of the stream. Optinally can skip AS1/2 tags when file is AS3
|
||||
* of the stream. Optionally can skip AS1/2 tags when file is AS3
|
||||
*
|
||||
* @param swf
|
||||
* @param level
|
||||
@@ -1529,234 +1081,234 @@ public class SWFInputStream extends InputStream {
|
||||
|
||||
try {
|
||||
actionCode = readUI8();
|
||||
} catch (EndOfStreamException eos) {
|
||||
if (actionCode == 0) {
|
||||
return new ActionEnd();
|
||||
}
|
||||
if (actionCode == -1) {
|
||||
return null;
|
||||
}
|
||||
int actionLength = 0;
|
||||
if (actionCode >= 0x80) {
|
||||
actionLength = readUI16();
|
||||
}
|
||||
switch (actionCode) {
|
||||
//SWF3 Actions
|
||||
case 0x81:
|
||||
return new ActionGotoFrame(actionLength, this);
|
||||
case 0x83:
|
||||
return new ActionGetURL(actionLength, this, version);
|
||||
case 0x04:
|
||||
return new ActionNextFrame();
|
||||
case 0x05:
|
||||
return new ActionPrevFrame();
|
||||
case 0x06:
|
||||
return new ActionPlay();
|
||||
case 0x07:
|
||||
return new ActionStop();
|
||||
case 0x08:
|
||||
return new ActionToggleQuality();
|
||||
case 0x09:
|
||||
return new ActionStopSounds();
|
||||
case 0x8A:
|
||||
return new ActionWaitForFrame(actionLength, this, cpool);
|
||||
case 0x8B:
|
||||
return new ActionSetTarget(actionLength, this, version);
|
||||
case 0x8C:
|
||||
return new ActionGoToLabel(actionLength, this, version);
|
||||
//SWF4 Actions
|
||||
case 0x96:
|
||||
return new ActionPush(actionLength, this, version);
|
||||
case 0x17:
|
||||
return new ActionPop();
|
||||
case 0x0A:
|
||||
return new ActionAdd();
|
||||
case 0x0B:
|
||||
return new ActionSubtract();
|
||||
case 0x0C:
|
||||
return new ActionMultiply();
|
||||
case 0x0D:
|
||||
return new ActionDivide();
|
||||
case 0x0E:
|
||||
return new ActionEquals();
|
||||
case 0x0F:
|
||||
return new ActionLess();
|
||||
case 0x10:
|
||||
return new ActionAnd();
|
||||
case 0x11:
|
||||
return new ActionOr();
|
||||
case 0x12:
|
||||
return new ActionNot();
|
||||
case 0x13:
|
||||
return new ActionStringEquals();
|
||||
case 0x14:
|
||||
return new ActionStringLength();
|
||||
case 0x21:
|
||||
return new ActionStringAdd();
|
||||
case 0x15:
|
||||
return new ActionStringExtract();
|
||||
case 0x29:
|
||||
return new ActionStringLess();
|
||||
case 0x31:
|
||||
return new ActionMBStringLength();
|
||||
case 0x35:
|
||||
return new ActionMBStringExtract();
|
||||
case 0x18:
|
||||
return new ActionToInteger();
|
||||
case 0x32:
|
||||
return new ActionCharToAscii();
|
||||
case 0x33:
|
||||
return new ActionAsciiToChar();
|
||||
case 0x36:
|
||||
return new ActionMBCharToAscii();
|
||||
case 0x37:
|
||||
return new ActionMBAsciiToChar();
|
||||
case 0x99:
|
||||
return new ActionJump(actionLength, this);
|
||||
case 0x9D:
|
||||
return new ActionIf(actionLength, this);
|
||||
case 0x9E:
|
||||
return new ActionCall(actionLength);
|
||||
case 0x1C:
|
||||
return new ActionGetVariable();
|
||||
case 0x1D:
|
||||
return new ActionSetVariable();
|
||||
case 0x9A:
|
||||
return new ActionGetURL2(actionLength, this);
|
||||
case 0x9F:
|
||||
return new ActionGotoFrame2(actionLength, this);
|
||||
case 0x20:
|
||||
return new ActionSetTarget2();
|
||||
case 0x22:
|
||||
return new ActionGetProperty();
|
||||
case 0x23:
|
||||
return new ActionSetProperty();
|
||||
case 0x24:
|
||||
return new ActionCloneSprite();
|
||||
case 0x25:
|
||||
return new ActionRemoveSprite();
|
||||
case 0x27:
|
||||
return new ActionStartDrag();
|
||||
case 0x28:
|
||||
return new ActionEndDrag();
|
||||
case 0x8D:
|
||||
return new ActionWaitForFrame2(actionLength, this, cpool);
|
||||
case 0x26:
|
||||
return new ActionTrace();
|
||||
case 0x34:
|
||||
return new ActionGetTime();
|
||||
case 0x30:
|
||||
return new ActionRandomNumber();
|
||||
//SWF5 Actions
|
||||
case 0x3D:
|
||||
return new ActionCallFunction();
|
||||
case 0x52:
|
||||
return new ActionCallMethod();
|
||||
case 0x88:
|
||||
return new ActionConstantPool(actionLength, this, version);
|
||||
case 0x9B:
|
||||
return new ActionDefineFunction(actionLength, this, rri, version);
|
||||
case 0x3C:
|
||||
return new ActionDefineLocal();
|
||||
case 0x41:
|
||||
return new ActionDefineLocal2();
|
||||
case 0x3A:
|
||||
return new ActionDelete();
|
||||
case 0x3B:
|
||||
return new ActionDelete2();
|
||||
case 0x46:
|
||||
return new ActionEnumerate();
|
||||
case 0x49:
|
||||
return new ActionEquals2();
|
||||
case 0x4E:
|
||||
return new ActionGetMember();
|
||||
case 0x42:
|
||||
return new ActionInitArray();
|
||||
case 0x43:
|
||||
return new ActionInitObject();
|
||||
case 0x53:
|
||||
return new ActionNewMethod();
|
||||
case 0x40:
|
||||
return new ActionNewObject();
|
||||
case 0x4F:
|
||||
return new ActionSetMember();
|
||||
case 0x45:
|
||||
return new ActionTargetPath();
|
||||
case 0x94:
|
||||
return new ActionWith(actionLength, this, rri, version);
|
||||
case 0x4A:
|
||||
return new ActionToNumber();
|
||||
case 0x4B:
|
||||
return new ActionToString();
|
||||
case 0x44:
|
||||
return new ActionTypeOf();
|
||||
case 0x47:
|
||||
return new ActionAdd2();
|
||||
case 0x48:
|
||||
return new ActionLess2();
|
||||
case 0x3F:
|
||||
return new ActionModulo();
|
||||
case 0x60:
|
||||
return new ActionBitAnd();
|
||||
case 0x63:
|
||||
return new ActionBitLShift();
|
||||
case 0x61:
|
||||
return new ActionBitOr();
|
||||
case 0x64:
|
||||
return new ActionBitRShift();
|
||||
case 0x65:
|
||||
return new ActionBitURShift();
|
||||
case 0x62:
|
||||
return new ActionBitXor();
|
||||
case 0x51:
|
||||
return new ActionDecrement();
|
||||
case 0x50:
|
||||
return new ActionIncrement();
|
||||
case 0x4C:
|
||||
return new ActionPushDuplicate();
|
||||
case 0x3E:
|
||||
return new ActionReturn();
|
||||
case 0x4D:
|
||||
return new ActionStackSwap();
|
||||
case 0x87:
|
||||
return new ActionStoreRegister(actionLength, this);
|
||||
//SWF6 Actions
|
||||
case 0x54:
|
||||
return new ActionInstanceOf();
|
||||
case 0x55:
|
||||
return new ActionEnumerate2();
|
||||
case 0x66:
|
||||
return new ActionStrictEquals();
|
||||
case 0x67:
|
||||
return new ActionGreater();
|
||||
case 0x68:
|
||||
return new ActionStringGreater();
|
||||
//SWF7 Actions
|
||||
case 0x8E:
|
||||
return new ActionDefineFunction2(actionLength, this, rri, version);
|
||||
case 0x69:
|
||||
return new ActionExtends();
|
||||
case 0x2B:
|
||||
return new ActionCastOp();
|
||||
case 0x2C:
|
||||
return new ActionImplementsOp();
|
||||
case 0x8F:
|
||||
return new ActionTry(actionLength, this, rri, version);
|
||||
case 0x2A:
|
||||
return new ActionThrow();
|
||||
default:
|
||||
/*if (actionLength > 0) {
|
||||
//skip(actionLength);
|
||||
}*/
|
||||
//throw new UnknownActionException(actionCode);
|
||||
Action r = new ActionNop();
|
||||
r.actionCode = actionCode;
|
||||
r.actionLength = actionLength;
|
||||
return r;
|
||||
//return new Action(actionCode, actionLength);
|
||||
}
|
||||
} catch (EndOfStreamException | ArrayIndexOutOfBoundsException eos) {
|
||||
return null;
|
||||
}
|
||||
if (actionCode == 0) {
|
||||
return new ActionEnd();
|
||||
}
|
||||
if (actionCode == -1) {
|
||||
return null;
|
||||
}
|
||||
int actionLength = 0;
|
||||
if (actionCode >= 0x80) {
|
||||
actionLength = readUI16();
|
||||
}
|
||||
switch (actionCode) {
|
||||
//SWF3 Actions
|
||||
case 0x81:
|
||||
return new ActionGotoFrame(this);
|
||||
case 0x83:
|
||||
return new ActionGetURL(actionLength, this, version);
|
||||
case 0x04:
|
||||
return new ActionNextFrame();
|
||||
case 0x05:
|
||||
return new ActionPrevFrame();
|
||||
case 0x06:
|
||||
return new ActionPlay();
|
||||
case 0x07:
|
||||
return new ActionStop();
|
||||
case 0x08:
|
||||
return new ActionToggleQuality();
|
||||
case 0x09:
|
||||
return new ActionStopSounds();
|
||||
case 0x8A:
|
||||
return new ActionWaitForFrame(this, cpool);
|
||||
case 0x8B:
|
||||
return new ActionSetTarget(actionLength, this, version);
|
||||
case 0x8C:
|
||||
return new ActionGoToLabel(actionLength, this, version);
|
||||
//SWF4 Actions
|
||||
case 0x96:
|
||||
return new ActionPush(actionLength, this, version);
|
||||
case 0x17:
|
||||
return new ActionPop();
|
||||
case 0x0A:
|
||||
return new ActionAdd();
|
||||
case 0x0B:
|
||||
return new ActionSubtract();
|
||||
case 0x0C:
|
||||
return new ActionMultiply();
|
||||
case 0x0D:
|
||||
return new ActionDivide();
|
||||
case 0x0E:
|
||||
return new ActionEquals();
|
||||
case 0x0F:
|
||||
return new ActionLess();
|
||||
case 0x10:
|
||||
return new ActionAnd();
|
||||
case 0x11:
|
||||
return new ActionOr();
|
||||
case 0x12:
|
||||
return new ActionNot();
|
||||
case 0x13:
|
||||
return new ActionStringEquals();
|
||||
case 0x14:
|
||||
return new ActionStringLength();
|
||||
case 0x21:
|
||||
return new ActionStringAdd();
|
||||
case 0x15:
|
||||
return new ActionStringExtract();
|
||||
case 0x29:
|
||||
return new ActionStringLess();
|
||||
case 0x31:
|
||||
return new ActionMBStringLength();
|
||||
case 0x35:
|
||||
return new ActionMBStringExtract();
|
||||
case 0x18:
|
||||
return new ActionToInteger();
|
||||
case 0x32:
|
||||
return new ActionCharToAscii();
|
||||
case 0x33:
|
||||
return new ActionAsciiToChar();
|
||||
case 0x36:
|
||||
return new ActionMBCharToAscii();
|
||||
case 0x37:
|
||||
return new ActionMBAsciiToChar();
|
||||
case 0x99:
|
||||
return new ActionJump(this);
|
||||
case 0x9D:
|
||||
return new ActionIf(this);
|
||||
case 0x9E:
|
||||
return new ActionCall();
|
||||
case 0x1C:
|
||||
return new ActionGetVariable();
|
||||
case 0x1D:
|
||||
return new ActionSetVariable();
|
||||
case 0x9A:
|
||||
return new ActionGetURL2(this);
|
||||
case 0x9F:
|
||||
return new ActionGotoFrame2(actionLength, this);
|
||||
case 0x20:
|
||||
return new ActionSetTarget2();
|
||||
case 0x22:
|
||||
return new ActionGetProperty();
|
||||
case 0x23:
|
||||
return new ActionSetProperty();
|
||||
case 0x24:
|
||||
return new ActionCloneSprite();
|
||||
case 0x25:
|
||||
return new ActionRemoveSprite();
|
||||
case 0x27:
|
||||
return new ActionStartDrag();
|
||||
case 0x28:
|
||||
return new ActionEndDrag();
|
||||
case 0x8D:
|
||||
return new ActionWaitForFrame2(this, cpool);
|
||||
case 0x26:
|
||||
return new ActionTrace();
|
||||
case 0x34:
|
||||
return new ActionGetTime();
|
||||
case 0x30:
|
||||
return new ActionRandomNumber();
|
||||
//SWF5 Actions
|
||||
case 0x3D:
|
||||
return new ActionCallFunction();
|
||||
case 0x52:
|
||||
return new ActionCallMethod();
|
||||
case 0x88:
|
||||
return new ActionConstantPool(actionLength, this, version);
|
||||
case 0x9B:
|
||||
return new ActionDefineFunction(actionLength, this, rri, version);
|
||||
case 0x3C:
|
||||
return new ActionDefineLocal();
|
||||
case 0x41:
|
||||
return new ActionDefineLocal2();
|
||||
case 0x3A:
|
||||
return new ActionDelete();
|
||||
case 0x3B:
|
||||
return new ActionDelete2();
|
||||
case 0x46:
|
||||
return new ActionEnumerate();
|
||||
case 0x49:
|
||||
return new ActionEquals2();
|
||||
case 0x4E:
|
||||
return new ActionGetMember();
|
||||
case 0x42:
|
||||
return new ActionInitArray();
|
||||
case 0x43:
|
||||
return new ActionInitObject();
|
||||
case 0x53:
|
||||
return new ActionNewMethod();
|
||||
case 0x40:
|
||||
return new ActionNewObject();
|
||||
case 0x4F:
|
||||
return new ActionSetMember();
|
||||
case 0x45:
|
||||
return new ActionTargetPath();
|
||||
case 0x94:
|
||||
return new ActionWith(this, rri, version);
|
||||
case 0x4A:
|
||||
return new ActionToNumber();
|
||||
case 0x4B:
|
||||
return new ActionToString();
|
||||
case 0x44:
|
||||
return new ActionTypeOf();
|
||||
case 0x47:
|
||||
return new ActionAdd2();
|
||||
case 0x48:
|
||||
return new ActionLess2();
|
||||
case 0x3F:
|
||||
return new ActionModulo();
|
||||
case 0x60:
|
||||
return new ActionBitAnd();
|
||||
case 0x63:
|
||||
return new ActionBitLShift();
|
||||
case 0x61:
|
||||
return new ActionBitOr();
|
||||
case 0x64:
|
||||
return new ActionBitRShift();
|
||||
case 0x65:
|
||||
return new ActionBitURShift();
|
||||
case 0x62:
|
||||
return new ActionBitXor();
|
||||
case 0x51:
|
||||
return new ActionDecrement();
|
||||
case 0x50:
|
||||
return new ActionIncrement();
|
||||
case 0x4C:
|
||||
return new ActionPushDuplicate();
|
||||
case 0x3E:
|
||||
return new ActionReturn();
|
||||
case 0x4D:
|
||||
return new ActionStackSwap();
|
||||
case 0x87:
|
||||
return new ActionStoreRegister(this);
|
||||
//SWF6 Actions
|
||||
case 0x54:
|
||||
return new ActionInstanceOf();
|
||||
case 0x55:
|
||||
return new ActionEnumerate2();
|
||||
case 0x66:
|
||||
return new ActionStrictEquals();
|
||||
case 0x67:
|
||||
return new ActionGreater();
|
||||
case 0x68:
|
||||
return new ActionStringGreater();
|
||||
//SWF7 Actions
|
||||
case 0x8E:
|
||||
return new ActionDefineFunction2(actionLength, this, rri, version);
|
||||
case 0x69:
|
||||
return new ActionExtends();
|
||||
case 0x2B:
|
||||
return new ActionCastOp();
|
||||
case 0x2C:
|
||||
return new ActionImplementsOp();
|
||||
case 0x8F:
|
||||
return new ActionTry(actionLength, this, rri, version);
|
||||
case 0x2A:
|
||||
return new ActionThrow();
|
||||
default:
|
||||
/*if (actionLength > 0) {
|
||||
//skip(actionLength);
|
||||
}*/
|
||||
//throw new UnknownActionException(actionCode);
|
||||
Action r = new ActionNop();
|
||||
r.actionCode = actionCode;
|
||||
r.actionLength = actionLength;
|
||||
return r;
|
||||
//return new Action(actionCode, actionLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ import com.jpexs.decompiler.flash.tags.ShowFrameTag;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ASMSource;
|
||||
import com.jpexs.decompiler.flash.tags.base.Container;
|
||||
import com.jpexs.decompiler.flash.tags.base.ContainerItem;
|
||||
import com.jpexs.decompiler.flash.tags.base.Exportable;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.helpers.Helper;
|
||||
@@ -83,7 +84,7 @@ public class TagNode {
|
||||
return tag.toString();
|
||||
}
|
||||
|
||||
public static List<TagNode> createTagList(List<Object> list) {
|
||||
public static List<TagNode> createTagList(List<ContainerItem> list) {
|
||||
List<TagNode> ret = new ArrayList<>();
|
||||
int frame = 1;
|
||||
List<TagNode> frames = new ArrayList<>();
|
||||
@@ -162,7 +163,7 @@ public class TagNode {
|
||||
if (t instanceof Container) {
|
||||
TagNode tti = new TagNode(t);
|
||||
if (((Container) t).getItemCount() > 0) {
|
||||
List<Object> subItems = ((Container) t).getSubItems();
|
||||
List<ContainerItem> subItems = ((Container) t).getSubItems();
|
||||
tti.subItems = createTagList(subItems);
|
||||
}
|
||||
//ret.add(tti);
|
||||
|
||||
@@ -1375,7 +1375,7 @@ public class AVM2Code implements Serializable {
|
||||
list.remove(lastPos);
|
||||
}
|
||||
|
||||
s = Graph.graphToString(list, hilighted, constants, localRegNames, fullyQualifiedNames);
|
||||
s = Graph.graphToString(list, hilighted, true, constants, localRegNames, fullyQualifiedNames);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -43,6 +43,12 @@ public class NewObjectAVM2Item extends AVM2Item {
|
||||
if (pairs.size() < 2) {
|
||||
return hilight("{", highlight) + params + hilight("}", highlight);
|
||||
}
|
||||
return "\r\n" + Graph.INDENTOPEN + "\r\n" + hilight("{", highlight) + "\r\n" + params + "\r\n" + hilight("}", highlight) + "\r\n" + Graph.INDENTCLOSE + "\r\n";
|
||||
String ret = "\r\n" + Graph.INDENTOPEN + "\r\n";
|
||||
ret += hilight("{", highlight) + "\r\n";
|
||||
ret += Graph.INDENTOPEN + "\r\n";
|
||||
ret += params + "\r\n";
|
||||
ret += Graph.INDENTCLOSE + "\r\n";
|
||||
ret += hilight("}", highlight) + "\r\n" + Graph.INDENTCLOSE + "\r\n";
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.abc.avm2.model;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -44,10 +45,12 @@ public class WithAVM2Item extends AVM2Item {
|
||||
public String toString(boolean highlight, ConstantPool constants, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames) {
|
||||
String ret;
|
||||
ret = hilight("with(", highlight) + scope.toString(highlight, constants, localRegNames, fullyQualifiedNames) + hilight(")", highlight) + "\r\n" + hilight("{", highlight) + "\r\n";
|
||||
ret += Graph.INDENTOPEN + "\r\n";
|
||||
/*for (GraphTargetItem ti : items) {
|
||||
ret += ti.toString(constants, localRegNames, fullyQualifiedNames) + "\r\n";
|
||||
}
|
||||
ret += hilight("}", highlight);*/
|
||||
}*/
|
||||
ret += Graph.INDENTCLOSE + "\r\n";
|
||||
ret += hilight("}", highlight);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.abc.avm2.model.InAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.LocalRegAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.SetTypeAVM2Item;
|
||||
import com.jpexs.decompiler.graph.Block;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.Loop;
|
||||
@@ -71,11 +72,13 @@ public class ForEachInAVM2Item extends LoopItem implements Block {
|
||||
String ret = "";
|
||||
ret += hilight("loop" + loop.id + ":", highlight) + "\r\n";
|
||||
ret += hilight("for each (", highlight) + expression.toString(highlight, localData) + hilight(")", highlight) + "\r\n" + hilight("{", highlight) + "\r\n";
|
||||
ret += Graph.INDENTOPEN + "\r\n";
|
||||
for (GraphTargetItem ti : commands) {
|
||||
if (!ti.isEmpty()) {
|
||||
ret += ti.toStringSemicoloned(highlight, localData) + "\r\n";
|
||||
}
|
||||
}
|
||||
ret += Graph.INDENTCLOSE + "\r\n";
|
||||
ret += hilight("}", highlight) + "\r\n";
|
||||
ret += hilight(":loop" + loop.id, highlight);
|
||||
return ret;
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.abc.avm2.model.InAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.LocalRegAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.SetTypeAVM2Item;
|
||||
import com.jpexs.decompiler.graph.Block;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.Loop;
|
||||
@@ -71,11 +72,13 @@ public class ForInAVM2Item extends LoopItem implements Block {
|
||||
String ret = "";
|
||||
ret += hilight("loop" + loop.id + ":", highlight) + "\r\n";
|
||||
ret += hilight("for (", highlight) + expression.toString(highlight, localData) + hilight(")", highlight) + "\r\n" + hilight("{", highlight) + "\r\n";
|
||||
ret += Graph.INDENTOPEN + "\r\n";
|
||||
for (GraphTargetItem ti : commands) {
|
||||
if (!ti.isEmpty()) {
|
||||
ret += ti.toStringSemicoloned(highlight, localData) + "\r\n";
|
||||
}
|
||||
}
|
||||
ret += Graph.INDENTCLOSE + "\r\n";
|
||||
ret += hilight("}", highlight) + "\r\n";
|
||||
ret += hilight(":loop" + loop.id, highlight);
|
||||
return ret;
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.abc.avm2.ConstantPool;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.AVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.types.ABCException;
|
||||
import com.jpexs.decompiler.graph.Block;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.model.ContinueItem;
|
||||
import com.jpexs.helpers.Helper;
|
||||
@@ -55,29 +56,35 @@ public class TryAVM2Item extends AVM2Item implements Block {
|
||||
public String toString(boolean highlight, ConstantPool constants, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames) {
|
||||
String ret = "";
|
||||
ret += hilight("try", highlight) + "\r\n" + hilight("{", highlight) + "\r\n";
|
||||
ret += Graph.INDENTOPEN + "\r\n";
|
||||
for (GraphTargetItem ti : tryCommands) {
|
||||
if (!ti.isEmpty()) {
|
||||
ret += ti.toStringSemicoloned(highlight, Helper.toList(constants, localRegNames, fullyQualifiedNames)) + "\r\n";
|
||||
}
|
||||
}
|
||||
ret += Graph.INDENTCLOSE + "\r\n";
|
||||
ret += hilight("}", highlight);
|
||||
for (int e = 0; e < catchExceptions.size(); e++) {
|
||||
ret += "\r\n" + hilight("catch(" + catchExceptions.get(e).getVarName(constants, fullyQualifiedNames) + ":" + catchExceptions.get(e).getTypeName(constants, fullyQualifiedNames) + ")", highlight) + "\r\n" + hilight("{", highlight) + "\r\n";
|
||||
ret += Graph.INDENTOPEN + "\r\n";
|
||||
List<GraphTargetItem> commands = catchCommands.get(e);
|
||||
for (GraphTargetItem ti : commands) {
|
||||
if (!ti.isEmpty()) {
|
||||
ret += ti.toStringSemicoloned(highlight, Helper.toList(constants, localRegNames, fullyQualifiedNames)) + "\r\n";
|
||||
}
|
||||
}
|
||||
ret += Graph.INDENTCLOSE + "\r\n";
|
||||
ret += hilight("}", highlight);
|
||||
}
|
||||
if (finallyCommands.size() > 0) {
|
||||
ret += "\r\n" + hilight("finally", highlight) + "\r\n" + hilight("{", highlight) + "\r\n";
|
||||
ret += Graph.INDENTOPEN + "\r\n";
|
||||
for (GraphTargetItem ti : finallyCommands) {
|
||||
if (!ti.isEmpty()) {
|
||||
ret += ti.toStringSemicoloned(highlight, Helper.toList(constants, localRegNames, fullyQualifiedNames)) + "\r\n";
|
||||
}
|
||||
}
|
||||
ret += Graph.INDENTCLOSE + "\r\n";
|
||||
ret += hilight("}", highlight);
|
||||
}
|
||||
return ret;
|
||||
|
||||
@@ -203,7 +203,6 @@ public class Action implements GraphSourceItem {
|
||||
List<Long> part = a.getAllRefs(version);
|
||||
ret.addAll(part);
|
||||
if (a.afterInsert != null) {
|
||||
a.afterInsert.setAddress(a.getAddress(), version, false);
|
||||
ret.addAll(a.afterInsert.getAllRefs(version));
|
||||
}
|
||||
}
|
||||
@@ -726,7 +725,7 @@ public class Action implements GraphSourceItem {
|
||||
|
||||
List<GraphTargetItem> tree = actionsToTree(new HashMap<Integer, String>(), new HashMap<String, GraphTargetItem>(), new HashMap<String, GraphTargetItem>(), actions, version, staticOperation, path);
|
||||
|
||||
return Graph.graphToString(tree, highlight);
|
||||
return Graph.graphToString(tree, highlight, true);
|
||||
}
|
||||
}, timeout, TimeUnit.SECONDS);
|
||||
} catch (TimeoutException ex) {
|
||||
@@ -1199,9 +1198,9 @@ public class Action implements GraphSourceItem {
|
||||
String s = null;
|
||||
try {
|
||||
s = Action.actionsToString(new ArrayList<DisassemblyListener>(), address, ret, null, version, false, false, swfPos, path);
|
||||
ret = ASMParser.parse(address, swfPos, true, s, SWF.DEFAULT_VERSION);
|
||||
ret = ASMParser.parse(address, swfPos, true, s, SWF.DEFAULT_VERSION, false);
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(SWFInputStream.class.getName()).log(Level.SEVERE, "parsing error", ex);
|
||||
Logger.getLogger(SWFInputStream.class.getName()).log(Level.SEVERE, "parsing error. path: " + path, ex);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,843 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2013 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.action;
|
||||
|
||||
import com.jpexs.decompiler.flash.Configuration;
|
||||
import com.jpexs.decompiler.flash.DisassemblyListener;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.action.model.ConstantPool;
|
||||
import com.jpexs.decompiler.flash.action.model.DirectValueActionItem;
|
||||
import com.jpexs.decompiler.flash.action.special.ActionEnd;
|
||||
import com.jpexs.decompiler.flash.action.special.ActionNop;
|
||||
import com.jpexs.decompiler.flash.action.special.ActionStore;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionEquals;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionIf;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionJump;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionPush;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionConstantPool;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionDefineFunction;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionEquals2;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionStoreRegister;
|
||||
import com.jpexs.decompiler.flash.action.swf7.ActionDefineFunction2;
|
||||
import com.jpexs.decompiler.flash.ecma.EcmaScript;
|
||||
import com.jpexs.decompiler.flash.ecma.Null;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItemContainer;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.NotCompileTimeItem;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import com.jpexs.helpers.ReReadableInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Scanner;
|
||||
import java.util.Stack;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Class for reading data from SWF file
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ActionListReader {
|
||||
|
||||
private static final Logger log = Logger.getLogger(SWFInputStream.class.getName());
|
||||
|
||||
/**
|
||||
* Reads list of actions from the stream. Reading ends with
|
||||
* ActionEndFlag(=0) or end of the stream.
|
||||
*
|
||||
* @param listeners
|
||||
* @param address
|
||||
* @param ip
|
||||
* @param rri
|
||||
* @param version
|
||||
* @param containerSWFOffset
|
||||
* @param endip
|
||||
* @param path
|
||||
* @return List of actions
|
||||
* @throws IOException
|
||||
*/
|
||||
public static List<Action> readActionList(List<DisassemblyListener> listeners, long containerSWFOffset, ReReadableInputStream rri, int version, int ip, int endIp, String path) throws IOException {
|
||||
boolean deobfuscate = Configuration.getConfig("autoDeobfuscate", true);
|
||||
|
||||
ConstantPool cpool = new ConstantPool();
|
||||
|
||||
SWFInputStream sis = new SWFInputStream(rri, version);
|
||||
|
||||
// List of the actions. N. item contains the action which starts in offset N.
|
||||
List<Action> actionMap = new ArrayList<>();
|
||||
List<Long> nextOffsets = new ArrayList<>();
|
||||
Action entryAction = readActionListAtPos(listeners, containerSWFOffset, cpool,
|
||||
sis, rri,
|
||||
actionMap, nextOffsets,
|
||||
ip, ip, endIp, version, path, false, new ArrayList<Long>());
|
||||
|
||||
Map<Action, List<Action>> containerLastActions = new HashMap<>();
|
||||
getContainerLastActions(actionMap, containerLastActions);
|
||||
|
||||
List<Action> actions = new ArrayList<>();
|
||||
|
||||
// jump to the entry action when it is diffrent from the first action in the map
|
||||
int index = getNextNotNullIndex(actionMap, 0);
|
||||
if (index != -1 && entryAction != actionMap.get(index)) {
|
||||
ActionJump jump = new ActionJump(0);
|
||||
int size = getTotalActionLength(jump);
|
||||
jump.setJumpOffset((int) (entryAction.getAddress() - size));
|
||||
actions.add(jump);
|
||||
}
|
||||
|
||||
// remove nulls
|
||||
index = getNextNotNullIndex(actionMap, index);
|
||||
while (index > -1) {
|
||||
Action action = actionMap.get(index);
|
||||
long nextOffset = nextOffsets.get(index);
|
||||
int nextIndex = getNextNotNullIndex(actionMap, index + 1);
|
||||
actions.add(action);
|
||||
if (nextIndex != -1 && nextOffset != nextIndex) {
|
||||
if (!action.isExit() && !(action instanceof ActionJump)) {
|
||||
ActionJump jump = new ActionJump(0);
|
||||
jump.setAddress(action.getAddress(), version);
|
||||
int size = getTotalActionLength(jump);
|
||||
jump.setJumpOffset((int) (nextOffset - action.getAddress() - size));
|
||||
actions.add(jump);
|
||||
}
|
||||
}
|
||||
index = nextIndex;
|
||||
}
|
||||
|
||||
// Map for storing the targers of the "jump" actions
|
||||
// "jump" action can be ActionIf, ActionJump and any ActionStore
|
||||
Map<Action, Action> jumps = new HashMap<>();
|
||||
getJumps(actions, jumps);
|
||||
|
||||
long endAddress = updateAddresses(actions, ip, version);
|
||||
updateJumps(actions, jumps, containerLastActions, endAddress, version);
|
||||
updateActionStores(actions, jumps);
|
||||
updateContainerSizes(actions, containerLastActions);
|
||||
updateActionLengths(actions, version);
|
||||
|
||||
// add end action
|
||||
Action lastAction = actions.get(actions.size() - 1);
|
||||
if (!(lastAction instanceof ActionEnd)) {
|
||||
Action aEnd = new ActionEnd();
|
||||
aEnd.setAddress(endAddress, version);
|
||||
actions.add(aEnd);
|
||||
endAddress += getTotalActionLength(aEnd);
|
||||
}
|
||||
|
||||
if (deobfuscate) {
|
||||
return deobfuscateActionList(listeners, containerSWFOffset, actions, version, 0, path);
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads list of actions from the stream. Reading ends with
|
||||
* ActionEndFlag(=0) or end of the stream.
|
||||
*
|
||||
* @param listeners
|
||||
* @param address
|
||||
* @param ip
|
||||
* @param rri
|
||||
* @param version
|
||||
* @param containerSWFOffset
|
||||
* @param endip
|
||||
* @param path
|
||||
* @return List of actions
|
||||
* @throws IOException
|
||||
*/
|
||||
public static List<Action> deobfuscateActionList(List<DisassemblyListener> listeners, long containerSWFOffset, List<Action> actions, int version, int ip, String path) throws IOException {
|
||||
byte[] data = Action.actionsToBytes(actions, true, version);
|
||||
ReReadableInputStream rri = new ReReadableInputStream(new ByteArrayInputStream(data));
|
||||
int endIp = data.length;
|
||||
|
||||
List<Action> retdups = new ArrayList<>();
|
||||
for (int i = 0; i <= endIp; i++) {
|
||||
Action a = new ActionNop();
|
||||
a.setAddress(i, version);
|
||||
retdups.add(a);
|
||||
}
|
||||
ConstantPool cpool = new ConstantPool();
|
||||
|
||||
Stack<GraphTargetItem> stack = new Stack<>();
|
||||
|
||||
List<Object> localData = Helper.toList(new HashMap<Integer, String>(), new HashMap<String, GraphTargetItem>(), new HashMap<String, GraphTargetItem>());
|
||||
|
||||
SWFInputStream sis = new SWFInputStream(rri, version);
|
||||
deobfustaceActionListAtPosRecursive(listeners, new ArrayList<GraphTargetItem>(), new HashMap<Long, List<GraphSourceItemContainer>>(), containerSWFOffset, localData, stack, cpool, sis, rri, ip, retdups, ip, endIp, path, new HashMap<Integer, Integer>(), false, new HashMap<Integer, HashMap<String, GraphTargetItem>>(), version);
|
||||
|
||||
if (!retdups.isEmpty()) {
|
||||
for (int i = 0; i < ip; i++) {
|
||||
retdups.remove(0);
|
||||
}
|
||||
}
|
||||
List<Action> ret = new ArrayList<>();
|
||||
Action last = null;
|
||||
for (Action a : retdups) {
|
||||
if (a != last) {
|
||||
ret.add(a);
|
||||
}
|
||||
last = a;
|
||||
}
|
||||
for (int i = 0; i < retdups.size(); i++) {
|
||||
Action a = retdups.get(i);
|
||||
if (a instanceof ActionEnd) {
|
||||
if (i < retdups.size() - 1) {
|
||||
ActionJump jmp = new ActionJump(0);
|
||||
jmp.setJumpOffset(retdups.size() - i - jmp.getBytes(version).length);
|
||||
a.replaceWith = jmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Configuration.getConfig("removeNops", true)) {
|
||||
ret = Action.removeNops(0, ret, version, 0, path);
|
||||
}
|
||||
List<Action> reta = new ArrayList<>();
|
||||
for (Object o : ret) {
|
||||
if (o instanceof Action) {
|
||||
reta.add((Action) o);
|
||||
}
|
||||
}
|
||||
return reta;
|
||||
}
|
||||
|
||||
private static int getPrevNotNullIndex(List<Action> actionMap, int startIndex) {
|
||||
startIndex = Math.min(startIndex, actionMap.size() - 1);
|
||||
for (int i = startIndex; i >= 0; i--) {
|
||||
if (actionMap.get(i) != null) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static int getNextNotNullIndex(List<Action> actionMap, int startIndex) {
|
||||
for (int i = startIndex; i < actionMap.size(); i++) {
|
||||
if (actionMap.get(i) != null) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static Map<Long, Action> actionListToMap(List<Action> actions) {
|
||||
Map<Long, Action> map = new HashMap<>(actions.size());
|
||||
for (Action a : actions) {
|
||||
long address = a.getAddress();
|
||||
// There are multiple actions in the same address (2nd action is a jump for obfuscated code)
|
||||
// So this check is required
|
||||
if (!map.containsKey(address)) {
|
||||
map.put(a.getAddress(), a);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private static void getJumps(List<Action> actions, Map<Action, Action> jumps) {
|
||||
Map<Long, Action> actionMap = actionListToMap(actions);
|
||||
for (Action a : actions) {
|
||||
long target = -1;
|
||||
if (a instanceof ActionIf) {
|
||||
ActionIf aIf = (ActionIf) a;
|
||||
target = aIf.getAddress() + getTotalActionLength(a) + aIf.getJumpOffset();
|
||||
} else if (a instanceof ActionJump) {
|
||||
ActionJump aJump = (ActionJump) a;
|
||||
target = aJump.getAddress() + getTotalActionLength(a) + aJump.getJumpOffset();
|
||||
} else if (a instanceof ActionStore) {
|
||||
ActionStore aStore = (ActionStore) a;
|
||||
int storeSize = aStore.getStoreSize();
|
||||
// skip storeSize + 1 actions (+1 is the current action)
|
||||
Action targetAction = a;
|
||||
for (int i = 0; i <= storeSize; i++) {
|
||||
long address = targetAction.getAddress() + getTotalActionLength(targetAction);
|
||||
targetAction = actionMap.get(address);
|
||||
if (targetAction == null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
jumps.put(a, targetAction);
|
||||
}
|
||||
if (target >= 0) {
|
||||
Action targetAction = actionMap.get(target);
|
||||
jumps.put(a, targetAction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void getContainerLastActions(List<Action> actionMap, Map<Action, List<Action>> lastActions) {
|
||||
for (int i = 0; i < actionMap.size(); i++) {
|
||||
Action a = actionMap.get(i);
|
||||
if (a == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (a instanceof GraphSourceItemContainer) {
|
||||
GraphSourceItemContainer container = (GraphSourceItemContainer) a;
|
||||
List<Long> sizes = container.getContainerSizes();
|
||||
long endAddress = a.getAddress() + container.getHeaderSize();
|
||||
List<Action> lasts = new ArrayList<>(sizes.size());
|
||||
for (long size : sizes) {
|
||||
endAddress += size;
|
||||
int lastActionIndex = getPrevNotNullIndex(actionMap, (int) (endAddress - 1));
|
||||
Action lastAction = null;
|
||||
if (lastActionIndex != -1) {
|
||||
lastAction = actionMap.get(lastActionIndex);
|
||||
}
|
||||
lasts.add(lastAction);
|
||||
}
|
||||
lastActions.put(a, lasts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static long updateAddresses(List<Action> actions, long address, int version) {
|
||||
for (int i = 0; i < actions.size(); i++) {
|
||||
Action a = actions.get(i);
|
||||
a.setAddress(address, version);
|
||||
int length = a.getBytes(version).length;
|
||||
if ((i != actions.size() - 1) && (a instanceof ActionEnd)) {
|
||||
// placeholder for jump action
|
||||
length = getTotalActionLength(new ActionJump(0));
|
||||
}
|
||||
address += length;
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
private static void updateActionLengths(List<Action> actions, int version) {
|
||||
for (int i = 0; i < actions.size(); i++) {
|
||||
Action a = actions.get(i);
|
||||
int length = a.getBytes(version).length;
|
||||
a.actionLength = length - 1 - ((a.actionCode >= 0x80) ? 2 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
private static void updateActionStores(List<Action> actions, Map<Action, Action> jumps) {
|
||||
Map<Long, Action> actionMap = actionListToMap(actions);
|
||||
for (int i = 0; i < actions.size(); i++) {
|
||||
Action a = actions.get(i);
|
||||
if (a instanceof ActionStore) {
|
||||
ActionStore aStore = (ActionStore) a;
|
||||
Action nextActionAfterStore = jumps.get(a);
|
||||
Action a1 = a;
|
||||
List<Action> store = new ArrayList<>();
|
||||
while (true) {
|
||||
long address = a1.getAddress() + getTotalActionLength(a1);
|
||||
a1 = actionMap.get(address);
|
||||
if (a1 == null || a1 == nextActionAfterStore) {
|
||||
break;
|
||||
}
|
||||
actions.remove(a1);
|
||||
store.add(a1);
|
||||
}
|
||||
aStore.setStore(store);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void updateContainerSizes(List<Action> actions, Map<Action, List<Action>> containerLastActions) {
|
||||
for (int i = 0; i < actions.size(); i++) {
|
||||
Action a = actions.get(i);
|
||||
if (a instanceof GraphSourceItemContainer) {
|
||||
GraphSourceItemContainer container = (GraphSourceItemContainer) a;
|
||||
List<Action> lastActions = containerLastActions.get(a);
|
||||
long startAddress = a.getAddress() + container.getHeaderSize();
|
||||
for (int j = 0; j < lastActions.size(); j++) {
|
||||
Action lastAction = lastActions.get(j);
|
||||
int length = (int) (lastAction.getAddress() + getTotalActionLength(lastAction) - startAddress);
|
||||
container.setContainerSize(j, length);
|
||||
startAddress += length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void replaceJumpTargets(Map<Action, Action> jumps, Action oldTarget, Action newTarget) {
|
||||
for (Action a : jumps.keySet()) {
|
||||
if (jumps.get(a) == oldTarget) {
|
||||
jumps.put(a, newTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void replaceContainerLastActions(Map<Action, List<Action>> containerLastActions, Action oldTarget, Action newTarget) {
|
||||
for (Action a : containerLastActions.keySet()) {
|
||||
List<Action> targets = containerLastActions.get(a);
|
||||
for (int i = 0; i < targets.size(); i++) {
|
||||
if (targets.get(i) == oldTarget) {
|
||||
targets.set(i, newTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void updateJumps(List<Action> actions, Map<Action, Action> jumps, Map<Action, List<Action>> containerLastActions, long endAddress, int version) {
|
||||
if (actions.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < actions.size(); i++) {
|
||||
Action a = actions.get(i);
|
||||
if ((i != actions.size() - 1) && (a instanceof ActionEnd)) {
|
||||
ActionJump aJump = new ActionJump(0);
|
||||
aJump.setJumpOffset((int) (endAddress - a.getAddress() - getTotalActionLength(aJump)));
|
||||
aJump.setAddress(a.getAddress(), version);
|
||||
replaceJumpTargets(jumps, a, aJump);
|
||||
replaceContainerLastActions(containerLastActions, a, aJump);
|
||||
a = aJump;
|
||||
actions.set(i, a);
|
||||
} else if (a instanceof ActionIf) {
|
||||
ActionIf aIf = (ActionIf) a;
|
||||
Action target = jumps.get(a);
|
||||
long offset;
|
||||
if (target != null) {
|
||||
offset = target.getAddress() - a.getAddress() - getTotalActionLength(a);
|
||||
} else {
|
||||
offset = endAddress - a.getAddress() - getTotalActionLength(a);
|
||||
}
|
||||
aIf.setJumpOffset((int) offset);
|
||||
} else if (a instanceof ActionJump) {
|
||||
ActionJump aJump = (ActionJump) a;
|
||||
Action target = jumps.get(a);
|
||||
long offset;
|
||||
if (target != null) {
|
||||
offset = target.getAddress() - a.getAddress() - getTotalActionLength(a);
|
||||
} else {
|
||||
offset = endAddress - a.getAddress() - getTotalActionLength(a);
|
||||
}
|
||||
aJump.setJumpOffset((int) offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Action readActionListAtPos(List<DisassemblyListener> listeners, long containerSWFOffset, ConstantPool cpool,
|
||||
SWFInputStream sis, ReReadableInputStream rri,
|
||||
List<Action> actions, List<Long> nextOffsets,
|
||||
long ip, long startIp, long endIp, int version, String path, boolean indeterminate, List<Long> visitedContainers) throws IOException {
|
||||
|
||||
Action entryAction = null;
|
||||
|
||||
if (visitedContainers.contains(ip)) {
|
||||
return null;
|
||||
}
|
||||
visitedContainers.add(ip);
|
||||
|
||||
Queue<Long> jumpQueue = new LinkedList<>();
|
||||
jumpQueue.add(ip);
|
||||
while (!jumpQueue.isEmpty()) {
|
||||
ip = jumpQueue.remove();
|
||||
while ((endIp == -1) || (endIp > ip)) {
|
||||
rri.setPos((int) ip);
|
||||
|
||||
Action a;
|
||||
if ((a = sis.readAction(rri, cpool)) == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
int actionLengthWithHeader = getTotalActionLength(a);
|
||||
|
||||
// unknown action, replace with jump
|
||||
if (a instanceof ActionNop) {
|
||||
ActionJump aJump = new ActionJump(0);
|
||||
int jumpLength = getTotalActionLength(aJump);
|
||||
aJump.setAddress(a.getAddress(), version);
|
||||
aJump.setJumpOffset(actionLengthWithHeader - jumpLength);
|
||||
a = aJump;
|
||||
actionLengthWithHeader = getTotalActionLength(a);
|
||||
}
|
||||
|
||||
if (entryAction == null) {
|
||||
entryAction = a;
|
||||
}
|
||||
|
||||
ensureCapacity(actions, nextOffsets, ip);
|
||||
|
||||
Action existingAction = actions.get((int) ip);
|
||||
if (existingAction != null) {
|
||||
break;
|
||||
}
|
||||
|
||||
actions.set((int) ip, a);
|
||||
nextOffsets.set((int) ip, ip + actionLengthWithHeader);
|
||||
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
listeners.get(i).progress("Reading", rri.getCount(), rri.length());
|
||||
}
|
||||
|
||||
a.containerSWFOffset = containerSWFOffset;
|
||||
a.setAddress(ip, version, false);
|
||||
|
||||
if (a instanceof ActionPush && cpool != null) {
|
||||
((ActionPush) a).constantPool = cpool.constants;
|
||||
} else if (a instanceof ActionConstantPool) {
|
||||
if (cpool == null) {
|
||||
cpool = new ConstantPool();
|
||||
}
|
||||
cpool.setNew(((ActionConstantPool) a).constantPool);
|
||||
} else if (a instanceof ActionIf) {
|
||||
ActionIf aIf = (ActionIf) a;
|
||||
long nIp = ip + actionLengthWithHeader + aIf.getJumpOffset();
|
||||
if (nIp >= 0) {
|
||||
jumpQueue.add(nIp);
|
||||
}
|
||||
} else if (a instanceof ActionJump) {
|
||||
ActionJump aJump = (ActionJump) a;
|
||||
long nIp = ip + actionLengthWithHeader + aJump.getJumpOffset();
|
||||
if (nIp >= 0) {
|
||||
jumpQueue.add(nIp);
|
||||
}
|
||||
break;
|
||||
} else if (a instanceof GraphSourceItemContainer) {
|
||||
GraphSourceItemContainer cnt = (GraphSourceItemContainer) a;
|
||||
String cntName = cnt.getName();
|
||||
String newPath = path + (cntName == null ? "" : "/" + cntName);
|
||||
for (long size : cnt.getContainerSizes()) {
|
||||
if (size != 0) {
|
||||
long ip2 = ip + actionLengthWithHeader;
|
||||
//long endIp2 = ip + actionLengthWithHeader + size;
|
||||
readActionListAtPos(listeners, containerSWFOffset, cpool,
|
||||
sis, rri,
|
||||
actions, nextOffsets,
|
||||
ip2, startIp, endIp, version, newPath, indeterminate, visitedContainers);
|
||||
actionLengthWithHeader += size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ip = ip + actionLengthWithHeader;
|
||||
|
||||
if (a.isExit()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return entryAction;
|
||||
}
|
||||
|
||||
private static int getTotalActionLength(Action action) {
|
||||
return action.actionLength + 1 + ((action.actionCode >= 0x80) ? 2 : 0);
|
||||
}
|
||||
|
||||
private static void ensureCapacity(List<Action> actions, List<Long> nextOffsets, long index) {
|
||||
while (actions.size() <= index) {
|
||||
actions.add(null);
|
||||
nextOffsets.add(-1L);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static void deobfustaceActionListAtPosRecursive(List<DisassemblyListener> listeners, List<GraphTargetItem> output, HashMap<Long, List<GraphSourceItemContainer>> containers, long containerSWFOffset, List<Object> localData, Stack<GraphTargetItem> stack, ConstantPool cpool, SWFInputStream sis, ReReadableInputStream rri, int ip, List<Action> ret, int startIp, int endip, String path, Map<Integer, Integer> visited, boolean indeterminate, Map<Integer, HashMap<String, GraphTargetItem>> decisionStates, int version) throws IOException {
|
||||
boolean debugMode = false;
|
||||
boolean decideBranch = false;
|
||||
|
||||
boolean deobfuscate = Configuration.getConfig("autoDeobfuscate", true);
|
||||
rri.setPos(ip);
|
||||
Action a;
|
||||
long filePos = rri.getPos();
|
||||
Scanner sc = new Scanner(System.in, "utf-8");
|
||||
int prevIp = ip;
|
||||
loopip:
|
||||
while (((endip == -1) || (endip > ip)) && (a = sis.readAction(rri, cpool)) != null) {
|
||||
if (!visited.containsKey(ip)) {
|
||||
visited.put(ip, 0);
|
||||
}
|
||||
int curVisited = visited.get(ip);
|
||||
curVisited++;
|
||||
visited.put(ip, curVisited);
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
listeners.get(i).progress("Deobfuscating", rri.getCount(), rri.length());
|
||||
}
|
||||
if ((ip < ret.size()) && (!(ret.get(ip) instanceof ActionNop))) {
|
||||
a = ret.get(ip);
|
||||
}
|
||||
a.containerSWFOffset = containerSWFOffset;
|
||||
a.setAddress(prevIp, version, false);
|
||||
int info = a.actionLength + 1 + ((a.actionCode >= 0x80) ? 2 : 0);
|
||||
|
||||
if (a instanceof ActionPush) {
|
||||
if (cpool != null) {
|
||||
((ActionPush) a).constantPool = cpool.constants;
|
||||
}
|
||||
}
|
||||
|
||||
if (debugMode) {
|
||||
String atos = a.getASMSource(new ArrayList<GraphSourceItem>(), new ArrayList<Long>(), cpool.constants, version, false);
|
||||
if (a instanceof GraphSourceItemContainer) {
|
||||
atos = a.toString();
|
||||
}
|
||||
System.err.println("readActionListAtPos ip: " + (ip - startIp) + " (0x" + Helper.formatAddress(ip - startIp) + ") " + " action(len " + a.actionLength + "): " + atos + (a.isIgnored() ? " (ignored)" : "") + " stack:" + Helper.stackToString(stack, Helper.toList(cpool)) + " " + Helper.byteArrToString(a.getBytes(version)));
|
||||
@SuppressWarnings("unchecked")
|
||||
HashMap<String, GraphTargetItem> vars = (HashMap<String, GraphTargetItem>) localData.get(1);
|
||||
System.err.print("variables: ");
|
||||
for (Map.Entry<String, GraphTargetItem> v : vars.entrySet()) {
|
||||
System.err.print("'" + v + "' = " + v.getValue().toString(false, cpool) + ", ");
|
||||
}
|
||||
System.err.println();
|
||||
String add = "";
|
||||
if (a instanceof ActionIf) {
|
||||
add = " change: " + ((ActionIf) a).getJumpOffset();
|
||||
}
|
||||
if (a instanceof ActionJump) {
|
||||
add = " change: " + ((ActionJump) a).getJumpOffset();
|
||||
}
|
||||
System.err.println(add);
|
||||
}
|
||||
long newFilePos = rri.getPos();
|
||||
long actionLen = newFilePos - filePos;
|
||||
|
||||
int newip = -1;
|
||||
|
||||
if (a instanceof ActionConstantPool) {
|
||||
if (cpool == null) {
|
||||
cpool = new ConstantPool();
|
||||
}
|
||||
cpool.setNew(((ActionConstantPool) a).constantPool);
|
||||
}
|
||||
ActionIf aif = null;
|
||||
boolean goaif = false;
|
||||
if (!a.isIgnored()) {
|
||||
String varname = null;
|
||||
if (a instanceof StoreTypeAction) {
|
||||
StoreTypeAction sta = (StoreTypeAction) a;
|
||||
varname = sta.getVariableName(stack, cpool);
|
||||
}
|
||||
|
||||
try {
|
||||
if (a instanceof ActionIf) {
|
||||
aif = (ActionIf) a;
|
||||
|
||||
GraphTargetItem top = null;
|
||||
if (deobfuscate) {
|
||||
top = stack.pop();
|
||||
}
|
||||
int nip = rri.getPos() + aif.getJumpOffset();
|
||||
|
||||
if (decideBranch) {
|
||||
System.out.print("newip " + nip + ", ");
|
||||
System.out.print("Action: jump(j),ignore(i),compute(c)?");
|
||||
String next = sc.next();
|
||||
if (next.equals("j")) {
|
||||
newip = rri.getPos() + aif.getJumpOffset();
|
||||
rri.setPos(newip);
|
||||
|
||||
} else if (next.equals("i")) {
|
||||
} else if (next.equals("c")) {
|
||||
goaif = true;
|
||||
}
|
||||
} else if (deobfuscate && top.isCompileTime() && (!top.hasSideEffect())) {
|
||||
((ActionIf) a).compileTime = true;
|
||||
if (debugMode) {
|
||||
System.err.print("is compiletime -> ");
|
||||
}
|
||||
if (EcmaScript.toBoolean(top.getResult())) {
|
||||
newip = rri.getPos() + aif.getJumpOffset();
|
||||
aif.jumpUsed = true;
|
||||
if (aif.ignoreUsed) {
|
||||
aif.compileTime = false;
|
||||
}
|
||||
if (debugMode) {
|
||||
System.err.println("jump");
|
||||
}
|
||||
} else {
|
||||
aif.ignoreUsed = true;
|
||||
if (aif.jumpUsed) {
|
||||
aif.compileTime = false;
|
||||
}
|
||||
if (debugMode) {
|
||||
System.err.println("ignore");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (debugMode) {
|
||||
System.err.println("goaif");
|
||||
}
|
||||
goaif = true;
|
||||
}
|
||||
} else if (a instanceof ActionJump) {
|
||||
newip = rri.getPos() + ((ActionJump) a).getJumpOffset();
|
||||
} else if (!(a instanceof GraphSourceItemContainer)) {
|
||||
if (deobfuscate) {
|
||||
//return in for..in, TODO:Handle this better way
|
||||
if (((a instanceof ActionEquals) || (a instanceof ActionEquals2)) && (stack.size() == 1) && (stack.peek() instanceof DirectValueActionItem)) {
|
||||
stack.push(new DirectValueActionItem(null, 0, new Null(), new ArrayList<String>()));
|
||||
}
|
||||
if ((a instanceof ActionStoreRegister) && stack.isEmpty()) {
|
||||
stack.push(new DirectValueActionItem(null, 0, new Null(), new ArrayList<String>()));
|
||||
}
|
||||
a.translate(localData, stack, output, Graph.SOP_USE_STATIC/*Graph.SOP_SKIP_STATIC*/, path);
|
||||
}
|
||||
}
|
||||
} catch (RuntimeException ex) {
|
||||
log.log(Level.SEVERE, "Disassembly exception", ex);
|
||||
break;
|
||||
}
|
||||
|
||||
HashMap<String, GraphTargetItem> vars = (HashMap<String, GraphTargetItem>) localData.get(1);
|
||||
if (varname != null) {
|
||||
GraphTargetItem varval = vars.get(varname);
|
||||
if (varval != null && varval.isCompileTime() && indeterminate) {
|
||||
vars.put(varname, new NotCompileTimeItem(null, varval));
|
||||
}
|
||||
}
|
||||
}
|
||||
int nopos = -1;
|
||||
for (int i = 0; i < actionLen; i++) {
|
||||
if (a instanceof ActionNop) {
|
||||
int prevPos = (int) a.getAddress();
|
||||
a = new ActionNop();
|
||||
a.setAddress(prevPos, version);
|
||||
nopos++;
|
||||
if (nopos > 0) {
|
||||
a.setAddress(a.getAddress() + 1, version);
|
||||
}
|
||||
|
||||
}
|
||||
ret.set(ip + i, a);
|
||||
}
|
||||
|
||||
if (a instanceof GraphSourceItemContainer) {
|
||||
GraphSourceItemContainer cnt = (GraphSourceItemContainer) a;
|
||||
if (a instanceof Action) {
|
||||
long endAddr = a.getAddress() + cnt.getHeaderSize();
|
||||
String cntName = cnt.getName();
|
||||
List<List<GraphTargetItem>> output2s = new ArrayList<>();
|
||||
for (long size : cnt.getContainerSizes()) {
|
||||
if (size == 0) {
|
||||
output2s.add(new ArrayList<GraphTargetItem>());
|
||||
continue;
|
||||
}
|
||||
List<Object> localData2;
|
||||
List<GraphTargetItem> output2 = new ArrayList<>();
|
||||
if ((cnt instanceof ActionDefineFunction) || (cnt instanceof ActionDefineFunction2)) {
|
||||
localData2 = Helper.toList(new HashMap<Integer, String>(), new HashMap<String, GraphTargetItem>(), new HashMap<String, GraphTargetItem>());
|
||||
} else {
|
||||
localData2 = localData;
|
||||
}
|
||||
deobfustaceActionListAtPosRecursive(listeners, output2, containers, containerSWFOffset, localData2, new Stack<GraphTargetItem>(), cpool, sis, rri, (int) endAddr, ret, startIp, (int) (endAddr + size), path + (cntName == null ? "" : "/" + cntName), visited, indeterminate, decisionStates, version);
|
||||
output2s.add(output2);
|
||||
endAddr += size;
|
||||
}
|
||||
if (deobfuscate) {
|
||||
cnt.translateContainer(output2s, stack, output, (HashMap<Integer, String>) localData.get(0), (HashMap<String, GraphTargetItem>) localData.get(1), (HashMap<String, GraphTargetItem>) localData.get(2));
|
||||
}
|
||||
ip = (int) endAddr;
|
||||
prevIp = ip;
|
||||
rri.setPos(ip);
|
||||
filePos = rri.getPos();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (a instanceof ActionEnd) {
|
||||
break;
|
||||
}
|
||||
if (newip > -1) {
|
||||
ip = newip;
|
||||
} else {
|
||||
ip = ip + info;
|
||||
}
|
||||
rri.setPos(ip);
|
||||
filePos = rri.getPos();
|
||||
if (goaif) {
|
||||
aif.ignoreUsed = true;
|
||||
aif.jumpUsed = true;
|
||||
indeterminate = true;
|
||||
|
||||
HashMap<String, GraphTargetItem> vars = (HashMap<String, GraphTargetItem>) localData.get(1);
|
||||
boolean stateChanged = false;
|
||||
if (decisionStates.containsKey(ip)) {
|
||||
HashMap<String, GraphTargetItem> oldstate = decisionStates.get(ip);
|
||||
if (oldstate.size() != vars.size()) {
|
||||
stateChanged = true;
|
||||
} else {
|
||||
for (String k : vars.keySet()) {
|
||||
if (!oldstate.containsKey(k)) {
|
||||
stateChanged = true;
|
||||
break;
|
||||
}
|
||||
if (!vars.get(k).isCompileTime() && oldstate.get(k).isCompileTime()) {
|
||||
stateChanged = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
HashMap<String, GraphTargetItem> curstate = new HashMap<>();
|
||||
curstate.putAll(vars);
|
||||
decisionStates.put(ip, curstate);
|
||||
|
||||
if ((!stateChanged) && curVisited > 1) {
|
||||
List<Integer> branches = new ArrayList<>();
|
||||
branches.add(rri.getPos() + aif.getJumpOffset());
|
||||
branches.add(rri.getPos());
|
||||
for (int br : branches) {
|
||||
int visc = 0;
|
||||
if (visited.containsKey(br)) {
|
||||
visc = visited.get(br);
|
||||
}
|
||||
if (visc == 0) {//<curVisited){
|
||||
ip = br;
|
||||
prevIp = ip;
|
||||
rri.setPos(br);
|
||||
filePos = rri.getPos();
|
||||
continue loopip;
|
||||
}
|
||||
}
|
||||
break loopip;
|
||||
}
|
||||
|
||||
int oldPos = rri.getPos();
|
||||
@SuppressWarnings("unchecked")
|
||||
Stack<GraphTargetItem> substack = (Stack<GraphTargetItem>) stack.clone();
|
||||
deobfustaceActionListAtPosRecursive(listeners, output, containers, containerSWFOffset, prepareLocalBranch(localData), substack, cpool, sis, rri, rri.getPos() + aif.getJumpOffset(), ret, startIp, endip, path, visited, indeterminate, decisionStates, version);
|
||||
rri.setPos(oldPos);
|
||||
}
|
||||
prevIp = ip;
|
||||
if (a.isExit()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (DisassemblyListener listener : listeners) {
|
||||
listener.progress("Deobfuscating", rri.getCount(), rri.length());
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Object> prepareLocalBranch(List<Object> localData) {
|
||||
@SuppressWarnings("unchecked")
|
||||
HashMap<Integer, String> regNames = (HashMap<Integer, String>) localData.get(0);
|
||||
@SuppressWarnings("unchecked")
|
||||
HashMap<String, GraphTargetItem> variables = (HashMap<String, GraphTargetItem>) localData.get(1);
|
||||
@SuppressWarnings("unchecked")
|
||||
HashMap<String, GraphTargetItem> functions = (HashMap<String, GraphTargetItem>) localData.get(2);
|
||||
List<Object> ret = new ArrayList<>();
|
||||
ret.add(new HashMap<>(regNames));
|
||||
ret.add(new HashMap<>(variables));
|
||||
ret.add(new HashMap<>(functions));
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -21,10 +21,7 @@ import java.util.List;
|
||||
|
||||
public class ConstantPool {
|
||||
|
||||
public List<List<String>> archive = new ArrayList<>();
|
||||
public List<Integer> archiveCounts = new ArrayList<>();
|
||||
public List<String> constants = new ArrayList<>();
|
||||
public int count;
|
||||
|
||||
public ConstantPool() {
|
||||
}
|
||||
@@ -34,31 +31,15 @@ public class ConstantPool {
|
||||
}
|
||||
|
||||
public void setNew(List<String> constants) {
|
||||
archive.add(this.constants);
|
||||
this.constants = constants;
|
||||
archiveCounts.add(count);
|
||||
count = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "" + count + "x " + constants.toString();
|
||||
return "x " + constants.toString();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return constants.isEmpty();
|
||||
}
|
||||
|
||||
public void getLastUsed() {
|
||||
if (count > 0) {
|
||||
return;
|
||||
}
|
||||
for (int i = archive.size() - 1; i >= 0; i--) {
|
||||
if (archiveCounts.get(i) > 0) {
|
||||
count = archiveCounts.get(i);
|
||||
constants = archive.get(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +91,11 @@ public class FunctionActionItem extends ActionItem {
|
||||
}
|
||||
ret += hilight(pname, highlight);
|
||||
}
|
||||
ret += hilight(")", highlight) + "\r\n" + hilight("{", highlight) + "\r\n" + Graph.graphToString(actions, highlight, constants) + hilight("}", highlight);
|
||||
ret += hilight(")", highlight) + "\r\n" + hilight("{", highlight) + "\r\n";
|
||||
ret += Graph.INDENTOPEN + "\r\n";
|
||||
ret += Graph.graphToString(actions, highlight, false, constants);
|
||||
ret += Graph.INDENTCLOSE + "\r\n";
|
||||
ret += hilight("}", highlight);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import com.jpexs.decompiler.flash.action.swf4.RegisterNumber;
|
||||
import com.jpexs.decompiler.flash.helpers.Highlighting;
|
||||
import com.jpexs.decompiler.flash.helpers.collections.MyEntry;
|
||||
import com.jpexs.decompiler.graph.Block;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.SourceGenerator;
|
||||
@@ -173,6 +174,7 @@ public class ClassActionItem extends ActionItem implements Block {
|
||||
}
|
||||
}
|
||||
ret += "\r\n" + hilight("{", highlight) + "\r\n";
|
||||
ret += Graph.INDENTOPEN + "\r\n";
|
||||
|
||||
if (constructor != null) {
|
||||
ret += constructor.toString(highlight, constants) + "\r\n";
|
||||
@@ -196,6 +198,7 @@ public class ClassActionItem extends ActionItem implements Block {
|
||||
ret += hilight("static ", highlight) + f.toString(highlight, constants) + "\r\n";
|
||||
}
|
||||
|
||||
ret += Graph.INDENTCLOSE + "\r\n";
|
||||
ret += hilight("}", highlight) + "\r\n";
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import com.jpexs.decompiler.flash.action.swf5.ActionStoreRegister;
|
||||
import com.jpexs.decompiler.flash.action.swf6.ActionEnumerate2;
|
||||
import com.jpexs.decompiler.flash.ecma.Null;
|
||||
import com.jpexs.decompiler.graph.Block;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.Loop;
|
||||
@@ -66,9 +67,11 @@ public class ForInActionItem extends LoopActionItem implements Block {
|
||||
String ret = "";
|
||||
ret += hilight("loop" + loop.id + ":", highlight) + "\r\n";
|
||||
ret += hilight("for(", highlight) + ((variableName instanceof DirectValueActionItem) && (((DirectValueActionItem) variableName).value instanceof RegisterNumber) ? "var " : "") + stripQuotes(variableName, constants, highlight) + " in " + enumVariable.toString(highlight, constants) + ")\r\n{\r\n";
|
||||
ret += Graph.INDENTOPEN + "\r\n";
|
||||
for (GraphTargetItem ti : commands) {
|
||||
ret += ti.toStringSemicoloned(highlight, constants) + "\r\n";
|
||||
}
|
||||
ret += Graph.INDENTCLOSE + "\r\n";
|
||||
ret += hilight("}", highlight) + "\r\n";
|
||||
ret += hilight(":loop" + loop.id, highlight);
|
||||
return ret;
|
||||
|
||||
+6
-1
@@ -45,7 +45,12 @@ public class IfFrameLoadedActionItem extends ActionItem implements Block {
|
||||
|
||||
@Override
|
||||
public String toString(boolean highlight, ConstantPool constants) {
|
||||
return hilight("ifFrameLoaded(", highlight) + frame.toString(highlight, constants) + hilight(")", highlight) + "\r\n" + hilight("{", highlight) + "\r\n" + Graph.graphToString(actions, highlight, constants) + "}";
|
||||
String ret = hilight("ifFrameLoaded(", highlight) + frame.toString(highlight, constants) + hilight(")", highlight) + "\r\n" + hilight("{", highlight) + "\r\n";
|
||||
ret += Graph.INDENTOPEN + "\r\n";
|
||||
ret += Graph.graphToString(actions, highlight, false, constants);
|
||||
ret += Graph.INDENTCLOSE + "\r\n";
|
||||
ret += hilight("}", highlight);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.action.model.ActionItem;
|
||||
import com.jpexs.decompiler.flash.action.model.ConstantPool;
|
||||
import com.jpexs.decompiler.flash.action.swf3.ActionSetTarget;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionSetTarget2;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.SourceGenerator;
|
||||
@@ -40,9 +41,11 @@ public class TellTargetActionItem extends ActionItem {
|
||||
@Override
|
||||
public String toString(boolean highlight, ConstantPool constants) {
|
||||
String ret = hilight("tellTarget(", highlight) + target.toString(highlight, constants) + hilight(")", highlight) + "\r\n" + hilight("{", highlight) + "\r\n";
|
||||
ret += Graph.INDENTOPEN + "\r\n";
|
||||
for (GraphTargetItem ti : commands) {
|
||||
ret += ti.toString(highlight, constants) + "\r\n";
|
||||
}
|
||||
ret += Graph.INDENTCLOSE + "\r\n";
|
||||
ret += hilight("}", highlight);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.jpexs.decompiler.flash.action.parser.script.ActionSourceGenerator;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionJump;
|
||||
import com.jpexs.decompiler.flash.action.swf7.ActionTry;
|
||||
import com.jpexs.decompiler.graph.Block;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.SourceGenerator;
|
||||
@@ -59,6 +60,7 @@ public class TryActionItem extends ActionItem implements Block {
|
||||
public String toString(boolean highlight, ConstantPool constants) {
|
||||
String ret = "";
|
||||
ret += hilight("try", highlight) + "\r\n" + hilight("{", highlight) + "\r\n";
|
||||
ret += Graph.INDENTOPEN + "\r\n";
|
||||
List<Object> localData = new ArrayList<>();
|
||||
localData.add(constants);
|
||||
for (GraphTargetItem ti : tryCommands) {
|
||||
@@ -66,24 +68,29 @@ public class TryActionItem extends ActionItem implements Block {
|
||||
ret += ti.toStringSemicoloned(highlight, localData) + "\r\n";
|
||||
}
|
||||
}
|
||||
ret += Graph.INDENTCLOSE + "\r\n";
|
||||
ret += hilight("}", highlight);
|
||||
for (int e = 0; e < catchExceptions.size(); e++) {
|
||||
ret += "\r\n" + hilight("catch(", highlight) + catchExceptions.get(e).toStringNoQuotes(highlight, localData) + hilight(")", highlight) + "\r\n" + hilight("{", highlight) + "\r\n";
|
||||
ret += Graph.INDENTOPEN + "\r\n";
|
||||
List<GraphTargetItem> commands = catchCommands.get(e);
|
||||
for (GraphTargetItem ti : commands) {
|
||||
if (!ti.isEmpty()) {
|
||||
ret += ti.toStringSemicoloned(highlight, localData) + "\r\n";
|
||||
}
|
||||
}
|
||||
ret += Graph.INDENTCLOSE + "\r\n";
|
||||
ret += hilight("}", highlight);
|
||||
}
|
||||
if (finallyCommands.size() > 0) {
|
||||
ret += "\r\n" + hilight("finally", highlight) + "\r\n" + hilight("{", highlight) + "\r\n";
|
||||
ret += Graph.INDENTOPEN + "\r\n";
|
||||
for (GraphTargetItem ti : finallyCommands) {
|
||||
if (!ti.isEmpty()) {
|
||||
ret += ti.toStringSemicoloned(highlight, localData) + "\r\n";
|
||||
}
|
||||
}
|
||||
ret += Graph.INDENTCLOSE + "\r\n";
|
||||
ret += hilight("}", highlight);
|
||||
}
|
||||
return ret;
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.action.model.ActionItem;
|
||||
import com.jpexs.decompiler.flash.action.model.ConstantPool;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionWith;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.SourceGenerator;
|
||||
@@ -50,9 +51,11 @@ public class WithActionItem extends ActionItem {
|
||||
List<Object> localData = new ArrayList<>();
|
||||
localData.add(constants);
|
||||
ret = hilight("with(", highlight) + scope.toString(highlight, localData) + hilight(")", highlight) + "\r\n" + hilight("{", highlight) + "\r\n";
|
||||
ret += Graph.INDENTOPEN + "\r\n";
|
||||
for (GraphTargetItem ti : items) {
|
||||
ret += ti.toString(highlight, localData) + "\r\n";
|
||||
}
|
||||
ret += Graph.INDENTCLOSE + "\r\n";
|
||||
ret += hilight("}", highlight);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -377,7 +377,7 @@ public class ASMParser {
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Action> parse(long address, long containerSWFOffset, boolean ignoreNops, String source, int version) throws IOException, ParseException {
|
||||
public static List<Action> parse(long address, long containerSWFOffset, boolean ignoreNops, String source, int version, boolean throwOnError) throws IOException, ParseException {
|
||||
FlasmLexer lexer = new FlasmLexer(new StringReader(source));
|
||||
List<Action> list = parseAllActions(lexer, version);
|
||||
|
||||
@@ -421,7 +421,11 @@ public class ASMParser {
|
||||
}
|
||||
if ((link instanceof ActionJump) || (link instanceof ActionIf)) {
|
||||
if (!found) {
|
||||
Logger.getLogger(ASMParser.class.getName()).log(Level.SEVERE, "TARGET NOT FOUND - identifier:" + identifier + " addr: ofs" + Helper.formatAddress(link.getAddress()));
|
||||
if (throwOnError) {
|
||||
throw new ParseException("TARGET NOT FOUND - identifier:" + identifier + " addr: ofs" + Helper.formatAddress(link.getAddress()), -1);
|
||||
} else {
|
||||
Logger.getLogger(ASMParser.class.getName()).log(Level.SEVERE, "TARGET NOT FOUND - identifier:" + identifier + " addr: ofs" + Helper.formatAddress(link.getAddress()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,8 +38,8 @@ public class ActionGotoFrame extends Action {
|
||||
this.frame = frame;
|
||||
}
|
||||
|
||||
public ActionGotoFrame(SWFInputStream sis) throws IOException {
|
||||
super(0x81, 2);
|
||||
public ActionGotoFrame(int actionLength, SWFInputStream sis) throws IOException {
|
||||
super(0x81, actionLength);
|
||||
frame = sis.readUI16();
|
||||
}
|
||||
|
||||
|
||||
@@ -30,10 +30,8 @@ import com.jpexs.decompiler.flash.action.parser.ParseException;
|
||||
import com.jpexs.decompiler.flash.action.parser.pcode.FlasmLexer;
|
||||
import com.jpexs.decompiler.flash.action.special.ActionEnd;
|
||||
import com.jpexs.decompiler.flash.action.special.ActionStore;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionPush;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
@@ -47,12 +45,12 @@ public class ActionWaitForFrame extends Action implements ActionStore {
|
||||
public int skipCount;
|
||||
public List<Action> skipped;
|
||||
|
||||
public ActionWaitForFrame(SWFInputStream sis, ConstantPool cpool) throws IOException {
|
||||
super(0x8A, 3);
|
||||
public ActionWaitForFrame(int actionLength, SWFInputStream sis, ConstantPool cpool) throws IOException {
|
||||
super(0x8A, actionLength);
|
||||
frame = sis.readUI16();
|
||||
skipCount = sis.readUI8();
|
||||
skipped = new ArrayList<>();
|
||||
for (int i = 0; i < skipCount; i++) {
|
||||
/*for (int i = 0; i < skipCount; i++) {
|
||||
Action a = sis.readAction(cpool);
|
||||
if (a instanceof ActionEnd) {
|
||||
skipCount = i;
|
||||
@@ -65,7 +63,6 @@ public class ActionWaitForFrame extends Action implements ActionStore {
|
||||
if (a instanceof ActionPush) {
|
||||
if (cpool != null) {
|
||||
((ActionPush) a).constantPool = cpool.constants;
|
||||
cpool.count++;
|
||||
}
|
||||
}
|
||||
skipped.add(a);
|
||||
@@ -85,7 +82,7 @@ public class ActionWaitForFrame extends Action implements ActionStore {
|
||||
}
|
||||
}
|
||||
skipCount = skipped.size();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -29,6 +29,10 @@ public class ActionCall extends Action {
|
||||
super(0x9E, 0);
|
||||
}
|
||||
|
||||
public ActionCall(int actionLength) {
|
||||
super(0x9E, actionLength);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Call";
|
||||
|
||||
@@ -56,8 +56,8 @@ public class ActionGetURL2 extends Action {
|
||||
this.sendVarsMethod = sendVarsMethod;
|
||||
}
|
||||
|
||||
public ActionGetURL2(SWFInputStream sis) throws IOException {
|
||||
super(0x9A, 1);
|
||||
public ActionGetURL2(int actionLength, SWFInputStream sis) throws IOException {
|
||||
super(0x9A, actionLength);
|
||||
loadVariablesFlag = sis.readUB(1) == 1;
|
||||
loadTargetFlag = sis.readUB(1) == 1;
|
||||
sis.readUB(4); //reserved
|
||||
|
||||
@@ -53,8 +53,8 @@ public class ActionIf extends Action {
|
||||
setJumpOffset(offset);
|
||||
}
|
||||
|
||||
public ActionIf(SWFInputStream sis) throws IOException {
|
||||
super(0x9D, 2);
|
||||
public ActionIf(int actionLength, SWFInputStream sis) throws IOException {
|
||||
super(0x9D, actionLength);
|
||||
setJumpOffset(sis.readSI16());
|
||||
}
|
||||
|
||||
|
||||
@@ -52,8 +52,8 @@ public class ActionJump extends Action {
|
||||
setJumpOffset(offset);
|
||||
}
|
||||
|
||||
public ActionJump(SWFInputStream sis) throws IOException {
|
||||
super(0x99, 2);
|
||||
public ActionJump(int actionLength, SWFInputStream sis) throws IOException {
|
||||
super(0x99, actionLength);
|
||||
setJumpOffset(sis.readSI16());
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ public class ActionWaitForFrame2 extends Action implements ActionStore {
|
||||
public ActionWaitForFrame2(int skipCount) {
|
||||
super(0x8D, 1);
|
||||
this.skipCount = skipCount;
|
||||
skipped = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -60,11 +61,11 @@ public class ActionWaitForFrame2 extends Action implements ActionStore {
|
||||
skipCount = store.size();
|
||||
}
|
||||
|
||||
public ActionWaitForFrame2(SWFInputStream sis, ConstantPool cpool) throws IOException {
|
||||
super(0x8D, 1);
|
||||
public ActionWaitForFrame2(int actionLength, SWFInputStream sis, ConstantPool cpool) throws IOException {
|
||||
super(0x8D, actionLength);
|
||||
skipCount = sis.readUI8();
|
||||
skipped = new ArrayList<>();
|
||||
for (int i = 0; i < skipCount; i++) {
|
||||
/*for (int i = 0; i < skipCount; i++) {
|
||||
Action a = sis.readAction(cpool);
|
||||
if (a instanceof ActionEnd) {
|
||||
skipCount = i;
|
||||
@@ -91,12 +92,13 @@ public class ActionWaitForFrame2 extends Action implements ActionStore {
|
||||
}
|
||||
}
|
||||
skipCount = skipped.size();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
public ActionWaitForFrame2(FlasmLexer lexer) throws IOException, ParseException {
|
||||
super(0x8D, -1);
|
||||
skipCount = (int) lexLong(lexer);
|
||||
skipped = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -227,6 +227,15 @@ public class ActionDefineFunction extends Action implements GraphSourceItemConta
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContainerSize(int index, long size) {
|
||||
if (index == 0) {
|
||||
codeSize = (int) size;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Index must be 0.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getASMSourceBetween(int pos) {
|
||||
return "";
|
||||
|
||||
@@ -48,8 +48,8 @@ public class ActionStoreRegister extends Action implements StoreTypeAction {
|
||||
this.registerNumber = registerNumber;
|
||||
}
|
||||
|
||||
public ActionStoreRegister(SWFInputStream sis) throws IOException {
|
||||
super(0x87, 1);
|
||||
public ActionStoreRegister(int actionLength, SWFInputStream sis) throws IOException {
|
||||
super(0x87, actionLength);
|
||||
registerNumber = sis.readUI8();
|
||||
}
|
||||
|
||||
|
||||
@@ -50,8 +50,8 @@ public class ActionWith extends Action implements GraphSourceItemContainer {
|
||||
return false;
|
||||
}
|
||||
|
||||
public ActionWith(SWFInputStream sis, ReReadableInputStream rri, int version) throws IOException {
|
||||
super(0x94, 2);
|
||||
public ActionWith(int actionLength, SWFInputStream sis, ReReadableInputStream rri, int version) throws IOException {
|
||||
super(0x94, actionLength);
|
||||
codeSize = sis.readUI16();
|
||||
this.version = version;
|
||||
}
|
||||
@@ -107,6 +107,16 @@ public class ActionWith extends Action implements GraphSourceItemContainer {
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContainerSize(int index, long size) {
|
||||
if (index == 0) {
|
||||
codeSize = (int) size;
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Index must be 0.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getASMSourceBetween(int pos) {
|
||||
return "";
|
||||
|
||||
@@ -362,6 +362,15 @@ public class ActionDefineFunction2 extends Action implements GraphSourceItemCont
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContainerSize(int index, long size) {
|
||||
if (index == 0) {
|
||||
codeSize = (int) size;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Index must be 0.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean parseDivision(long size, FlasmLexer lexer) {
|
||||
codeSize = (int) (size - getHeaderSize());
|
||||
|
||||
@@ -206,6 +206,10 @@ public class ActionTry extends Action implements GraphSourceItemContainer {
|
||||
return surroundWithAction(baos.toByteArray(), version).length;
|
||||
}
|
||||
|
||||
public long getTrySize() {
|
||||
return trySize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> getContainerSizes() {
|
||||
List<Long> ret = new ArrayList<>();
|
||||
@@ -215,6 +219,23 @@ public class ActionTry extends Action implements GraphSourceItemContainer {
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContainerSize(int index, long size) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
trySize = size;
|
||||
break;
|
||||
case 1:
|
||||
catchSize = size;
|
||||
break;
|
||||
case 2:
|
||||
finallySize = size;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Valid indexes are 0, 1, and 2.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean parseDivision(long size, FlasmLexer lexer) {
|
||||
try {
|
||||
|
||||
@@ -83,6 +83,7 @@ import com.jpexs.decompiler.flash.tags.base.AloneTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.Container;
|
||||
import com.jpexs.decompiler.flash.tags.base.ContainerItem;
|
||||
import com.jpexs.decompiler.flash.tags.base.DrawableTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.FontTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ImageTag;
|
||||
@@ -149,6 +150,7 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -793,7 +795,7 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
|
||||
|
||||
//setJMenuBar(menuBar);
|
||||
|
||||
List<Object> objs = new ArrayList<>();
|
||||
List<ContainerItem> objs = new ArrayList<>();
|
||||
if (swf != null) {
|
||||
objs.addAll(swf.tags);
|
||||
}
|
||||
@@ -958,16 +960,29 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
|
||||
if (SwingUtilities.isRightMouseButton(e)) {
|
||||
|
||||
int row = tagTree.getClosestRowForLocation(e.getX(), e.getY());
|
||||
tagTree.setSelectionRow(row);
|
||||
Object tagObj = tagTree.getLastSelectedPathComponent();
|
||||
if (tagObj == null) {
|
||||
int[] selectionRows = tagTree.getSelectionRows();
|
||||
if (!Helper.contains(selectionRows, row)) {
|
||||
tagTree.setSelectionRow(row);
|
||||
}
|
||||
|
||||
TreePath[] paths = tagTree.getSelectionPaths();
|
||||
if (paths == null || paths.length == 0) {
|
||||
return;
|
||||
}
|
||||
boolean allSelectedIsTag = true;
|
||||
for (TreePath treePath : paths) {
|
||||
Object tagObj = treePath.getLastPathComponent();
|
||||
|
||||
if (tagObj instanceof TagNode) {
|
||||
tagObj = ((TagNode) tagObj).tag;
|
||||
if (tagObj instanceof TagNode) {
|
||||
Object tag = ((TagNode) tagObj).tag;
|
||||
if (!(tag instanceof Tag)) {
|
||||
allSelectedIsTag = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
removeMenuItem.setVisible(tagObj instanceof Tag);
|
||||
|
||||
removeMenuItem.setVisible(allSelectedIsTag);
|
||||
contextPopupMenu.show(e.getComponent(), e.getX(), e.getY());
|
||||
}
|
||||
}
|
||||
@@ -1050,7 +1065,7 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
|
||||
}
|
||||
}
|
||||
characters = new HashMap<>();
|
||||
List<Object> list2 = new ArrayList<>();
|
||||
List<ContainerItem> list2 = new ArrayList<>();
|
||||
if (swf != null) {
|
||||
list2.addAll(swf.tags);
|
||||
}
|
||||
@@ -1649,8 +1664,8 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
|
||||
}
|
||||
}
|
||||
|
||||
private void parseCharacters(List<Object> list) {
|
||||
for (Object t : list) {
|
||||
private void parseCharacters(List<ContainerItem> list) {
|
||||
for (ContainerItem t : list) {
|
||||
if (t instanceof CharacterTag) {
|
||||
characters.put(((CharacterTag) t).getCharacterId(), (CharacterTag) t);
|
||||
}
|
||||
@@ -1660,8 +1675,8 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
|
||||
}
|
||||
}
|
||||
|
||||
public static void getShapes(List<Object> list, List<Tag> shapes) {
|
||||
for (Object t : list) {
|
||||
public static void getShapes(List<ContainerItem> list, List<Tag> shapes) {
|
||||
for (ContainerItem t : list) {
|
||||
if (t instanceof Container) {
|
||||
getShapes(((Container) t).getSubItems(), shapes);
|
||||
}
|
||||
@@ -1674,8 +1689,8 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
|
||||
}
|
||||
}
|
||||
|
||||
public static void getFonts(List<Object> list, List<Tag> fonts) {
|
||||
for (Object t : list) {
|
||||
public static void getFonts(List<ContainerItem> list, List<Tag> fonts) {
|
||||
for (ContainerItem t : list) {
|
||||
if (t instanceof Container) {
|
||||
getFonts(((Container) t).getSubItems(), fonts);
|
||||
}
|
||||
@@ -1688,8 +1703,8 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
|
||||
}
|
||||
}
|
||||
|
||||
public static void getActionScript3(List<Object> list, List<ABCContainerTag> actionScripts) {
|
||||
for (Object t : list) {
|
||||
public static void getActionScript3(List<ContainerItem> list, List<ABCContainerTag> actionScripts) {
|
||||
for (ContainerItem t : list) {
|
||||
if (t instanceof Container) {
|
||||
getActionScript3(((Container) t).getSubItems(), actionScripts);
|
||||
}
|
||||
@@ -1699,8 +1714,8 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
|
||||
}
|
||||
}
|
||||
|
||||
public static void getMorphShapes(List<Object> list, List<Tag> morphShapes) {
|
||||
for (Object t : list) {
|
||||
public static void getMorphShapes(List<ContainerItem> list, List<Tag> morphShapes) {
|
||||
for (ContainerItem t : list) {
|
||||
if (t instanceof Container) {
|
||||
getMorphShapes(((Container) t).getSubItems(), morphShapes);
|
||||
}
|
||||
@@ -1710,8 +1725,8 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
|
||||
}
|
||||
}
|
||||
|
||||
public static void getImages(List<Object> list, List<Tag> images) {
|
||||
for (Object t : list) {
|
||||
public static void getImages(List<ContainerItem> list, List<Tag> images) {
|
||||
for (ContainerItem t : list) {
|
||||
if (t instanceof Container) {
|
||||
getImages(((Container) t).getSubItems(), images);
|
||||
}
|
||||
@@ -1726,8 +1741,8 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
|
||||
}
|
||||
}
|
||||
|
||||
public static void getTexts(List<Object> list, List<Tag> texts) {
|
||||
for (Object t : list) {
|
||||
public static void getTexts(List<ContainerItem> list, List<Tag> texts) {
|
||||
for (ContainerItem t : list) {
|
||||
if (t instanceof Container) {
|
||||
getTexts(((Container) t).getSubItems(), texts);
|
||||
}
|
||||
@@ -1739,8 +1754,8 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
|
||||
}
|
||||
}
|
||||
|
||||
public static void getSprites(List<Object> list, List<Tag> sprites) {
|
||||
for (Object t : list) {
|
||||
public static void getSprites(List<ContainerItem> list, List<Tag> sprites) {
|
||||
for (ContainerItem t : list) {
|
||||
if (t instanceof Container) {
|
||||
getSprites(((Container) t).getSubItems(), sprites);
|
||||
}
|
||||
@@ -1750,8 +1765,8 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
|
||||
}
|
||||
}
|
||||
|
||||
public static void getButtons(List<Object> list, List<Tag> buttons) {
|
||||
for (Object t : list) {
|
||||
public static void getButtons(List<ContainerItem> list, List<Tag> buttons) {
|
||||
for (ContainerItem t : list) {
|
||||
if (t instanceof Container) {
|
||||
getButtons(((Container) t).getSubItems(), buttons);
|
||||
}
|
||||
@@ -1859,10 +1874,10 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
|
||||
return ret;
|
||||
}
|
||||
|
||||
public List<TagNode> getTagNodesWithType(List<Object> list, String type, Object parent, boolean display) {
|
||||
public List<TagNode> getTagNodesWithType(List<? extends ContainerItem> list, String type, Object parent, boolean display) {
|
||||
List<TagNode> ret = new ArrayList<>();
|
||||
int frameCnt = 0;
|
||||
for (Object o : list) {
|
||||
for (ContainerItem o : list) {
|
||||
String ttype = getTagType(o);
|
||||
if ("showframe".equals(ttype) && "frame".equals(type)) {
|
||||
frameCnt++;
|
||||
@@ -1921,6 +1936,21 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
|
||||
}
|
||||
}
|
||||
|
||||
public List<Object> getSelected(JTree tree) {
|
||||
TreeSelectionModel tsm = tree.getSelectionModel();
|
||||
TreePath tps[] = tsm.getSelectionPaths();
|
||||
List<Object> ret = new ArrayList<>();
|
||||
if (tps == null) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (TreePath tp : tps) {
|
||||
Object o = tp.getLastPathComponent();
|
||||
ret.add(o);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public List<Object> getAllSubs(JTree tree, Object o) {
|
||||
TreeModel tm = tree.getModel();
|
||||
List<Object> ret = new ArrayList<>();
|
||||
@@ -1968,7 +1998,7 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<TagNode> createTagList(List<Object> list, Object parent) {
|
||||
public List<TagNode> createTagList(List<ContainerItem> list, Object parent) {
|
||||
List<TagNode> ret = new ArrayList<>();
|
||||
List<TagNode> frames = getTagNodesWithType(list, "frame", parent, true);
|
||||
List<TagNode> shapes = getTagNodesWithType(list, "shape", parent, true);
|
||||
@@ -1995,7 +2025,7 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
|
||||
}
|
||||
|
||||
for (TagNode n : sprites) {
|
||||
n.subItems = getTagNodesWithType(new ArrayList<Object>(((DefineSpriteTag) n.tag).subTags), "frame", n.tag, true);
|
||||
n.subItems = getTagNodesWithType(((DefineSpriteTag) n.tag).subTags, "frame", n.tag, true);
|
||||
}
|
||||
|
||||
List<ExportAssetsTag> exportAssetsTags = new ArrayList<>();
|
||||
@@ -2010,7 +2040,7 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
|
||||
if (t instanceof Container) {
|
||||
TagNode tti = new TagNode(t);
|
||||
if (((Container) t).getItemCount() > 0) {
|
||||
List<Object> subItems = ((Container) t).getSubItems();
|
||||
List<ContainerItem> subItems = ((Container) t).getSubItems();
|
||||
tti.subItems = createTagList(subItems, t);
|
||||
}
|
||||
//ret.add(tti);
|
||||
@@ -2422,17 +2452,31 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
|
||||
}
|
||||
break;
|
||||
case "REMOVEITEM":
|
||||
tagObj = tagTree.getLastSelectedPathComponent();
|
||||
if (tagObj == null) {
|
||||
return;
|
||||
}
|
||||
List<Object> sel = getSelected(tagTree);
|
||||
|
||||
if (tagObj instanceof TagNode) {
|
||||
tagObj = ((TagNode) tagObj).tag;
|
||||
List<Tag> tagsToRemove = new ArrayList<>();
|
||||
for (Object o : sel) {
|
||||
Object tag = o;
|
||||
if (o instanceof TagNode) {
|
||||
tag = ((TagNode) o).tag;
|
||||
}
|
||||
if (tag instanceof Tag) {
|
||||
tagsToRemove.add((Tag) tag);
|
||||
}
|
||||
}
|
||||
if (tagObj instanceof Tag) {
|
||||
if (View.showConfirmDialog(this, translate("message.confirm.remove").replace("%item%", tagObj.toString()), translate("message.confirm"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {
|
||||
swf.removeTag((Tag) tagObj);
|
||||
|
||||
if (tagsToRemove.size() == 1) {
|
||||
Tag tag = tagsToRemove.get(0);
|
||||
if (View.showConfirmDialog(this, translate("message.confirm.remove").replace("%item%", tag.toString()), translate("message.confirm"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {
|
||||
swf.removeTag(tag);
|
||||
showCard(CARDEMPTYPANEL);
|
||||
refreshTree();
|
||||
}
|
||||
} else if (tagsToRemove.size() > 1) {
|
||||
if (View.showConfirmDialog(this, translate("message.confirm.removemultiple").replace("%count%", Integer.toString(tagsToRemove.size())), translate("message.confirm"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {
|
||||
for (Tag tag : tagsToRemove) {
|
||||
swf.removeTag(tag);
|
||||
}
|
||||
showCard(CARDEMPTYPANEL);
|
||||
refreshTree();
|
||||
}
|
||||
@@ -3024,13 +3068,13 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
|
||||
DefineVideoStreamTag vs = null;
|
||||
if (tagObj instanceof DefineVideoStreamTag) {
|
||||
vs = (DefineVideoStreamTag) tagObj;
|
||||
swf.populateVideoFrames(vs.getCharacterId(), new ArrayList<Object>(swf.tags), videoFrames);
|
||||
swf.populateVideoFrames(vs.getCharacterId(), swf.tags, videoFrames);
|
||||
frameCount = videoFrames.size();
|
||||
}
|
||||
|
||||
List<SoundStreamBlockTag> soundFrames = new ArrayList<>();
|
||||
if (tagObj instanceof SoundStreamHeadTypeTag) {
|
||||
SWF.populateSoundStreamBlocks(new ArrayList<Object>(swf.tags), (Tag) tagObj, soundFrames);
|
||||
SWF.populateSoundStreamBlocks(swf.tags, (Tag) tagObj, soundFrames);
|
||||
frameCount = soundFrames.size();
|
||||
}
|
||||
|
||||
@@ -3077,7 +3121,7 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
|
||||
if (tagObj instanceof FrameNode) {
|
||||
FrameNode fn = (FrameNode) tagObj;
|
||||
Object parent = fn.getParent();
|
||||
List<Object> subs = new ArrayList<>();
|
||||
List<ContainerItem> subs = new ArrayList<>();
|
||||
if (parent == null) {
|
||||
subs.addAll(swf.tags);
|
||||
} else {
|
||||
@@ -3236,7 +3280,7 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
|
||||
+ "Push \"start\"\n"
|
||||
+ "CallMethod\n"
|
||||
+ "Pop\n"
|
||||
+ "Stop", SWF.DEFAULT_VERSION);
|
||||
+ "Stop", SWF.DEFAULT_VERSION, false);
|
||||
doa.setActions(actions, SWF.DEFAULT_VERSION);
|
||||
sos2.writeTag(doa);
|
||||
sos2.writeTag(new ShowFrameTag(null));
|
||||
@@ -3322,11 +3366,69 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
|
||||
}
|
||||
|
||||
public void refreshTree() {
|
||||
List<Object> objs = new ArrayList<>();
|
||||
List<ContainerItem> objs = new ArrayList<>();
|
||||
objs.addAll(swf.tags);
|
||||
|
||||
List<List<String>> expandedNodes = getExpandedNodes(tagTree);
|
||||
|
||||
tagTree.setModel(new TagTreeModel(createTagList(objs, null), new SWFRoot((new File(Main.file)).getName())));
|
||||
|
||||
expandTreeNodes(tagTree, expandedNodes);
|
||||
}
|
||||
|
||||
private List<List<String>> getExpandedNodes(JTree tree) {
|
||||
List<List<String>> expandedNodes = new ArrayList<>();
|
||||
int rowCount = tree.getRowCount();
|
||||
for (int i = 0; i < rowCount; i++){
|
||||
TreePath path = tree.getPathForRow(i);
|
||||
if (tree.isExpanded(path)) {
|
||||
List<String> pathAsStringList = new ArrayList<>();
|
||||
for (Object pathCompnent : path.getPath()) {
|
||||
pathAsStringList.add(pathCompnent.toString());
|
||||
}
|
||||
expandedNodes.add(pathAsStringList);
|
||||
}
|
||||
}
|
||||
return expandedNodes;
|
||||
}
|
||||
|
||||
private void expandTreeNodes(JTree tree, List<List<String>> pathsToExpand) {
|
||||
for(List<String> pathAsStringList : pathsToExpand) {
|
||||
expandTreeNode(tree, pathAsStringList);
|
||||
}
|
||||
}
|
||||
|
||||
private void expandTreeNode(JTree tree, List<String> pathAsStringList) {
|
||||
TreeModel model = tree.getModel();
|
||||
Object node = model.getRoot();
|
||||
|
||||
if (pathAsStringList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (!pathAsStringList.get(0).equals(node.toString())) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Object> path = new ArrayList<>();
|
||||
path.add(node);
|
||||
|
||||
for (int i = 1; i < pathAsStringList.size(); i++) {
|
||||
String name = pathAsStringList.get(i);
|
||||
int childCount = model.getChildCount(node);
|
||||
for (int j = 0; j < childCount; j++) {
|
||||
Object child = model.getChild(node, j);
|
||||
if (child.toString().equals(name)) {
|
||||
node = child;
|
||||
path.add(node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TreePath tp = new TreePath(path.toArray(new Object[path.size()]));
|
||||
tree.expandPath(tp);
|
||||
}
|
||||
|
||||
public void setEditText(boolean edit) {
|
||||
textValue.setEditable(edit);
|
||||
textSaveButton.setVisible(edit);
|
||||
|
||||
@@ -49,13 +49,14 @@ import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Scanner;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -89,6 +90,7 @@ public class ActionPanel extends JPanel implements ActionListener {
|
||||
public JButton saveDecompiledButton = new JButton(translate("button.save"), View.getIcon("save16"));
|
||||
public JButton cancelDecompiledButton = new JButton(translate("button.cancel"), View.getIcon("cancel16"));
|
||||
public JToggleButton hexButton;
|
||||
public JToggleButton hexOnlyButton;
|
||||
public JLabel asmLabel = new HeaderLabel(translate("panel.disassembled"));
|
||||
public JLabel decLabel = new HeaderLabel(translate("panel.decompiled"));
|
||||
public List<Highlighting> decompiledHilights = new ArrayList<>();
|
||||
@@ -102,6 +104,7 @@ public class ActionPanel extends JPanel implements ActionListener {
|
||||
public JPanel topButtonsPan;
|
||||
private String srcWithHex;
|
||||
private String srcNoHex;
|
||||
private String srcHexOnly;
|
||||
private String lastDecompiled = "";
|
||||
private ASMSource lastASM;
|
||||
public JPanel searchPanel;
|
||||
@@ -199,8 +202,7 @@ public class ActionPanel extends JPanel implements ActionListener {
|
||||
if ((txt != null) && (!txt.equals(""))) {
|
||||
searchIgnoreCase = ignoreCase;
|
||||
searchRegexp = regexp;
|
||||
List<Object> tags = new ArrayList<Object>(Main.swf.tags);
|
||||
List<TagNode> list = Main.swf.createASTagList(tags, null);
|
||||
List<TagNode> list = Main.swf.createASTagList(Main.swf.tags, null);
|
||||
Map<String, ASMSource> asms = getASMs("", list);
|
||||
found = new ArrayList<>();
|
||||
Pattern pat = null;
|
||||
@@ -272,8 +274,8 @@ public class ActionPanel extends JPanel implements ActionListener {
|
||||
|
||||
}
|
||||
|
||||
public void setHex(boolean hex) {
|
||||
setText(hex ? srcWithHex : srcNoHex);
|
||||
public void setHex(boolean hex, boolean hexOnly) {
|
||||
setText(hex ? srcWithHex : (hexOnly ? srcHexOnly : srcNoHex));
|
||||
}
|
||||
|
||||
public void setSource(ASMSource src, final boolean useCache) {
|
||||
@@ -309,7 +311,8 @@ public class ActionPanel extends JPanel implements ActionListener {
|
||||
asm.removeDisassemblyListener(listener);
|
||||
srcWithHex = Helper.hexToComments(lastDisasm);
|
||||
srcNoHex = Helper.stripComments(lastDisasm);
|
||||
setHex(hexButton.isSelected());
|
||||
srcHexOnly = getHexText(srcWithHex);
|
||||
setHex(hexButton.isSelected(), hexOnlyButton.isSelected());
|
||||
if (Configuration.getConfig("decompile", true)) {
|
||||
decompiledEditor.setText("//" + translate("work.decompiling") + "...");
|
||||
String stripped = "";
|
||||
@@ -378,10 +381,19 @@ public class ActionPanel extends JPanel implements ActionListener {
|
||||
hexButton.setToolTipText(translate("button.viewhex"));
|
||||
hexButton.setMargin(new Insets(3, 3, 3, 3));
|
||||
|
||||
// todo: find icon, and set visible
|
||||
hexOnlyButton = new JToggleButton(View.getIcon("hex16"));
|
||||
hexOnlyButton.setActionCommand("HEXONLY");
|
||||
hexOnlyButton.addActionListener(this);
|
||||
hexOnlyButton.setToolTipText(translate("button.viewhex"));
|
||||
hexOnlyButton.setMargin(new Insets(3, 3, 3, 3));
|
||||
hexOnlyButton.setVisible(false);
|
||||
|
||||
topButtonsPan = new JPanel();
|
||||
topButtonsPan.setLayout(new BoxLayout(topButtonsPan, BoxLayout.X_AXIS));
|
||||
topButtonsPan.add(graphButton);
|
||||
topButtonsPan.add(hexButton);
|
||||
topButtonsPan.add(hexOnlyButton);
|
||||
JPanel panCode = new JPanel(new BorderLayout());
|
||||
panCode.add(new JScrollPane(editor), BorderLayout.CENTER);
|
||||
panCode.add(topButtonsPan, BorderLayout.NORTH);
|
||||
@@ -548,8 +560,11 @@ public class ActionPanel extends JPanel implements ActionListener {
|
||||
}
|
||||
|
||||
public void setEditMode(boolean val) {
|
||||
// todo: create UI for editing raw data
|
||||
final boolean rawEdit = false;
|
||||
|
||||
if (val) {
|
||||
setText(srcNoHex);
|
||||
setText(rawEdit ? srcHexOnly : srcNoHex);
|
||||
editor.setEditable(true);
|
||||
saveButton.setVisible(true);
|
||||
editButton.setVisible(false);
|
||||
@@ -640,13 +655,19 @@ public class ActionPanel extends JPanel implements ActionListener {
|
||||
} else if (e.getActionCommand().equals("EDITACTION")) {
|
||||
setEditMode(true);
|
||||
} else if (e.getActionCommand().equals("HEX")) {
|
||||
setHex(hexButton.isSelected());
|
||||
setHex(hexButton.isSelected(), hexOnlyButton.isSelected());
|
||||
} else if (e.getActionCommand().equals("CANCELACTION")) {
|
||||
setEditMode(false);
|
||||
setHex(hexButton.isSelected());
|
||||
setHex(hexButton.isSelected(), hexOnlyButton.isSelected());
|
||||
} else if (e.getActionCommand().equals("SAVEACTION")) {
|
||||
try {
|
||||
src.setActions(ASMParser.parse(0, src.getPos(), true, editor.getText(), SWF.DEFAULT_VERSION), SWF.DEFAULT_VERSION);
|
||||
String text = editor.getText();
|
||||
if (text.trim().startsWith("#hexdata")) {
|
||||
src.setActionBytes(getBytesFromHexaText(text));
|
||||
}
|
||||
else {
|
||||
src.setActions(ASMParser.parse(0, src.getPos(), true, text, SWF.DEFAULT_VERSION, false), SWF.DEFAULT_VERSION);
|
||||
}
|
||||
setSource(this.src, false);
|
||||
View.showMessageDialog(this, translate("message.action.saved"));
|
||||
saveButton.setVisible(false);
|
||||
@@ -678,6 +699,53 @@ public class ActionPanel extends JPanel implements ActionListener {
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getBytesFromHexaText(String text) {
|
||||
Scanner scanner = new Scanner(text);
|
||||
scanner.nextLine(); // ignore first line
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
while (scanner.hasNextLine()) {
|
||||
String line = scanner.nextLine().trim();
|
||||
if (line.startsWith(";")) {
|
||||
continue;
|
||||
}
|
||||
line = line.replace(" ", "");
|
||||
for (int i = 0; i < line.length() / 2; i++) {
|
||||
String hexStr = line.substring(i * 2, (i + 1) * 2);
|
||||
byte b = (byte)Integer.parseInt(hexStr, 16);
|
||||
baos.write(b);
|
||||
}
|
||||
}
|
||||
byte[] data = baos.toByteArray();
|
||||
return data;
|
||||
}
|
||||
|
||||
private String getHexText(String srcWithHex) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
String nl = System.getProperty("line.separator");
|
||||
result.append("#hexdata").append(nl);
|
||||
|
||||
/* // hex data from decompiled actions
|
||||
Scanner scanner = new Scanner(srcWithHex);
|
||||
while (scanner.hasNextLine()) {
|
||||
String line = scanner.nextLine().trim();
|
||||
if (line.startsWith(";")) {
|
||||
result.append(line.substring(1).trim()).append(nl);
|
||||
} else {
|
||||
result.append(";").append(line).append(nl);
|
||||
}
|
||||
}*/
|
||||
|
||||
byte[] data = src.getActionBytes();
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
if (i % 8 == 0) {
|
||||
result.append(nl);
|
||||
}
|
||||
result.append(String.format("%02x ", data[i]));
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public void updateSearchPos() {
|
||||
searchPos.setText((foundPos + 1) + "/" + found.size());
|
||||
setSource(found.get(foundPos), true);
|
||||
|
||||
@@ -350,4 +350,6 @@ ColorChooser.sampleText=Sample Text Sample Text
|
||||
#after version 1.7.1:
|
||||
preview.play = Play
|
||||
preview.pause = Pause
|
||||
preview.stop = Stop
|
||||
preview.stop = Stop
|
||||
|
||||
message.confirm.removemultiple = Are you sure you want to remove %count% items\n and all objects which depend on it?
|
||||
|
||||
@@ -350,4 +350,11 @@ ColorChooser.resetText = Alaphelyzet
|
||||
ColorChooser.previewText = El\u0151n\u00e9zet
|
||||
ColorChooser.swatchesNameText = Mint\u00e1k
|
||||
ColorChooser.swatchesRecentText = El\u0151zm\u00e9nyek:
|
||||
ColorChooser.sampleText=Minta Sz\u00f6veg Minta Sz\u00f6veg
|
||||
ColorChooser.sampleText=Minta Sz\u00f6veg Minta Sz\u00f6veg
|
||||
|
||||
#after version 1.7.1:
|
||||
preview.play = Lej\u00e1tsz\u00e1s
|
||||
preview.pause = Sz\u00fcnet
|
||||
preview.stop = Meg\u00e1ll\u00edt\u00e1s
|
||||
|
||||
message.confirm.removemultiple = Biztos benne, hogy t\u00f6r\u00f6lni k\u00edv\u00e1nja a %count% elemet\n \u00e9s az \u00f6sszes t\u0151le f\u00fcgg\u0151 objektumot ?
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.jpexs.decompiler.flash.tags.base.BoundedTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ButtonTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.Container;
|
||||
import com.jpexs.decompiler.flash.tags.base.ContainerItem;
|
||||
import com.jpexs.decompiler.flash.types.BUTTONCONDACTION;
|
||||
import com.jpexs.decompiler.flash.types.BUTTONRECORD;
|
||||
import com.jpexs.decompiler.flash.types.MATRIX;
|
||||
@@ -177,8 +178,8 @@ public class DefineButton2Tag extends CharacterTag implements Container, Bounded
|
||||
* @return List of sub-items
|
||||
*/
|
||||
@Override
|
||||
public List<Object> getSubItems() {
|
||||
List<Object> ret = new ArrayList<>();
|
||||
public List<ContainerItem> getSubItems() {
|
||||
List<ContainerItem> ret = new ArrayList<>();
|
||||
ret.addAll(actions);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.abc.CopyOutputStream;
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.action.ActionListReader;
|
||||
import com.jpexs.decompiler.flash.tags.base.ASMSource;
|
||||
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ButtonTag;
|
||||
@@ -169,11 +170,7 @@ public class DefineButtonTag extends CharacterTag implements ASMSource, BoundedT
|
||||
ReReadableInputStream rri = new ReReadableInputStream(new ByteArrayInputStream(baos.toByteArray()));
|
||||
rri.setPos(prevLength);
|
||||
|
||||
boolean deobfuscate = Configuration.getConfig("autoDeobfuscate", true);
|
||||
List<Action> list = SWFInputStream.readActionList(listeners, getPos() + hdrSize - prevLength, rri, version, prevLength, -1, toString()/*FIXME?*/);
|
||||
if (deobfuscate) {
|
||||
list = Action.removeNops(0, list, version, getPos() + hdrSize, toString()/*FIXME?*/);
|
||||
}
|
||||
List<Action> list = ActionListReader.readActionList(listeners, getPos() + hdrSize - prevLength, rri, version, prevLength, -1, toString()/*FIXME?*/);
|
||||
return list;
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(DoActionTag.class.getName()).log(Level.SEVERE, null, ex);
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.jpexs.decompiler.flash.abc.CopyOutputStream;
|
||||
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.Container;
|
||||
import com.jpexs.decompiler.flash.tags.base.ContainerItem;
|
||||
import com.jpexs.decompiler.flash.tags.base.DrawableTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag;
|
||||
import com.jpexs.decompiler.flash.types.MATRIX;
|
||||
@@ -234,8 +235,8 @@ public class DefineSpriteTag extends CharacterTag implements Container, BoundedT
|
||||
* @return List of sub-items
|
||||
*/
|
||||
@Override
|
||||
public List<Object> getSubItems() {
|
||||
List<Object> ret = new ArrayList<>();
|
||||
public List<ContainerItem> getSubItems() {
|
||||
List<ContainerItem> ret = new ArrayList<>();
|
||||
ret.addAll(subTags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.action.ActionListReader;
|
||||
import com.jpexs.decompiler.flash.tags.base.ASMSource;
|
||||
import com.jpexs.helpers.ReReadableInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
@@ -115,11 +116,7 @@ public class DoActionTag extends Tag implements ASMSource {
|
||||
baos.write(actionBytes);
|
||||
ReReadableInputStream rri = new ReReadableInputStream(new ByteArrayInputStream(baos.toByteArray()));
|
||||
rri.setPos(prevLength);
|
||||
boolean deobfuscate = Configuration.getConfig("autoDeobfuscate", true);
|
||||
List<Action> list = SWFInputStream.readActionList(listeners, getPos() - prevLength, rri, version, prevLength, -1, toString()/*FIXME?*/);
|
||||
if (deobfuscate) {
|
||||
list = Action.removeNops(0, list, version, getPos(), toString()/*FIXME?*/);
|
||||
}
|
||||
List<Action> list = ActionListReader.readActionList(listeners, getPos() - prevLength, rri, version, prevLength, -1, toString()/*FIXME?*/);
|
||||
return list;
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(DoActionTag.class.getName()).log(Level.SEVERE, null, ex);
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.action.ActionListReader;
|
||||
import com.jpexs.decompiler.flash.tags.base.ASMSource;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterIdTag;
|
||||
import com.jpexs.helpers.Helper;
|
||||
@@ -124,11 +125,7 @@ public class DoInitActionTag extends CharacterIdTag implements ASMSource {
|
||||
baos.write(actionBytes);
|
||||
ReReadableInputStream rri = new ReReadableInputStream(new ByteArrayInputStream(baos.toByteArray()));
|
||||
rri.setPos(prevLength);
|
||||
boolean deobfuscate = Configuration.getConfig("autoDeobfuscate", true);
|
||||
List<Action> list = SWFInputStream.readActionList(listeners, getPos() + 2 - prevLength, rri, version, prevLength, -1, toString()/*FIXME?*/);
|
||||
if (deobfuscate) {
|
||||
list = Action.removeNops(0, list, version, getPos() + 2, toString()/*FIXME?*/);
|
||||
}
|
||||
List<Action> list = ActionListReader.readActionList(listeners, getPos() + 2 - prevLength, rri, version, prevLength, -1, toString()/*FIXME?*/);
|
||||
return list;
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(DoActionTag.class.getName()).log(Level.SEVERE, null, ex);
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.abc.CopyOutputStream;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterIdTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.Container;
|
||||
import com.jpexs.decompiler.flash.tags.base.ContainerItem;
|
||||
import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag;
|
||||
import com.jpexs.decompiler.flash.types.CLIPACTIONS;
|
||||
import com.jpexs.decompiler.flash.types.CXFORM;
|
||||
@@ -249,8 +250,8 @@ public class PlaceObject2Tag extends CharacterIdTag implements Container, PlaceO
|
||||
* @return List of sub-items
|
||||
*/
|
||||
@Override
|
||||
public List<Object> getSubItems() {
|
||||
List<Object> ret = new ArrayList<>();
|
||||
public List<ContainerItem> getSubItems() {
|
||||
List<ContainerItem> ret = new ArrayList<>();
|
||||
if (placeFlagHasClipActions) {
|
||||
ret.addAll(clipActions.clipActionRecords);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.abc.CopyOutputStream;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterIdTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.Container;
|
||||
import com.jpexs.decompiler.flash.tags.base.ContainerItem;
|
||||
import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag;
|
||||
import com.jpexs.decompiler.flash.types.CLIPACTIONS;
|
||||
import com.jpexs.decompiler.flash.types.CXFORM;
|
||||
@@ -356,8 +357,8 @@ public class PlaceObject3Tag extends CharacterIdTag implements Container, PlaceO
|
||||
* @return List of sub-items
|
||||
*/
|
||||
@Override
|
||||
public List<Object> getSubItems() {
|
||||
List<Object> ret = new ArrayList<>();
|
||||
public List<ContainerItem> getSubItems() {
|
||||
List<ContainerItem> ret = new ArrayList<>();
|
||||
if (placeFlagHasClipActions) {
|
||||
ret.addAll(clipActions.clipActionRecords);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.abc.CopyOutputStream;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterIdTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.Container;
|
||||
import com.jpexs.decompiler.flash.tags.base.ContainerItem;
|
||||
import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag;
|
||||
import com.jpexs.decompiler.flash.types.CLIPACTIONS;
|
||||
import com.jpexs.decompiler.flash.types.CXFORM;
|
||||
@@ -358,8 +359,8 @@ public class PlaceObject4Tag extends CharacterIdTag implements Container, PlaceO
|
||||
* @return List of sub-items
|
||||
*/
|
||||
@Override
|
||||
public List<Object> getSubItems() {
|
||||
List<Object> ret = new ArrayList<>();
|
||||
public List<ContainerItem> getSubItems() {
|
||||
List<ContainerItem> ret = new ArrayList<>();
|
||||
if (placeFlagHasClipActions) {
|
||||
ret.addAll(clipActions.clipActionRecords);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ContainerItem;
|
||||
import com.jpexs.decompiler.flash.tags.base.Exportable;
|
||||
import com.jpexs.decompiler.flash.tags.base.NeedsCharacters;
|
||||
import java.util.HashMap;
|
||||
@@ -28,7 +29,7 @@ import java.util.Set;
|
||||
/**
|
||||
* Represents Tag inside SWF file
|
||||
*/
|
||||
public class Tag implements NeedsCharacters, Exportable {
|
||||
public class Tag implements NeedsCharacters, Exportable, ContainerItem {
|
||||
|
||||
/**
|
||||
* Identifier of tag type
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags.base;
|
||||
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -30,7 +31,7 @@ public interface Container {
|
||||
*
|
||||
* @return List of sub-items
|
||||
*/
|
||||
public List<Object> getSubItems();
|
||||
public List<ContainerItem> getSubItems();
|
||||
|
||||
/**
|
||||
* Returns number of sub-items
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2013 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.tags.base;
|
||||
|
||||
/**
|
||||
* Object which contains other objects
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface ContainerItem {
|
||||
|
||||
}
|
||||
@@ -20,8 +20,10 @@ import com.jpexs.decompiler.flash.Configuration;
|
||||
import com.jpexs.decompiler.flash.DisassemblyListener;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.action.ActionListReader;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ASMSource;
|
||||
import com.jpexs.decompiler.flash.tags.base.ContainerItem;
|
||||
import com.jpexs.decompiler.flash.tags.base.Exportable;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import com.jpexs.helpers.ReReadableInputStream;
|
||||
@@ -38,7 +40,7 @@ import java.util.logging.Logger;
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class BUTTONCONDACTION implements ASMSource, Exportable {
|
||||
public class BUTTONCONDACTION implements ASMSource, Exportable, ContainerItem {
|
||||
|
||||
private long pos;
|
||||
|
||||
@@ -169,11 +171,7 @@ public class BUTTONCONDACTION implements ASMSource, Exportable {
|
||||
@Override
|
||||
public List<Action> getActions(int version) {
|
||||
try {
|
||||
boolean deobfuscate = Configuration.getConfig("autoDeobfuscate", true);
|
||||
List<Action> list = SWFInputStream.readActionList(listeners, getPos() + 4, new ReReadableInputStream(new ByteArrayInputStream(actionBytes)), version, 0, -1, toString()/*FIXME?*/);
|
||||
if (deobfuscate) {
|
||||
list = Action.removeNops(0, list, version, getPos() + 4, toString()/*FIXME?*/);
|
||||
}
|
||||
List<Action> list = ActionListReader.readActionList(listeners, getPos() + 4, new ReReadableInputStream(new ByteArrayInputStream(actionBytes)), version, 0, -1, toString()/*FIXME?*/);
|
||||
return list;
|
||||
|
||||
} catch (Exception ex) {
|
||||
|
||||
@@ -20,8 +20,10 @@ import com.jpexs.decompiler.flash.Configuration;
|
||||
import com.jpexs.decompiler.flash.DisassemblyListener;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.action.ActionListReader;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ASMSource;
|
||||
import com.jpexs.decompiler.flash.tags.base.ContainerItem;
|
||||
import com.jpexs.decompiler.flash.tags.base.Exportable;
|
||||
import com.jpexs.helpers.ReReadableInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
@@ -37,7 +39,7 @@ import java.util.logging.Logger;
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class CLIPACTIONRECORD implements ASMSource, Exportable {
|
||||
public class CLIPACTIONRECORD implements ASMSource, Exportable, ContainerItem {
|
||||
|
||||
public static String keyToString(int key) {
|
||||
if ((key < CLIPACTIONRECORD.KEYNAMES.length) && (key > 0) && (CLIPACTIONRECORD.KEYNAMES[key] != null)) {
|
||||
@@ -167,11 +169,7 @@ public class CLIPACTIONRECORD implements ASMSource, Exportable {
|
||||
@Override
|
||||
public List<Action> getActions(int version) {
|
||||
try {
|
||||
boolean deobfuscate = Configuration.getConfig("autoDeobfuscate", true);
|
||||
List<Action> list = SWFInputStream.readActionList(listeners, getPos() + hdrPos, new ReReadableInputStream(new ByteArrayInputStream(actionBytes)), version, 0, -1, toString()/*FIXME?*/);
|
||||
if (deobfuscate) {
|
||||
list = Action.removeNops(0, list, version, getPos() + hdrPos, toString()/*FIXME?*/);
|
||||
}
|
||||
List<Action> list = ActionListReader.readActionList(listeners, getPos() + hdrPos, new ReReadableInputStream(new ByteArrayInputStream(actionBytes)), version, 0, -1, toString()/*FIXME?*/);
|
||||
return list;
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(BUTTONCONDACTION.class.getName()).log(Level.SEVERE, null, ex);
|
||||
|
||||
@@ -2155,7 +2155,7 @@ public class Graph {
|
||||
* @param localData
|
||||
* @return String
|
||||
*/
|
||||
public static String graphToString(List<GraphTargetItem> tree, boolean highlight, Object... localData) {
|
||||
public static String graphToString(List<GraphTargetItem> tree, boolean highlight, boolean replaceIndents, Object... localData) {
|
||||
StringBuilder ret = new StringBuilder();
|
||||
List<Object> localDataList = Arrays.asList(localData);
|
||||
for (GraphTargetItem ti : tree) {
|
||||
@@ -2228,23 +2228,20 @@ public class Graph {
|
||||
continue;
|
||||
}
|
||||
strippedP = Highlighting.stripHilights(parts[p]).trim();
|
||||
if (strippedP.equals(INDENTOPEN)) {
|
||||
level++;
|
||||
continue;
|
||||
}
|
||||
if (strippedP.equals(INDENTCLOSE)) {
|
||||
level--;
|
||||
continue;
|
||||
}
|
||||
if (strippedP.startsWith("}")) {
|
||||
level--;
|
||||
|
||||
if (replaceIndents) {
|
||||
if (strippedP.equals(INDENTOPEN)) {
|
||||
level++;
|
||||
continue;
|
||||
}
|
||||
if (strippedP.equals(INDENTCLOSE)) {
|
||||
level--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
ret.append(tabString(level));
|
||||
ret.append(parts[p]);
|
||||
ret.append(parts[p].trim());
|
||||
ret.append("\r\n");
|
||||
if (strippedP.equals("{")) {
|
||||
level++;
|
||||
}
|
||||
}
|
||||
return ret.toString();
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@ public interface GraphSourceItemContainer {
|
||||
|
||||
public List<Long> getContainerSizes();
|
||||
|
||||
public void setContainerSize(int index, long size);
|
||||
|
||||
public String getASMSourceBetween(int pos);
|
||||
|
||||
public boolean parseDivision(long size, FlasmLexer lexer);
|
||||
|
||||
@@ -37,7 +37,9 @@ public class BlockItem extends GraphTargetItem {
|
||||
|
||||
@Override
|
||||
public String toString(boolean highlight, List<Object> localData) {
|
||||
return hilight("{", highlight) + "\r\n" + Graph.graphToString(commands, highlight, localData) + "\r\n" + hilight("}", highlight);
|
||||
return hilight("{", highlight) + "\r\n" + Graph.INDENTOPEN + "\r\n" +
|
||||
Graph.graphToString(commands, highlight, false, localData) + "\r\n" +
|
||||
Graph.INDENTCLOSE + "\r\n" + hilight("}", highlight);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.jpexs.decompiler.graph.model;
|
||||
|
||||
import com.jpexs.decompiler.graph.Block;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.Loop;
|
||||
@@ -52,6 +53,7 @@ public class DoWhileItem extends LoopItem implements Block {
|
||||
String ret = "";
|
||||
ret += hilight("loop" + loop.id + ":", highlight) + "\r\n";
|
||||
ret += hilight("do", highlight) + "\r\n" + hilight("{", highlight) + "\r\n";
|
||||
ret += Graph.INDENTOPEN + "\r\n";
|
||||
for (GraphTargetItem ti : commands) {
|
||||
if (!ti.isEmpty()) {
|
||||
ret += ti.toStringSemicoloned(highlight, localData) + "\r\n";
|
||||
@@ -67,6 +69,7 @@ public class DoWhileItem extends LoopItem implements Block {
|
||||
}
|
||||
expStr += expression.get(i).toString(highlight, localData);
|
||||
}
|
||||
ret += Graph.INDENTCLOSE + "\r\n";
|
||||
ret += hilight("}", highlight) + "\r\n" + hilight("while(", highlight) + expStr + hilight(");", highlight) + "\r\n";
|
||||
ret += hilight(":loop" + loop.id, highlight);
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.jpexs.decompiler.graph.model;
|
||||
|
||||
import com.jpexs.decompiler.graph.Block;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.Loop;
|
||||
@@ -87,11 +88,13 @@ public class ForItem extends LoopItem implements Block {
|
||||
p++;
|
||||
}
|
||||
ret += hilight(")", highlight) + "\r\n" + hilight("{", highlight) + "\r\n";
|
||||
ret += Graph.INDENTOPEN + "\r\n";
|
||||
for (GraphTargetItem ti : commands) {
|
||||
if (!ti.isEmpty()) {
|
||||
ret += ti.toStringSemicoloned(highlight, localData) + "\r\n";
|
||||
}
|
||||
}
|
||||
ret += Graph.INDENTCLOSE + "\r\n";
|
||||
ret += hilight("}", highlight) + "\r\n";
|
||||
ret += ":loop" + loop.id;
|
||||
return ret;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.jpexs.decompiler.graph.model;
|
||||
|
||||
import com.jpexs.decompiler.graph.Block;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.SourceGenerator;
|
||||
@@ -71,19 +72,23 @@ public class IfItem extends GraphTargetItem implements Block {
|
||||
}
|
||||
}
|
||||
ret = hilight("if(", highlight) + expr.toString(highlight, localData) + hilight(")", highlight) + "\r\n" + hilight("{", highlight) + "\r\n";
|
||||
ret += Graph.INDENTOPEN + "\r\n";
|
||||
for (GraphTargetItem ti : ifBranch) {
|
||||
if (!ti.isEmpty()) {
|
||||
ret += ti.toStringSemicoloned(highlight, localData) + "\r\n";
|
||||
}
|
||||
}
|
||||
ret += Graph.INDENTCLOSE + "\r\n";
|
||||
ret += hilight("}", highlight);
|
||||
if (elseBranch.size() > 0) {
|
||||
ret += "\r\n" + hilight("else", highlight) + "\r\n" + hilight("{", highlight) + "\r\n";
|
||||
ret += Graph.INDENTOPEN + "\r\n";
|
||||
for (GraphTargetItem ti : elseBranch) {
|
||||
if (!ti.isEmpty()) {
|
||||
ret += ti.toStringSemicoloned(highlight, localData) + "\r\n";
|
||||
}
|
||||
}
|
||||
ret += Graph.INDENTCLOSE + "\r\n";
|
||||
ret += hilight("}", highlight);
|
||||
}
|
||||
return ret;
|
||||
|
||||
@@ -55,6 +55,7 @@ public class SwitchItem extends LoopItem implements Block {
|
||||
String ret = "";
|
||||
ret += hilight("loopswitch" + loop.id + ":", highlight) + "\r\n";
|
||||
ret += hilight("switch(", highlight) + switchedObject.toString(highlight, localData) + hilight(")", highlight) + "\r\n" + hilight("{", highlight) + "\r\n";
|
||||
ret += Graph.INDENTOPEN + "\r\n";
|
||||
for (int i = 0; i < caseCommands.size(); i++) {
|
||||
for (int k = 0; k < valuesMapping.size(); k++) {
|
||||
if (valuesMapping.get(k) == i) {
|
||||
@@ -81,6 +82,7 @@ public class SwitchItem extends LoopItem implements Block {
|
||||
ret += Graph.INDENTCLOSE + "\r\n";
|
||||
}
|
||||
}
|
||||
ret += Graph.INDENTCLOSE + "\r\n";
|
||||
ret += hilight("}", highlight) + "\r\n";
|
||||
ret += ":loop" + loop.id;
|
||||
return ret;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.jpexs.decompiler.graph.model;
|
||||
|
||||
import com.jpexs.decompiler.graph.Block;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.Loop;
|
||||
@@ -41,11 +42,13 @@ public class UniversalLoopItem extends LoopItem implements Block {
|
||||
ret += hilight("loop" + loop.id + ":", highlight) + "\r\n";
|
||||
ret += hilight("while(true)", highlight);
|
||||
ret += "\r\n" + hilight("{", highlight) + "\r\n";
|
||||
ret += Graph.INDENTOPEN + "\r\n";
|
||||
for (GraphTargetItem ti : commands) {
|
||||
if (!ti.isEmpty()) {
|
||||
ret += ti.toStringSemicoloned(highlight, localData) + "\r\n";
|
||||
}
|
||||
}
|
||||
ret += Graph.INDENTCLOSE + "\r\n";
|
||||
ret += hilight("}", highlight) + "\r\n";
|
||||
ret += hilight(":loop" + loop.id, highlight);
|
||||
return ret;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.jpexs.decompiler.graph.model;
|
||||
|
||||
import com.jpexs.decompiler.graph.Block;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.Loop;
|
||||
@@ -57,11 +58,13 @@ public class WhileItem extends LoopItem implements Block {
|
||||
expStr += expression.get(i).toString(highlight, localData);
|
||||
}
|
||||
ret += hilight("while(", highlight) + expStr + hilight(")", highlight) + "\r\n" + hilight("{", highlight) + "\r\n";
|
||||
ret += Graph.INDENTOPEN + "\r\n";
|
||||
for (GraphTargetItem ti : commands) {
|
||||
if (!ti.isEmpty()) {
|
||||
ret += ti.toStringSemicoloned(highlight, localData) + "\r\n";
|
||||
}
|
||||
}
|
||||
ret += Graph.INDENTCLOSE + "\r\n";
|
||||
ret += hilight("}", highlight) + "\r\n";
|
||||
ret += hilight(":loop" + loop.id, highlight);
|
||||
return ret;
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package com.jpexs.helpers;
|
||||
|
||||
import com.jpexs.decompiler.flash.gui.Freed;
|
||||
import com.jpexs.decompiler.flash.helpers.Highlighting;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.awt.Component;
|
||||
import java.io.ByteArrayInputStream;
|
||||
@@ -552,4 +551,13 @@ public class Helper {
|
||||
THREAD_POOL.execute(task);
|
||||
return task.get(timeout, timeUnit);
|
||||
}
|
||||
|
||||
public static boolean contains(int[] array, int value) {
|
||||
for (int i : array) {
|
||||
if (i == value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ public class ActionScript2AssemblerTest {
|
||||
"Jump loc000d\n" +
|
||||
"loc002f:";
|
||||
try {
|
||||
List<Action> actions = ASMParser.parse(0, 0, true, actionsString, swf.version);
|
||||
List<Action> actions = ASMParser.parse(0, 0, true, actionsString, swf.version, false);
|
||||
|
||||
DoActionTag doa = getFirstActionTag();
|
||||
doa.setActionBytes(Action.actionsToBytes(actions, true, swf.version));
|
||||
|
||||
@@ -78,11 +78,21 @@ public class ExportTest {
|
||||
}
|
||||
|
||||
@Test(dataProvider = "swfFiles")
|
||||
public void testDecompile(File f) {
|
||||
public void testDecompileAS(File f) {
|
||||
testDecompile(f, false);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "swfFiles")
|
||||
public void testDecompilePcode(File f) {
|
||||
testDecompile(f, true);
|
||||
}
|
||||
|
||||
public void testDecompile(File f, boolean isPcode) {
|
||||
try {
|
||||
SWF swf = new SWF(new FileInputStream(f), false);
|
||||
Configuration.DEBUG_COPY = true;
|
||||
File fdir = new File(TESTDATADIR + File.separator + "output" + File.separator + f.getName());
|
||||
String folderName = isPcode ? "outputp" : "output";
|
||||
File fdir = new File(TESTDATADIR + File.separator + folderName + File.separator + f.getName());
|
||||
fdir.mkdirs();
|
||||
|
||||
swf.exportActionScript(new AbortRetryIgnoreHandler() {
|
||||
@@ -96,7 +106,7 @@ public class ExportTest {
|
||||
return this;
|
||||
}
|
||||
|
||||
}, fdir.getAbsolutePath(), false, false);
|
||||
}, fdir.getAbsolutePath(), isPcode, false);
|
||||
} catch (Exception ex) {
|
||||
fail();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user