mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-05-31 19:54:37 +00:00
faster "removeGetTimes"
This commit is contained in:
@@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.DisassemblyListener;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.action.deobfuscation.ActionDeobfuscator;
|
||||
import com.jpexs.decompiler.flash.action.deobfuscation.ActionDeobfuscatorSimple;
|
||||
import com.jpexs.decompiler.flash.action.deobfuscation.ActionDeobfuscatorSimpleFast;
|
||||
import com.jpexs.decompiler.flash.action.model.ConstantPool;
|
||||
import com.jpexs.decompiler.flash.action.model.DirectValueActionItem;
|
||||
import com.jpexs.decompiler.flash.action.special.ActionDeobfuscateJump;
|
||||
@@ -180,6 +181,9 @@ public class ActionListReader {
|
||||
}
|
||||
} else if (deobfuscationMode == 1) {
|
||||
try {
|
||||
try (Statistics s = new Statistics("ActionDeobfuscatorSimpleFast")) {
|
||||
new ActionDeobfuscatorSimpleFast().actionListParsed(actions, sis.getSwf());
|
||||
}
|
||||
try (Statistics s = new Statistics("ActionDeobfuscatorSimple")) {
|
||||
new ActionDeobfuscatorSimple().actionListParsed(actions, sis.getSwf());
|
||||
}
|
||||
|
||||
@@ -1,235 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2015 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.action;
|
||||
|
||||
import com.jpexs.decompiler.flash.action.special.ActionStore;
|
||||
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.graph.GraphSourceItemContainer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class FastActionList {
|
||||
|
||||
private LinkedList<Action> actions;
|
||||
|
||||
private Map<Action, List<Action>> containerLastActions;
|
||||
|
||||
private Map<Action, Action> jumps;
|
||||
|
||||
public FastActionList(ActionList actions) {
|
||||
this.actions = new LinkedList<>(actions);
|
||||
|
||||
Map<Action, List<Action>> containerLastActions = new HashMap<>();
|
||||
getContainerLastActions(this.actions, actions, containerLastActions);
|
||||
this.containerLastActions = containerLastActions;
|
||||
|
||||
Map<Action, Action> jumps = new HashMap<>();
|
||||
getJumps(actions, jumps);
|
||||
this.jumps = jumps;
|
||||
}
|
||||
|
||||
private void getContainerLastActions(LinkedList<Action> linkedActions, ActionList actions, Map<Action, List<Action>> lastActions) {
|
||||
for (Action a : linkedActions) {
|
||||
if (a instanceof GraphSourceItemContainer) {
|
||||
lastActions.put(a, getContainerLastActions(actions, a));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<Action> getContainerLastActions(ActionList actions, Action action) {
|
||||
GraphSourceItemContainer container = (GraphSourceItemContainer) action;
|
||||
List<Long> sizes = container.getContainerSizes();
|
||||
long endAddress = action.getAddress() + container.getHeaderSize();
|
||||
List<Action> lasts = new ArrayList<>(sizes.size());
|
||||
for (long size : sizes) {
|
||||
endAddress += size;
|
||||
long lastActionAddress = getNearAddress(actions, endAddress - 1, false);
|
||||
Action lastAction = null;
|
||||
if (lastActionAddress != -1) {
|
||||
lastAction = actions.getByAddress(lastActionAddress);
|
||||
}
|
||||
lasts.add(lastAction);
|
||||
}
|
||||
return lasts;
|
||||
}
|
||||
|
||||
private long getNearAddress(ActionList actions, long address, boolean next) {
|
||||
int min = 0;
|
||||
int max = actions.size() - 1;
|
||||
|
||||
while (max >= min) {
|
||||
int mid = (min + max) / 2;
|
||||
long midValue = actions.get(mid).getAddress();
|
||||
if (midValue == address) {
|
||||
return address;
|
||||
} else if (midValue < address) {
|
||||
min = mid + 1;
|
||||
} else {
|
||||
max = mid - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return next
|
||||
? (min < actions.size() ? actions.get(min).getAddress() : -1)
|
||||
: (max >= 0 ? actions.get(max).getAddress() : -1);
|
||||
}
|
||||
|
||||
private static void getJumps(ActionList actions, Map<Action, Action> jumps) {
|
||||
for (Action a : actions) {
|
||||
long target = -1;
|
||||
if (a instanceof ActionIf) {
|
||||
target = ((ActionIf) a).getTargetAddress();
|
||||
} else if (a instanceof ActionJump) {
|
||||
target = ((ActionJump) a).getTargetAddress();
|
||||
} 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() + targetAction.getTotalActionLength();
|
||||
targetAction = actions.getByAddress(address);
|
||||
if (targetAction == null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
jumps.put(a, targetAction);
|
||||
}
|
||||
if (target >= 0) {
|
||||
Action targetAction = actions.getByAddress(target);
|
||||
jumps.put(a, targetAction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateJumps(Map<Action, Action> jumps) {
|
||||
if (actions.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
long endAddress = actions.getLast().getAddress();
|
||||
for (Action a : actions) {
|
||||
if (a instanceof ActionIf) {
|
||||
ActionIf aIf = (ActionIf) a;
|
||||
Action target = jumps.get(a);
|
||||
long offset;
|
||||
if (target != null) {
|
||||
offset = target.getAddress() - a.getAddress() - a.getTotalActionLength();
|
||||
} else {
|
||||
offset = endAddress - a.getAddress() - a.getTotalActionLength();
|
||||
}
|
||||
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() - a.getTotalActionLength();
|
||||
} else {
|
||||
offset = endAddress - a.getAddress() - a.getTotalActionLength();
|
||||
}
|
||||
aJump.setJumpOffset((int) offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateActionStores(ActionList actionList, Map<Action, Action> jumps) {
|
||||
for (Action a : actions) {
|
||||
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() + a1.getTotalActionLength();
|
||||
a1 = actionList.getByAddress(address);
|
||||
if (a1 == null || a1 == nextActionAfterStore) {
|
||||
break;
|
||||
}
|
||||
store.add(a1);
|
||||
}
|
||||
aStore.setStore(store);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateContainerSizes(Map<Action, List<Action>> containerLastActions) {
|
||||
for (Action a : actions) {
|
||||
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() + lastAction.getTotalActionLength() - startAddress);
|
||||
container.setContainerSize(j, length);
|
||||
startAddress += length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void expandPushes() {
|
||||
ListIterator<Action> iterator = actions.listIterator();
|
||||
while (iterator.hasNext()) {
|
||||
Action action = iterator.next();
|
||||
if (action instanceof ActionPush) {
|
||||
ActionPush push = (ActionPush) action;
|
||||
if (push.values.size() > 1) {
|
||||
for (int i = 1; i < push.values.size(); i++) {
|
||||
Object value = push.values.get(i);
|
||||
ActionPush newPush = new ActionPush(value);
|
||||
newPush.constantPool = push.constantPool;
|
||||
iterator.add(newPush);
|
||||
}
|
||||
|
||||
Object obj = push.values.get(0);
|
||||
push.values.clear();
|
||||
push.values.add(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateActionAddressesAndLengths() {
|
||||
long address = actions.get(0).getAddress();
|
||||
for (Action action : actions) {
|
||||
action.setAddress(address);
|
||||
action.updateLength();
|
||||
address += action.getTotalActionLength();
|
||||
}
|
||||
}
|
||||
|
||||
public ActionList toActionList() {
|
||||
ActionList result = new ActionList(actions);
|
||||
updateActionAddressesAndLengths();
|
||||
updateJumps(jumps);
|
||||
updateActionStores(result, jumps);
|
||||
updateContainerSizes(containerLastActions);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,6 @@ import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.action.ActionList;
|
||||
import com.jpexs.decompiler.flash.action.ActionLocalData;
|
||||
import com.jpexs.decompiler.flash.action.FastActionList;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionAdd;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionAnd;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionAsciiToChar;
|
||||
@@ -84,11 +83,7 @@ public class ActionDeobfuscatorSimple implements SWFDecompilerListener {
|
||||
|
||||
@Override
|
||||
public void actionListParsed(ActionList actions, SWF swf) throws InterruptedException {
|
||||
FastActionList fastActions = new FastActionList(actions);
|
||||
fastActions.expandPushes();
|
||||
actions.setActions(fastActions.toActionList());
|
||||
|
||||
removeGetTimes(actions);
|
||||
//removeGetTimes(actions);
|
||||
removeObfuscationIfs(actions);
|
||||
}
|
||||
|
||||
@@ -370,7 +365,7 @@ public class ActionDeobfuscatorSimple implements SWFDecompilerListener {
|
||||
|
||||
if (action instanceof ActionJump) {
|
||||
ActionJump jump = (ActionJump) action;
|
||||
long address = jump.getAddress() + jump.getTotalActionLength() + jump.getJumpOffset();
|
||||
long address = jump.getTargetAddress();
|
||||
idx = actions.getIndexByAddress(address);
|
||||
if (idx == -1) {
|
||||
throw new TranslateException("Jump target not found: " + address);
|
||||
@@ -384,7 +379,7 @@ public class ActionDeobfuscatorSimple implements SWFDecompilerListener {
|
||||
}
|
||||
|
||||
if (EcmaScript.toBoolean(stack.pop().getResult())) {
|
||||
long address = aif.getAddress() + aif.getTotalActionLength() + aif.getJumpOffset();
|
||||
long address = aif.getTargetAddress();
|
||||
idx = actions.getIndexByAddress(address);
|
||||
if (idx == -1) {
|
||||
throw new TranslateException("If target not found: " + address);
|
||||
|
||||
@@ -0,0 +1,389 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2015 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.action.deobfuscation;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.action.ActionList;
|
||||
import com.jpexs.decompiler.flash.action.ActionLocalData;
|
||||
import com.jpexs.decompiler.flash.action.fastactionlist.ActionItem;
|
||||
import com.jpexs.decompiler.flash.action.fastactionlist.FastActionList;
|
||||
import com.jpexs.decompiler.flash.action.fastactionlist.FastActionListIterator;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionAdd;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionAnd;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionAsciiToChar;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionCharToAscii;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionDivide;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionEquals;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionGetTime;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionIf;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionJump;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionLess;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionMBAsciiToChar;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionMBStringLength;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionMultiply;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionNot;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionOr;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionPush;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionStringAdd;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionStringEquals;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionStringLength;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionStringLess;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionSubtract;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionToInteger;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ConstantIndex;
|
||||
import com.jpexs.decompiler.flash.action.swf4.RegisterNumber;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionAdd2;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionBitAnd;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionBitLShift;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionBitOr;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionBitRShift;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionBitURShift;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionBitXor;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionDecrement;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionEquals2;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionIncrement;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionLess2;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionModulo;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionPushDuplicate;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionToNumber;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionToString;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionTypeOf;
|
||||
import com.jpexs.decompiler.flash.action.swf6.ActionGreater;
|
||||
import com.jpexs.decompiler.flash.action.swf6.ActionStringGreater;
|
||||
import com.jpexs.decompiler.flash.ecma.EcmaScript;
|
||||
import com.jpexs.decompiler.flash.helpers.SWFDecompilerListener;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.TranslateException;
|
||||
import com.jpexs.decompiler.graph.TranslateStack;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ActionDeobfuscatorSimpleFast implements SWFDecompilerListener {
|
||||
|
||||
private final int executionLimit = 30000;
|
||||
|
||||
@Override
|
||||
public void actionListParsed(ActionList actions, SWF swf) throws InterruptedException {
|
||||
FastActionList fastActions = new FastActionList(actions);
|
||||
fastActions.expandPushes();
|
||||
removeGetTimes(fastActions);
|
||||
//removeObfuscationIfs(fastActions);
|
||||
actions.setActions(fastActions.toActionList());
|
||||
}
|
||||
|
||||
private boolean removeGetTimes(FastActionList actions) {
|
||||
if (actions.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean changed = true;
|
||||
int getTimeCount = 1;
|
||||
while (changed && getTimeCount > 0) {
|
||||
changed = false;
|
||||
actions.removeUnreachableActions();
|
||||
actions.removeZeroJumps();
|
||||
getTimeCount = 0;
|
||||
|
||||
// GetTime, If => Jump, assume GetTime > 0
|
||||
FastActionListIterator iterator = actions.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Action a = iterator.next().action;
|
||||
ActionItem a2Item = iterator.peek(0);
|
||||
Action a2 = a2Item.action;
|
||||
boolean isGetTime = a instanceof ActionGetTime;
|
||||
if (isGetTime) {
|
||||
getTimeCount++;
|
||||
}
|
||||
|
||||
if (isGetTime && a2 instanceof ActionIf) {
|
||||
ActionJump jump = new ActionJump(0);
|
||||
ActionItem jumpItem = new ActionItem(jump);
|
||||
jumpItem.jumpTarget = a2Item.jumpTarget;
|
||||
iterator.remove(); // GetTime
|
||||
iterator.next();
|
||||
iterator.remove(); // If
|
||||
iterator.add(jumpItem); // replace If with Jump
|
||||
changed = true;
|
||||
getTimeCount--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!changed && getTimeCount > 0) {
|
||||
// GetTime, Increment If => Jump
|
||||
iterator = actions.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Action a = iterator.next().action;
|
||||
Action a1 = iterator.peek(0).action;
|
||||
ActionItem a2Item = iterator.peek(1);
|
||||
Action a2 = a2Item.action;
|
||||
if (a instanceof ActionGetTime && a1 instanceof ActionIncrement && a2 instanceof ActionIf) {
|
||||
ActionJump jump = new ActionJump(0);
|
||||
ActionItem jumpItem = new ActionItem(jump);
|
||||
jumpItem.jumpTarget = a2Item.jumpTarget;
|
||||
iterator.remove(); // GetTime
|
||||
iterator.next();
|
||||
iterator.remove(); // Increment
|
||||
iterator.next();
|
||||
iterator.remove(); // If
|
||||
iterator.add(jumpItem); // replace If with Jump
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// private boolean removeObfuscationIfs(FastActionList actions) throws InterruptedException {
|
||||
// if (actions.isEmpty()) {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// actions.removeUnreachableActions();
|
||||
// actions.removeZeroJumps();
|
||||
//
|
||||
// FastActionListIterator iterator = actions.iterator();
|
||||
// while (iterator.hasNext()) {
|
||||
// ActionItem actionItem = iterator.next();
|
||||
// ExecutionResult result = new ExecutionResult();
|
||||
// executeActions(actions, i, actions.size() - 1, result);
|
||||
//
|
||||
// if (result.idx != -1) {
|
||||
// int newIstructionCount = 1 /*jump */ + result.stack.size();
|
||||
// List<Action> unreachable = actions.getUnreachableActions(i, result.idx);
|
||||
// int unreachableCount = unreachable.size();
|
||||
//
|
||||
// if (newIstructionCount < unreachableCount) {
|
||||
// Action target = actions.get(result.idx);
|
||||
// Action prevAction = actions.get(i);
|
||||
//
|
||||
// if (result.stack.isEmpty() && prevAction instanceof ActionJump) {
|
||||
// ActionJump jump = (ActionJump) prevAction;
|
||||
// jump.setJumpOffset((int) (target.getAddress() - jump.getAddress() - jump.getTotalActionLength()));
|
||||
// } else {
|
||||
// if (!result.stack.isEmpty()) {
|
||||
// ActionPush push = new ActionPush(0);
|
||||
// push.values.clear();
|
||||
// for (GraphTargetItem graphTargetItem : result.stack) {
|
||||
// push.values.add(graphTargetItem.getResult());
|
||||
// }
|
||||
// push.setAddress(prevAction.getAddress());
|
||||
// actions.addAction(i++, push);
|
||||
// prevAction = push;
|
||||
// }
|
||||
//
|
||||
// ActionJump jump = new ActionJump(0);
|
||||
// jump.setAddress(prevAction.getAddress());
|
||||
// jump.setJumpOffset((int) (target.getAddress() - jump.getAddress() - jump.getTotalActionLength()));
|
||||
// actions.addAction(i++, jump);
|
||||
// }
|
||||
//
|
||||
// Action nextAction = actions.size() > i ? actions.get(i) : null;
|
||||
//
|
||||
// actions.removeUnreachableActions();
|
||||
// actions.removeZeroJumps();
|
||||
//
|
||||
// if (nextAction != null) {
|
||||
// int nextIdx = actions.indexOf(nextAction);
|
||||
// if (nextIdx < i) {
|
||||
// i = nextIdx;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return false;
|
||||
// }
|
||||
protected boolean isFakeName(String name) {
|
||||
for (char ch : name.toCharArray()) {
|
||||
if (ch > 31) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void executeActions(ActionList actions, int idx, int endIdx, ExecutionResult result) throws InterruptedException {
|
||||
List<GraphTargetItem> output = new ArrayList<>();
|
||||
ActionLocalData localData = new ActionLocalData();
|
||||
FixItemCounterTranslateStack stack = new FixItemCounterTranslateStack("");
|
||||
int instructionsProcessed = 0;
|
||||
|
||||
while (true) {
|
||||
if (Thread.currentThread().isInterrupted()) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
|
||||
if (idx > endIdx) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (instructionsProcessed > executionLimit) {
|
||||
break;
|
||||
}
|
||||
|
||||
Action action = actions.get(idx);
|
||||
|
||||
/*System.out.print(action.getASMSource(actions, new ArrayList<Long>(), ScriptExportMode.PCODE));
|
||||
for (int j = 0; j < stack.size(); j++) {
|
||||
System.out.print(" '" + stack.get(j).getResult() + "'");
|
||||
}
|
||||
System.out.println();*/
|
||||
// do not throw EmptyStackException, much faster
|
||||
int requiredStackSize = action.getStackPopCount(localData, stack);
|
||||
if (stack.size() < requiredStackSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
action.translate(localData, stack, output, Graph.SOP_USE_STATIC, "");
|
||||
|
||||
if (!(action instanceof ActionPush
|
||||
|| action instanceof ActionPushDuplicate
|
||||
//|| action instanceof ActionPop
|
||||
|| action instanceof ActionAsciiToChar
|
||||
|| action instanceof ActionCharToAscii
|
||||
|| action instanceof ActionDecrement
|
||||
|| action instanceof ActionIncrement
|
||||
|| action instanceof ActionNot
|
||||
|| action instanceof ActionToInteger
|
||||
|| action instanceof ActionToNumber
|
||||
|| action instanceof ActionToString
|
||||
|| action instanceof ActionTypeOf
|
||||
|| action instanceof ActionStringLength
|
||||
|| action instanceof ActionMBAsciiToChar
|
||||
|| action instanceof ActionMBStringLength
|
||||
|| action instanceof ActionAnd
|
||||
|| action instanceof ActionAdd
|
||||
|| action instanceof ActionAdd2
|
||||
|| action instanceof ActionBitAnd
|
||||
|| action instanceof ActionBitLShift
|
||||
|| action instanceof ActionBitOr
|
||||
|| action instanceof ActionBitRShift
|
||||
|| action instanceof ActionBitURShift
|
||||
|| action instanceof ActionBitXor
|
||||
|| action instanceof ActionDivide
|
||||
|| action instanceof ActionEquals
|
||||
|| action instanceof ActionEquals2
|
||||
|| action instanceof ActionGreater
|
||||
|| action instanceof ActionLess
|
||||
|| action instanceof ActionLess2 // todo: fix (tz.swf/frame_6/DoAction: _loc3_.icon.gotoAndStop((Number(item.cost) || 0) >= 0?1:2)
|
||||
|| action instanceof ActionModulo
|
||||
|| action instanceof ActionMultiply
|
||||
|| action instanceof ActionOr
|
||||
|| action instanceof ActionStringAdd
|
||||
|| action instanceof ActionStringEquals
|
||||
|| action instanceof ActionStringGreater
|
||||
|| action instanceof ActionStringLess
|
||||
|| action instanceof ActionSubtract
|
||||
|| action instanceof ActionIf
|
||||
|| action instanceof ActionJump)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (action instanceof ActionPush) {
|
||||
ActionPush push = (ActionPush) action;
|
||||
boolean ok = true;
|
||||
instructionsProcessed += push.values.size() - 1;
|
||||
for (Object value : push.values) {
|
||||
if (value instanceof ConstantIndex || value instanceof RegisterNumber) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
idx++;
|
||||
|
||||
if (action instanceof ActionJump) {
|
||||
ActionJump jump = (ActionJump) action;
|
||||
long address = jump.getTargetAddress();
|
||||
idx = actions.getIndexByAddress(address);
|
||||
if (idx == -1) {
|
||||
throw new TranslateException("Jump target not found: " + address);
|
||||
}
|
||||
}
|
||||
|
||||
if (action instanceof ActionIf) {
|
||||
ActionIf aif = (ActionIf) action;
|
||||
if (stack.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (EcmaScript.toBoolean(stack.pop().getResult())) {
|
||||
long address = aif.getTargetAddress();
|
||||
idx = actions.getIndexByAddress(address);
|
||||
if (idx == -1) {
|
||||
throw new TranslateException("If target not found: " + address);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
instructionsProcessed++;
|
||||
|
||||
if (stack.allItemsFixed() && !(action instanceof ActionPush)) {
|
||||
result.idx = idx == actions.size() ? idx - 1 : idx;
|
||||
result.instructionsProcessed = instructionsProcessed;
|
||||
result.stack.clear();
|
||||
result.stack.addAll(stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] proxyFileCatched(byte[] data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void swfParsed(SWF swf) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abcParsed(ABC abc, SWF swf) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void methodBodyParsed(MethodBody body, SWF swf) {
|
||||
}
|
||||
|
||||
class ExecutionResult {
|
||||
|
||||
public int idx = -1;
|
||||
|
||||
public int instructionsProcessed = -1;
|
||||
|
||||
public TranslateStack stack = new TranslateStack("?");
|
||||
|
||||
public Object resultValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2015 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.action.fastactionlist;
|
||||
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ActionItem {
|
||||
|
||||
public Action action;
|
||||
|
||||
public ActionItem prev;
|
||||
|
||||
public ActionItem next;
|
||||
|
||||
public ActionItem jumpTarget;
|
||||
|
||||
public List<ActionItem> containerLastActions;
|
||||
|
||||
// 1 means reachable, 2 means reachable and processed
|
||||
int reachable;
|
||||
|
||||
public ActionItem(Action action) {
|
||||
this.action = action;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,610 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2015 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.action.fastactionlist;
|
||||
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.action.ActionList;
|
||||
import com.jpexs.decompiler.flash.action.special.ActionStore;
|
||||
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.graph.GraphSourceItemContainer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class FastActionList implements Collection<ActionItem> {
|
||||
|
||||
private int size;
|
||||
|
||||
private ActionItem firstAction;
|
||||
|
||||
private final Map<Action, ActionItem> actionItemMap;
|
||||
|
||||
private final Set<ActionItem> actionItemSet;
|
||||
|
||||
public FastActionList(ActionList actions) {
|
||||
actionItemMap = new HashMap<>(actions.size());
|
||||
actionItemSet = new HashSet<>(actions.size());
|
||||
for (Action action : actions) {
|
||||
insertItemAfter(null, action);
|
||||
}
|
||||
|
||||
size = actions.size();
|
||||
getContainerLastActions(actions, actionItemMap);
|
||||
getJumps(actions, actionItemMap);
|
||||
}
|
||||
|
||||
final ActionItem insertItemAfter(ActionItem item, Action action) {
|
||||
ActionItem newItem = new ActionItem(action);
|
||||
return insertItemAfter(item, newItem);
|
||||
}
|
||||
|
||||
final ActionItem insertItemAfter(ActionItem item, ActionItem newItem) {
|
||||
if (item == null && firstAction == null) {
|
||||
firstAction = newItem;
|
||||
newItem.next = newItem;
|
||||
newItem.prev = newItem;
|
||||
} else {
|
||||
if (item == null) {
|
||||
// insert to the end
|
||||
item = firstAction.prev;
|
||||
}
|
||||
|
||||
ActionItem oldNext = item.next;
|
||||
newItem.prev = item;
|
||||
newItem.next = oldNext;
|
||||
item.next = newItem;
|
||||
oldNext.prev = newItem;
|
||||
}
|
||||
|
||||
size++;
|
||||
actionItemMap.put(newItem.action, newItem);
|
||||
actionItemSet.add(newItem);
|
||||
return newItem;
|
||||
}
|
||||
|
||||
ActionItem removeItem(ActionItem item) {
|
||||
ActionItem next = null;
|
||||
if (item == firstAction) {
|
||||
if (item.next == item) {
|
||||
// there is only 1 item
|
||||
firstAction = null;
|
||||
} else {
|
||||
next = item.next;
|
||||
firstAction = next;
|
||||
next.prev = item.prev;
|
||||
item.prev.next = next;
|
||||
}
|
||||
} else {
|
||||
next = item.next;
|
||||
item.prev.next = next;
|
||||
next.prev = item.prev;
|
||||
}
|
||||
|
||||
size--;
|
||||
actionItemMap.remove(item.action);
|
||||
actionItemSet.remove(item);
|
||||
return next;
|
||||
}
|
||||
|
||||
private void getContainerLastActions(ActionList actions, Map<Action, ActionItem> actionItemMap) {
|
||||
ActionItem item = firstAction;
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
Action action = item.action;
|
||||
if (action instanceof GraphSourceItemContainer) {
|
||||
item.containerLastActions = getContainerLastActions(actions, action, actionItemMap);
|
||||
}
|
||||
|
||||
item = item.next;
|
||||
} while (item != firstAction);
|
||||
}
|
||||
|
||||
private List<ActionItem> getContainerLastActions(ActionList actions, Action action, Map<Action, ActionItem> actionItemMap) {
|
||||
GraphSourceItemContainer container = (GraphSourceItemContainer) action;
|
||||
List<Long> sizes = container.getContainerSizes();
|
||||
long endAddress = action.getAddress() + container.getHeaderSize();
|
||||
List<ActionItem> lasts = new ArrayList<>(sizes.size());
|
||||
for (long size : sizes) {
|
||||
endAddress += size;
|
||||
long lastActionAddress = getNearAddress(actions, endAddress - 1, false);
|
||||
Action lastAction = null;
|
||||
if (lastActionAddress != -1) {
|
||||
lastAction = actions.getByAddress(lastActionAddress);
|
||||
}
|
||||
|
||||
if (lastAction != null) {
|
||||
lasts.add(actionItemMap.get(lastAction));
|
||||
} else {
|
||||
lasts.add(null);
|
||||
}
|
||||
}
|
||||
return lasts;
|
||||
}
|
||||
|
||||
private long getNearAddress(ActionList actions, long address, boolean next) {
|
||||
int min = 0;
|
||||
int max = actions.size() - 1;
|
||||
|
||||
while (max >= min) {
|
||||
int mid = (min + max) / 2;
|
||||
long midValue = actions.get(mid).getAddress();
|
||||
if (midValue == address) {
|
||||
return address;
|
||||
} else if (midValue < address) {
|
||||
min = mid + 1;
|
||||
} else {
|
||||
max = mid - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return next
|
||||
? (min < actions.size() ? actions.get(min).getAddress() : -1)
|
||||
: (max >= 0 ? actions.get(max).getAddress() : -1);
|
||||
}
|
||||
|
||||
private void getJumps(ActionList actions, Map<Action, ActionItem> actionItemMap) {
|
||||
ActionItem item = firstAction;
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
Action action = item.action;
|
||||
long target = -1;
|
||||
if (action instanceof ActionIf) {
|
||||
target = ((ActionIf) action).getTargetAddress();
|
||||
} else if (action instanceof ActionJump) {
|
||||
target = ((ActionJump) action).getTargetAddress();
|
||||
} else if (action instanceof ActionStore) {
|
||||
ActionStore aStore = (ActionStore) action;
|
||||
int storeSize = aStore.getStoreSize();
|
||||
// skip storeSize + 1 actions (+1 is the current action)
|
||||
Action targetAction = action;
|
||||
for (int i = 0; i <= storeSize; i++) {
|
||||
long address = targetAction.getAddress() + targetAction.getTotalActionLength();
|
||||
targetAction = actions.getByAddress(address);
|
||||
if (targetAction == null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
item.jumpTarget = actionItemMap.get(targetAction);
|
||||
}
|
||||
if (target >= 0) {
|
||||
Action targetAction = actions.getByAddress(target);
|
||||
item.jumpTarget = actionItemMap.get(targetAction);
|
||||
}
|
||||
|
||||
item = item.next;
|
||||
} while (item != firstAction);
|
||||
}
|
||||
|
||||
private void updateActionAddressesAndLengths() {
|
||||
ActionItem item = firstAction;
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
long address = item.action.getAddress();
|
||||
do {
|
||||
Action action = item.action;
|
||||
action.setAddress(address);
|
||||
action.updateLength();
|
||||
address += action.getTotalActionLength();
|
||||
item = item.next;
|
||||
} while (item != firstAction);
|
||||
}
|
||||
|
||||
private void updateJumps() {
|
||||
ActionItem item = firstAction;
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
long endAddress = item.prev.action.getAddress();
|
||||
do {
|
||||
Action action = item.action;
|
||||
if (action instanceof ActionIf) {
|
||||
ActionIf aIf = (ActionIf) action;
|
||||
Action target = item.jumpTarget == null ? null : item.jumpTarget.action;
|
||||
long offset;
|
||||
if (target != null) {
|
||||
offset = target.getAddress() - action.getAddress() - action.getTotalActionLength();
|
||||
} else {
|
||||
offset = endAddress - action.getAddress() - action.getTotalActionLength();
|
||||
}
|
||||
aIf.setJumpOffset((int) offset);
|
||||
} else if (action instanceof ActionJump) {
|
||||
ActionJump aJump = (ActionJump) action;
|
||||
Action target = item.jumpTarget == null ? null : item.jumpTarget.action;
|
||||
long offset;
|
||||
if (target != null) {
|
||||
offset = target.getAddress() - action.getAddress() - action.getTotalActionLength();
|
||||
} else {
|
||||
offset = endAddress - action.getAddress() - action.getTotalActionLength();
|
||||
}
|
||||
aJump.setJumpOffset((int) offset);
|
||||
}
|
||||
|
||||
item = item.next;
|
||||
} while (item != firstAction);
|
||||
}
|
||||
|
||||
private void updateActionStores(ActionList actionList) {
|
||||
ActionItem item = firstAction;
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
Action action = item.action;
|
||||
if (action instanceof ActionStore) {
|
||||
ActionStore aStore = (ActionStore) action;
|
||||
Action nextActionAfterStore = item.jumpTarget == null ? null : item.jumpTarget.action;
|
||||
Action a1 = action;
|
||||
List<Action> store = new ArrayList<>();
|
||||
while (true) {
|
||||
long address = a1.getAddress() + a1.getTotalActionLength();
|
||||
a1 = actionList.getByAddress(address);
|
||||
if (a1 == null || a1 == nextActionAfterStore) {
|
||||
break;
|
||||
}
|
||||
store.add(a1);
|
||||
}
|
||||
aStore.setStore(store);
|
||||
}
|
||||
|
||||
item = item.next;
|
||||
} while (item != firstAction);
|
||||
}
|
||||
|
||||
private void updateContainerSizes() {
|
||||
ActionItem item = firstAction;
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
Action action = item.action;
|
||||
if (action instanceof GraphSourceItemContainer) {
|
||||
GraphSourceItemContainer container = (GraphSourceItemContainer) action;
|
||||
List<ActionItem> lastActions = item.containerLastActions;
|
||||
long startAddress = action.getAddress() + container.getHeaderSize();
|
||||
for (int j = 0; j < lastActions.size(); j++) {
|
||||
Action lastAction = lastActions.get(j).action;
|
||||
int length = (int) (lastAction.getAddress() + lastAction.getTotalActionLength() - startAddress);
|
||||
container.setContainerSize(j, length);
|
||||
startAddress += length;
|
||||
}
|
||||
}
|
||||
|
||||
item = item.next;
|
||||
} while (item != firstAction);
|
||||
}
|
||||
|
||||
public void expandPushes() {
|
||||
ActionItem item = firstAction;
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
Action action = item.action;
|
||||
if (action instanceof ActionPush) {
|
||||
ActionPush push = (ActionPush) action;
|
||||
if (push.values.size() > 1) {
|
||||
for (int i = 1; i < push.values.size(); i++) {
|
||||
Object value = push.values.get(i);
|
||||
ActionPush newPush = new ActionPush(value);
|
||||
newPush.constantPool = push.constantPool;
|
||||
insertItemAfter(item, newPush);
|
||||
item = item.next;
|
||||
}
|
||||
|
||||
Object obj = push.values.get(0);
|
||||
push.values.clear();
|
||||
push.values.add(obj);
|
||||
}
|
||||
}
|
||||
|
||||
item = item.next;
|
||||
} while (item != firstAction);
|
||||
}
|
||||
|
||||
public void removeZeroJumps() {
|
||||
ActionItem item = firstAction;
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
Action action = item.action;
|
||||
if (action instanceof ActionJump) {
|
||||
if (item.jumpTarget == item.next && item.jumpTarget != firstAction) {
|
||||
item = removeItem(item);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
item = item.next;
|
||||
} while (item != firstAction);
|
||||
}
|
||||
|
||||
public void removeUnreachableActions() {
|
||||
ActionItem item = firstAction;
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateReachableFlags(null, null);
|
||||
|
||||
do {
|
||||
if (item.reachable == 0) {
|
||||
item = removeItem(item);
|
||||
continue;
|
||||
}
|
||||
|
||||
item = item.next;
|
||||
} while (item != firstAction);
|
||||
}
|
||||
|
||||
private void clearReachableFlags() {
|
||||
ActionItem item = firstAction;
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
item.reachable = 0;
|
||||
item = item.next;
|
||||
} while (item != firstAction);
|
||||
}
|
||||
|
||||
private void updateReachableFlags(ActionItem jump, ActionItem jumpTarget) {
|
||||
if (firstAction == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
clearReachableFlags();
|
||||
|
||||
firstAction.reachable = 1;
|
||||
boolean modified = true;
|
||||
while (modified) {
|
||||
modified = false;
|
||||
int i = 0;
|
||||
FastActionListIterator iterator = iterator();
|
||||
while (iterator.hasNext()) {
|
||||
ActionItem item = iterator.next();
|
||||
Action action = item.action;
|
||||
if (item.reachable == 1) {
|
||||
item.reachable = 2;
|
||||
modified = true;
|
||||
|
||||
if (item == jump) {
|
||||
if (jumpTarget.reachable == 0) {
|
||||
jumpTarget.reachable = 1;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!action.isExit() && !(action instanceof ActionJump) && item.next != null) {
|
||||
if (item.next.reachable == 0) {
|
||||
item.next.reachable = 1;
|
||||
}
|
||||
}
|
||||
|
||||
ActionItem target = item.jumpTarget;
|
||||
if (target != null) {
|
||||
if (target.reachable == 0) {
|
||||
target.reachable = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (action instanceof GraphSourceItemContainer) {
|
||||
for (ActionItem lastActionItem : item.containerLastActions) {
|
||||
if (lastActionItem != null && lastActionItem.next != null && lastActionItem.next.reachable == 0) {
|
||||
lastActionItem.next.reachable = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ActionList updateActions() {
|
||||
List<Action> resultList = new ArrayList<>(size);
|
||||
ActionItem item = firstAction;
|
||||
if (item == null) {
|
||||
return new ActionList(resultList);
|
||||
}
|
||||
|
||||
do {
|
||||
resultList.add(item.action);
|
||||
item = item.next;
|
||||
} while (item != firstAction);
|
||||
|
||||
ActionList result = new ActionList(resultList);
|
||||
updateActionAddressesAndLengths();
|
||||
updateJumps();
|
||||
updateActionStores(result);
|
||||
updateContainerSizes();
|
||||
return result;
|
||||
}
|
||||
|
||||
public ActionList toActionList() {
|
||||
return updateActions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return size == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
if (o instanceof ActionItem) {
|
||||
return actionItemSet.contains(o);
|
||||
} else if (o instanceof Action) {
|
||||
return actionItemMap.containsKey((Action) o);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FastActionListIterator iterator() {
|
||||
return new FastActionListIterator(firstAction, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
Object[] result = new Object[size];
|
||||
|
||||
ActionItem item = firstAction;
|
||||
if (item == null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
do {
|
||||
result[i] = item.action;
|
||||
item = item.next;
|
||||
i++;
|
||||
} while (item != firstAction);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T[] toArray(T[] a) {
|
||||
if (a.length != size) {
|
||||
a = (T[]) new ActionItem[size];
|
||||
}
|
||||
|
||||
ActionItem item = firstAction;
|
||||
if (item == null) {
|
||||
return a;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
do {
|
||||
a[i] = (T) item;
|
||||
item = item.next;
|
||||
i++;
|
||||
} while (item != firstAction);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(ActionItem e) {
|
||||
insertItemAfter(null, e);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
ActionItem item = null;
|
||||
if (o instanceof ActionItem) {
|
||||
item = (ActionItem) o;
|
||||
} else if (o instanceof Action) {
|
||||
item = actionItemMap.get(o);
|
||||
}
|
||||
|
||||
if (item == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
removeItem(item);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
for (Object c1 : c) {
|
||||
if (!contains(c1)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends ActionItem> c) {
|
||||
for (ActionItem c1 : c) {
|
||||
insertItemAfter(null, c1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
boolean result = false;
|
||||
for (Object c1 : c) {
|
||||
result |= remove(c1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
ActionItem item = firstAction;
|
||||
if (item == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean modified = false;
|
||||
do {
|
||||
if (!c.contains(item)) {
|
||||
item = removeItem(item);
|
||||
modified = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
item = item.next;
|
||||
} while (item != firstAction);
|
||||
return modified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
firstAction = null;
|
||||
size = 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2015 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.action.fastactionlist;
|
||||
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class FastActionListIterator implements Iterator<ActionItem> {
|
||||
|
||||
private ActionItem item;
|
||||
|
||||
private final FastActionList list;
|
||||
|
||||
private int index;
|
||||
|
||||
FastActionListIterator(ActionItem firstAction, FastActionList list) {
|
||||
item = firstAction;
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return index < list.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionItem next() {
|
||||
ActionItem result = item;
|
||||
index++;
|
||||
item = item.next;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
item = list.removeItem(item.prev);
|
||||
index--;
|
||||
}
|
||||
|
||||
public void add(Action action) {
|
||||
item = list.insertItemAfter(item.prev, action).next;
|
||||
index++;
|
||||
}
|
||||
|
||||
public void add(ActionItem actionItem) {
|
||||
item = list.insertItemAfter(item.prev, actionItem).next;
|
||||
index++;
|
||||
}
|
||||
|
||||
public ActionItem peek(int index) {
|
||||
ActionItem item = this.item;
|
||||
for (int i = 0; i < index; i++) {
|
||||
if (item == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
item = item.next;
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user