diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java index 291d2232c..f506a4525 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java @@ -30,6 +30,7 @@ import com.jpexs.decompiler.flash.abc.types.ScriptInfo; import com.jpexs.decompiler.flash.action.Action; import com.jpexs.decompiler.flash.action.ActionGraphSource; import com.jpexs.decompiler.flash.action.ActionList; +import com.jpexs.decompiler.flash.action.ActionListReader; import com.jpexs.decompiler.flash.action.ActionLocalData; import com.jpexs.decompiler.flash.action.CachedScript; import com.jpexs.decompiler.flash.action.model.ConstantPool; @@ -132,6 +133,7 @@ import com.jpexs.decompiler.graph.GraphSourceItemContainer; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.TranslateStack; import com.jpexs.decompiler.graph.model.LocalData; +import com.jpexs.helpers.ByteArrayRange; import com.jpexs.helpers.Cache; import com.jpexs.helpers.Helper; import com.jpexs.helpers.NulStream; @@ -306,6 +308,9 @@ public final class SWF implements SWFContainerItem, Timelined { @Internal private final Cache soundCache = Cache.getInstance(false, false, "sound"); + @Internal + private final Cache as2PcodeCache = Cache.getInstance(true, true, "as2pcode"); + @Internal private final Cache as2Cache = Cache.getInstance(true, false, "as2"); @@ -358,6 +363,7 @@ public final class SWF implements SWFContainerItem, Timelined { swfList.swfs.clear(); } + as2PcodeCache.clear(); as2Cache.clear(); as3Cache.clear(); frameCache.clear(); @@ -2265,6 +2271,7 @@ public final class SWF implements SWFContainerItem, Timelined { } public void clearScriptCache() { + as2PcodeCache.clear(); as2Cache.clear(); as3Cache.clear(); IdentifiersDeobfuscation.clearCache(); @@ -2283,7 +2290,9 @@ public final class SWF implements SWFContainerItem, Timelined { public static void uncache(ASMSource src) { if (src != null) { - src.getSwf().as2Cache.remove(src); + SWF swf = src.getSwf(); + swf.as2Cache.remove(src); + swf.as2PcodeCache.remove(src); } } @@ -2301,6 +2310,42 @@ public final class SWF implements SWFContainerItem, Timelined { return pack.getSwf().as3Cache.contains(pack); } + public static ActionList getCachedActionList(ASMSource src, final List listeners) throws InterruptedException { + synchronized (src) { + SWF swf = src.getSwf(); + int deobfuscationMode = Configuration.autoDeobfuscate.get() ? (Configuration.deobfuscationOldMode.get() ? 0 : 1) : -1; + if (swf != null && swf.as2PcodeCache.contains(src)) { + ActionList result = swf.as2PcodeCache.get(src); + if (result.deobfuscationMode == deobfuscationMode) { + return result; + } + } + + try { + ByteArrayRange actionBytes = src.getActionBytes(); + int prevLength = actionBytes.getPos(); + SWFInputStream rri = new SWFInputStream(swf, actionBytes.getArray()); + if (prevLength != 0) { + rri.seek(prevLength); + } + + int version = swf == null ? SWF.DEFAULT_VERSION : swf.version; + ActionList list = ActionListReader.readActionListTimeout(listeners, rri, version, prevLength, prevLength + actionBytes.getLength(), src.toString()/*FIXME?*/, deobfuscationMode); + list.deobfuscationMode = deobfuscationMode; + if (swf != null) { + swf.as2PcodeCache.put(src, list); + } + + return list; + } catch (InterruptedException ex) { + throw ex; + } catch (Exception ex) { + Logger.getLogger(SWF.class.getName()).log(Level.SEVERE, null, ex); + return new ActionList(); + } + } + } + public static CachedScript getCached(ASMSource src, ActionList actions) throws InterruptedException { SWF swf = src.getSwf(); if (swf.as2Cache.contains(src)) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionList.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionList.java index 7b1813646..51c30f4e1 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionList.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionList.java @@ -44,6 +44,8 @@ import java.util.logging.Logger; */ public class ActionList extends ArrayList { + public int deobfuscationMode; + public ActionList() { } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionListReader.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionListReader.java index d9c310491..d8ca84402 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionListReader.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionListReader.java @@ -18,7 +18,6 @@ package com.jpexs.decompiler.flash.action; 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.ActionDeobfuscatorSimpleFast; import com.jpexs.decompiler.flash.action.model.ConstantPool; import com.jpexs.decompiler.flash.action.model.DirectValueActionItem; @@ -91,9 +90,8 @@ public class ActionListReader { * @throws java.lang.InterruptedException * @throws java.util.concurrent.TimeoutException */ - public static ActionList readActionListTimeout(final List listeners, final SWFInputStream sis, final int version, final int ip, final int endIp, final String path) throws IOException, InterruptedException, TimeoutException { + public static ActionList readActionListTimeout(final List listeners, final SWFInputStream sis, final int version, final int ip, final int endIp, final String path, final int deobfuscationMode) throws IOException, InterruptedException, TimeoutException { try { - final int deobfuscationMode = Configuration.autoDeobfuscate.get() ? (Configuration.deobfuscationOldMode.get() ? 0 : 1) : -1; ActionList actions = CancellableWorker.call(new Callable() { @Override @@ -183,12 +181,6 @@ public class ActionListReader { try (Statistics s = new Statistics("ActionDeobfuscatorSimpleFast")) { new ActionDeobfuscatorSimpleFast().actionListParsed(actions, sis.getSwf()); } - /*try (Statistics s = new Statistics("ActionDeobfuscatorSimple")) { - new ActionDeobfuscatorSimple().actionListParsed(actions, sis.getSwf()); - }*/ - try (Statistics s = new Statistics("ActionDeobfuscator")) { - new ActionDeobfuscator().actionListParsed(actions, sis.getSwf()); - } } catch (ThreadDeath | InterruptedException ex) { throw ex; } catch (Throwable ex) { @@ -881,7 +873,7 @@ public class ActionListReader { return entryAction; } - public static void fixConstantPools(List listeners, ActionList actions) { + public static boolean fixConstantPools(List listeners, ActionList actions) { Action lastAction = actions.get(actions.size() - 1); int endIp = (int) lastAction.getAddress(); List actionMap = new ArrayList<>(endIp); @@ -894,23 +886,26 @@ public class ActionListReader { try { int startIp = (int) actions.get(0).getAddress(); - fixConstantPools(listeners, new ConstantPool(), actionMap, new TreeMap<>(), startIp, startIp, endIp, null, true, new ArrayList<>()); + return fixConstantPools(listeners, new ConstantPool(), actionMap, new TreeMap<>(), startIp, startIp, endIp, null, true, new ArrayList<>()); } catch (IOException ex) { // ignore } + + return false; } - private static void fixConstantPools(List listeners, ConstantPool cpool, + private static boolean fixConstantPools(List listeners, ConstantPool cpool, List actions, Map actionMap, int ip, int startIp, int endIp, String path, boolean indeterminate, List visitedContainers) throws IOException { if (visitedContainers.contains(ip)) { - return; + return false; } visitedContainers.add(ip); Queue jumpQueue = new LinkedList<>(); jumpQueue.add(ip); + boolean ret = false; while (!jumpQueue.isEmpty()) { ip = jumpQueue.remove(); if (ip < startIp) { @@ -949,10 +944,19 @@ public class ActionListReader { } } - a.setAddress(ip); + if (a.getAddress() != ip) { + a.setAddress(ip); + ret = true; + } if (a instanceof ActionPush && cpool != null) { - ((ActionPush) a).constantPool = cpool.constants; + ActionPush push = (ActionPush) a; + if (push.constantPool != cpool.constants) { + push.constantPool = cpool.constants.isEmpty() ? null : cpool.constants; + if (push.constantPool != null) { + ret = true; + } + } } else if (a instanceof ActionConstantPool) { cpool = new ConstantPool(((ActionConstantPool) a).constantPool); } else if (a instanceof ActionIf) { @@ -976,7 +980,7 @@ public class ActionListReader { if (size != 0) { int ip2 = ip + actionLengthWithHeader; int endIp2 = ip + actionLengthWithHeader + (int) size; - fixConstantPools(listeners, cpool, actions, actionMap, ip2, startIp, endIp2, newPath, indeterminate, visitedContainers); + ret |= fixConstantPools(listeners, cpool, actions, actionMap, ip2, startIp, endIp2, newPath, indeterminate, visitedContainers); actionLengthWithHeader += size; } } @@ -989,6 +993,8 @@ public class ActionListReader { } } } + + return ret; } private static void deobfustaceActionListAtPosRecursiveOld(List listeners, List output, HashMap> containers, ActionLocalData localData, TranslateStack stack, ConstantPool cpool, List actions, int ip, List ret, int startIp, int endip, String path, Map visited, boolean indeterminate, Map> decisionStates, int version, int recursionLevel, int maxRecursionLevel) throws IOException, InterruptedException { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/deobfuscation/ActionDeobfuscatorSimple.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/deobfuscation/ActionDeobfuscatorSimple.java index 76370760e..9dd661c77 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/deobfuscation/ActionDeobfuscatorSimple.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/deobfuscation/ActionDeobfuscatorSimple.java @@ -83,7 +83,7 @@ public class ActionDeobfuscatorSimple implements SWFDecompilerListener { @Override public void actionListParsed(ActionList actions, SWF swf) throws InterruptedException { - //removeGetTimes(actions); + removeGetTimes(actions); removeObfuscationIfs(actions); } @@ -398,6 +398,10 @@ public class ActionDeobfuscatorSimple implements SWFDecompilerListener { } } + @Override + public void actionTreeCreated(List tree, SWF swf) { + } + @Override public byte[] proxyFileCatched(byte[] data) { return null; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/deobfuscation/ActionDeobfuscatorSimpleFast.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/deobfuscation/ActionDeobfuscatorSimpleFast.java index e32bbb4b0..f6af32e43 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/deobfuscation/ActionDeobfuscatorSimpleFast.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/deobfuscation/ActionDeobfuscatorSimpleFast.java @@ -21,10 +21,14 @@ 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.ActionListReader; 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.model.DirectValueActionItem; +import com.jpexs.decompiler.flash.action.model.ReturnActionItem; +import com.jpexs.decompiler.flash.action.special.ActionEnd; import com.jpexs.decompiler.flash.action.swf4.ActionAdd; import com.jpexs.decompiler.flash.action.swf4.ActionAnd; import com.jpexs.decompiler.flash.action.swf4.ActionAsciiToChar; @@ -32,6 +36,7 @@ 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.ActionGetVariable; import com.jpexs.decompiler.flash.action.swf4.ActionIf; import com.jpexs.decompiler.flash.action.swf4.ActionJump; import com.jpexs.decompiler.flash.action.swf4.ActionLess; @@ -41,6 +46,7 @@ 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.ActionSetVariable; import com.jpexs.decompiler.flash.action.swf4.ActionStringAdd; import com.jpexs.decompiler.flash.action.swf4.ActionStringEquals; import com.jpexs.decompiler.flash.action.swf4.ActionStringLength; @@ -56,13 +62,17 @@ 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.ActionCallFunction; +import com.jpexs.decompiler.flash.action.swf5.ActionConstantPool; import com.jpexs.decompiler.flash.action.swf5.ActionDecrement; +import com.jpexs.decompiler.flash.action.swf5.ActionDefineFunction; import com.jpexs.decompiler.flash.action.swf5.ActionDefineLocal; 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.ActionReturn; import com.jpexs.decompiler.flash.action.swf5.ActionToNumber; import com.jpexs.decompiler.flash.action.swf5.ActionToString; import com.jpexs.decompiler.flash.action.swf5.ActionTypeOf; @@ -73,10 +83,14 @@ import com.jpexs.decompiler.flash.helpers.SWFDecompilerListener; import com.jpexs.decompiler.graph.Graph; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.TranslateStack; +import com.jpexs.decompiler.graph.model.FalseItem; +import com.jpexs.decompiler.graph.model.PushItem; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; /** * @@ -90,14 +104,22 @@ public class ActionDeobfuscatorSimpleFast implements SWFDecompilerListener { public void actionListParsed(ActionList actions, SWF swf) throws InterruptedException { FastActionList fastActions = new FastActionList(actions); fastActions.expandPushes(); + Map fakeFunctions = getFakeFunctionResults(fastActions); boolean changed = true; + boolean useVariables = false; while (changed) { changed = removeGetTimes(fastActions); - changed |= removeObfuscationIfs(fastActions); + changed |= removeObfuscationIfs(fastActions, fakeFunctions, useVariables); changed |= removeObfuscatedUnusedVariables(fastActions); + + actions.setActions(fastActions.toActionList()); + changed |= ActionListReader.fixConstantPools(null, actions); + if (!changed && !useVariables) { + useVariables = true; + changed = true; + } } - actions.setActions(fastActions.toActionList()); } private boolean removeGetTimes(FastActionList actions) { @@ -167,7 +189,7 @@ public class ActionDeobfuscatorSimpleFast implements SWFDecompilerListener { return ret; } - private boolean removeObfuscationIfs(FastActionList actions) throws InterruptedException { + private boolean removeObfuscationIfs(FastActionList actions, Map fakeFunctions, boolean useVariables) throws InterruptedException { if (actions.isEmpty()) { return false; } @@ -176,21 +198,63 @@ public class ActionDeobfuscatorSimpleFast implements SWFDecompilerListener { actions.removeUnreachableActions(); actions.removeZeroJumps(); + ActionConstantPool cPool = getConstantPool(actions); FastActionListIterator iterator = actions.iterator(); + boolean first = true; while (iterator.hasNext()) { ActionItem actionItem = iterator.next(); ExecutionResult result = new ExecutionResult(); - executeActions(actionItem, actions.last(), result); + executeActions(actionItem, cPool, result, fakeFunctions, useVariables, first); - if (result.item != null) { + if (result.item != null && result.resultValue == null) { int newIstructionCount = 1 /*jump */ + result.stack.size(); + if (result.constantPool != null) { + newIstructionCount++; + } + + newIstructionCount += 3 * result.variables.size(); /* 2x Push + Set or Define */ + + boolean allValueValid = true; + for (Object value : result.variables.values()) { + if (!ActionPush.isValidValue(value)) { + allValueValid = false; + break; + } + } + int unreachableCount = actions.getUnreachableActionCount(actionItem, result.item); - if (newIstructionCount < unreachableCount) { - if (result.stack.isEmpty() && actionItem.action instanceof ActionJump) { + if (allValueValid && newIstructionCount < unreachableCount) { + if (result.stack.isEmpty() && result.variables.isEmpty() && result.constantPool == null && actionItem.action instanceof ActionJump) { actionItem.setJumpTarget(result.item); } else { ActionItem prevActionItem = actionItem.prev; + if (result.constantPool != null) { + ActionConstantPool constantPool2 = new ActionConstantPool(new ArrayList<>(result.constantPool.constantPool)); + ActionItem constantPoolItem = new ActionItem(constantPool2); + iterator.addBefore(constantPoolItem); + } + + for (String variableName : result.variables.keySet()) { + Object value = result.variables.get(variableName); + ActionPush push = new ActionPush(variableName); + ActionItem pushItem = new ActionItem(push); + iterator.addBefore(pushItem); + push = new ActionPush(value); + pushItem = new ActionItem(push); + iterator.addBefore(pushItem); + + if (result.defines.contains(variableName)) { + ActionDefineLocal defineLocal = new ActionDefineLocal(); + ActionItem defineLocalItem = new ActionItem(defineLocal); + iterator.addBefore(defineLocalItem); + } else { + ActionSetVariable setVariable = new ActionSetVariable(); + ActionItem setVariableItem = new ActionItem(setVariable); + iterator.addBefore(setVariableItem); + } + } + if (!result.stack.isEmpty()) { for (GraphTargetItem graphTargetItem : result.stack) { ActionPush push = new ActionPush(graphTargetItem.getResult()); @@ -216,7 +280,10 @@ public class ActionDeobfuscatorSimpleFast implements SWFDecompilerListener { ret = true; } } + + first = false; } + return ret; } @@ -273,6 +340,66 @@ public class ActionDeobfuscatorSimpleFast implements SWFDecompilerListener { return ret; } + private ActionConstantPool getConstantPool(FastActionList actions) { + ActionConstantPool cPool = null; + for (ActionItem actionItem : actions) { + Action action = actionItem.action; + if (action instanceof ActionConstantPool) { + if (cPool != null) { + // there are multiple constant pools + return null; + } + cPool = (ActionConstantPool) action; + } + } + return cPool; + } + + private Map getFakeFunctionResults(FastActionList actions) throws InterruptedException { + /* + DefineFunction "fakeName" 0 { + Push 1777 + Return + } + */ + + Map results = new HashMap<>(); + + for (ActionItem actionItem : actions) { + Action action = actionItem.action; + if (action instanceof ActionDefineFunction) { + ActionDefineFunction def = (ActionDefineFunction) action; + if (def.paramNames.isEmpty() && def.functionName.length() > 0) { + // remove funcion only when the function name contains only non printable characters + if (!isFakeName(def.functionName)) { + continue; + } + + ExecutionResult result = new ExecutionResult(); + ActionItem lastActionItem = actionItem.getContainerLastActions().get(0); + // has at least 1 inner item + if (lastActionItem != actionItem) { + actions.setExcludedFlags(true); + ActionItem actionItem2 = actionItem; + do { + actionItem2.excluded = false; + actionItem2 = actionItem2.next; + } while (actionItem2 != lastActionItem && actionItem2 != actions.last()); + actionItem2.excluded = false; + executeActions(actionItem.next, null, result, null, true, false); + if (result.resultValue != null) { + results.put(def.functionName, result.resultValue); + actions.removeIncludedActions(); + } + } + } + } + } + + actions.setExcludedFlags(false); + return results; + } + protected boolean isFakeName(String name) { for (char ch : name.toCharArray()) { if (ch > 31) { @@ -283,13 +410,18 @@ public class ActionDeobfuscatorSimpleFast implements SWFDecompilerListener { return true; } - private void executeActions(ActionItem item, ActionItem endItem, ExecutionResult result) throws InterruptedException { + private void executeActions(ActionItem item, ActionConstantPool constantPool, ExecutionResult result, Map fakeFunctions, boolean useVariables, boolean allowGetUninitializedVariables) throws InterruptedException { List output = new ArrayList<>(); ActionLocalData localData = new ActionLocalData(); FixItemCounterTranslateStack stack = new FixItemCounterTranslateStack(""); int instructionsProcessed = 0; + ActionConstantPool lastConstantPool = null; while (true) { + if (item.isExcluded()) { + break; + } + if (Thread.currentThread().isInterrupted()) { throw new InterruptedException(); } @@ -305,13 +437,83 @@ public class ActionDeobfuscatorSimpleFast implements SWFDecompilerListener { 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; + if (action instanceof ActionConstantPool) { + lastConstantPool = (ActionConstantPool) action; } - action.translate(localData, stack, output, Graph.SOP_USE_STATIC, ""); + if (action instanceof ActionDefineLocal) { + if (stack.size() < 2) { + break; + } + + String variableName = stack.peek(2).getResult().toString(); + result.defines.add(variableName); + } + + if (action instanceof ActionGetVariable) { + if (stack.isEmpty()) { + break; + } + + GraphTargetItem variableNameObj = stack.peek(); + if (!(variableNameObj instanceof DirectValueActionItem)) { + // avoid dynamic variable names, for example: eval("item" add i); + break; + } + + String variableName = variableNameObj.getResult().toString(); + if (!localData.variables.containsKey(variableName) + && (!allowGetUninitializedVariables || !isFakeName(variableName))) { + break; + } + } + + if (action instanceof ActionSetVariable) { + if (stack.size() < 2) { + break; + } + + if (!(stack.peek(2) instanceof DirectValueActionItem)) { + // avoid dynamic variable names, for example: set("item" add i, 1); + break; + } + } + + if (action instanceof ActionCallFunction) { + if (stack.size() < 2) { + break; + } + + String functionName = stack.pop().getResult().toString(); + long numArgs = EcmaScript.toUint32(stack.pop().getResult()); + if (numArgs == 0) { + if (fakeFunctions != null && fakeFunctions.containsKey(functionName)) { + stack.push(new DirectValueActionItem(fakeFunctions.get(functionName))); + } else { + break; + } + } else { + break; + } + } else { + // do not throw EmptyStackException, much faster + int requiredStackSize = action.getStackPopCount(localData, stack); + if (stack.size() < requiredStackSize) { + break; + } + + action.translate(localData, stack, output, Graph.SOP_USE_STATIC, ""); + } + + if (!useVariables && (action instanceof ActionDefineLocal + || action instanceof ActionGetVariable + || action instanceof ActionSetVariable + || action instanceof ActionConstantPool + || action instanceof ActionCallFunction + || action instanceof ActionReturn + || action instanceof ActionEnd)) { + break; + } if (!(action instanceof ActionPush || action instanceof ActionPushDuplicate @@ -352,7 +554,14 @@ public class ActionDeobfuscatorSimpleFast implements SWFDecompilerListener { || action instanceof ActionStringLess || action instanceof ActionSubtract || action instanceof ActionIf - || action instanceof ActionJump)) { + || action instanceof ActionJump + || action instanceof ActionDefineLocal + || action instanceof ActionGetVariable + || action instanceof ActionSetVariable + || action instanceof ActionConstantPool + || action instanceof ActionCallFunction + || action instanceof ActionReturn + || action instanceof ActionEnd)) { break; } @@ -361,7 +570,7 @@ public class ActionDeobfuscatorSimpleFast implements SWFDecompilerListener { boolean ok = true; instructionsProcessed += push.values.size() - 1; for (Object value : push.values) { - if (value instanceof ConstantIndex || value instanceof RegisterNumber) { + if ((constantPool == null && value instanceof ConstantIndex) || value instanceof RegisterNumber) { ok = false; break; } @@ -371,11 +580,12 @@ public class ActionDeobfuscatorSimpleFast implements SWFDecompilerListener { } } + ActionItem prevItem = item; if (action instanceof ActionJump) { item = item.getJumpTarget(); } else if (action instanceof ActionIf) { if (stack.isEmpty()) { - return; + break; } if (EcmaScript.toBoolean(stack.pop().getResult())) { @@ -389,12 +599,39 @@ public class ActionDeobfuscatorSimpleFast implements SWFDecompilerListener { instructionsProcessed++; - if (stack.allItemsFixed() && !(action instanceof ActionPush)) { + if ((stack.allItemsFixed() || action instanceof ActionEnd) && !(action instanceof ActionPush)) { result.item = item; result.instructionsProcessed = instructionsProcessed; + result.constantPool = lastConstantPool; + result.variables.clear(); + for (String variableName : localData.variables.keySet()) { + Object value = localData.variables.get(variableName).getResult(); + result.variables.put(variableName, value); + } result.stack.clear(); result.stack.addAll(stack); } + + if (action instanceof ActionReturn) { + if (output.size() > 0) { + ReturnActionItem ret = (ReturnActionItem) output.get(output.size() - 1); + result.resultValue = ret.value.getResult(); + } + break; + } else if (action instanceof ActionEnd) { + result.item = prevItem; + break; + } + } + } + + @Override + public void actionTreeCreated(List tree, SWF swf) { + if (tree.size() > 0) { + GraphTargetItem firstItem = tree.get(0); + if (firstItem instanceof PushItem && firstItem.value instanceof FalseItem) { + tree.remove(0); + } } } @@ -424,5 +661,11 @@ public class ActionDeobfuscatorSimpleFast implements SWFDecompilerListener { public TranslateStack stack = new TranslateStack("?"); public Object resultValue; + + public ActionConstantPool constantPool; + + public Map variables = new HashMap<>(); + + public Set defines = new HashSet<>(); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/fastactionlist/ActionItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/fastactionlist/ActionItem.java index 040a3a92b..8d85cc1a2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/fastactionlist/ActionItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/fastactionlist/ActionItem.java @@ -44,6 +44,8 @@ public class ActionItem { // 1 means reachable, 2 means reachable and processed int reachable; + public boolean excluded; + public ActionItem(Action action) { this.action = action; } @@ -143,4 +145,8 @@ public class ActionItem { return lastActionOf; } + + public boolean isExcluded() { + return excluded; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/fastactionlist/FastActionList.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/fastactionlist/FastActionList.java index 0dcafa7c5..8efef6c70 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/fastactionlist/FastActionList.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/fastactionlist/FastActionList.java @@ -409,6 +409,22 @@ public class FastActionList implements Collection { } while (item != firstItem); } + public void removeIncludedActions() { + ActionItem item = firstItem; + if (item == null) { + return; + } + + do { + if (!item.excluded) { + item = removeItem(item); + continue; + } + + item = item.next; + } while (item != firstItem); + } + public int getUnreachableActionCount(ActionItem jump, ActionItem jumpTarget) { ActionItem item = firstItem; if (item == null) { @@ -442,6 +458,18 @@ public class FastActionList implements Collection { } while (item != firstItem); } + public void setExcludedFlags(boolean value) { + ActionItem item = firstItem; + if (item == null) { + return; + } + + do { + item.excluded = value; + item = item.next; + } while (item != firstItem); + } + private void updateReachableFlags(ActionItem jump, ActionItem jumpTarget) { if (firstItem == null) { return; @@ -453,9 +481,7 @@ public class FastActionList implements Collection { boolean modified = true; while (modified) { modified = false; - FastActionListIterator iterator = iterator(); - while (iterator.hasNext()) { - ActionItem item = iterator.next(); + for (ActionItem item : this) { Action action = item.action; if (item.reachable == 1) { item.reachable = 2; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf4/ActionPush.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf4/ActionPush.java index fcd8df2e5..e961569b0 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf4/ActionPush.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf4/ActionPush.java @@ -262,7 +262,7 @@ public class ActionPush extends Action { case ASMParsedSymbol.TYPE_STRING: count++; if (constantPool.contains((String) symb.value)) { - values.add(new ConstantIndex(constantPool.indexOf(symb.value), constantPool)); + values.add(new ConstantIndex(constantPool.indexOf(symb.value))); } else { values.add(symb.value); } @@ -317,15 +317,15 @@ public class ActionPush extends Action { public String toStringNoQ(int i) { String ret; - if (values.get(i) instanceof ConstantIndex) { - ((ConstantIndex) values.get(i)).constantPool = constantPool; - ret = ((ConstantIndex) values.get(i)).toStringNoQ(); - } else if (values.get(i) instanceof String) { - ret = (String) values.get(i); - } else if (values.get(i) instanceof RegisterNumber) { - ret = ((RegisterNumber) values.get(i)).toStringNoName(); + Object value = values.get(i); + if (value instanceof ConstantIndex) { + ret = ((ConstantIndex) value).toStringNoQ(constantPool); + } else if (value instanceof String) { + ret = (String) value; + } else if (value instanceof RegisterNumber) { + ret = ((RegisterNumber) value).toStringNoName(); } else { - ret = values.get(i).toString(); + ret = value.toString(); } return ret; } @@ -334,8 +334,7 @@ public class ActionPush extends Action { String ret; Object value = values.get(i); if (value instanceof ConstantIndex) { - ((ConstantIndex) value).constantPool = constantPool; - ret = ((ConstantIndex) value).toString(); + ret = ((ConstantIndex) value).toString(constantPool); } else if (value instanceof String) { ret = "\"" + Helper.escapeActionScriptString((String) value) + "\""; } else if (value instanceof RegisterNumber) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf4/ConstantIndex.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf4/ConstantIndex.java index 23b4d9565..257b0591f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf4/ConstantIndex.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf4/ConstantIndex.java @@ -19,44 +19,30 @@ package com.jpexs.decompiler.flash.action.swf4; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.helpers.Helper; import java.io.Serializable; -import java.util.ArrayList; import java.util.List; public class ConstantIndex implements Serializable { public int index; - public List constantPool; - public ConstantIndex(int index) { this.index = index; - this.constantPool = new ArrayList<>(); } - public ConstantIndex(int index, List constantPool) { - this.index = index; - this.constantPool = constantPool; - } - - public String toStringNoQ() { + public String toStringNoQ(List constantPool) { if (Configuration.resolveConstants.get()) { - if (constantPool != null) { - if (index < constantPool.size()) { - return constantPool.get(index); - } + if (constantPool != null && index < constantPool.size()) { + return constantPool.get(index); } } return "constant" + index; } - @Override - public String toString() { + public String toString(List constantPool) { if (Configuration.resolveConstants.get()) { - if (constantPool != null) { - if (index < constantPool.size()) { - return "\"" + Helper.escapeActionScriptString(constantPool.get(index)) + "\""; - } + if (constantPool != null && index < constantPool.size()) { + return "\"" + Helper.escapeActionScriptString(constantPool.get(index)) + "\""; } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/SWFDecompilerListener.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/SWFDecompilerListener.java index cd0cc8c21..26acc8e22 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/SWFDecompilerListener.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/SWFDecompilerListener.java @@ -20,6 +20,8 @@ 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.ActionList; +import com.jpexs.decompiler.graph.GraphTargetItem; +import java.util.List; /** * @@ -33,6 +35,8 @@ public interface SWFDecompilerListener { void actionListParsed(ActionList actions, SWF swf) throws InterruptedException; + void actionTreeCreated(List tree, SWF swf) throws InterruptedException; + void abcParsed(ABC abc, SWF swf); void methodBodyParsed(MethodBody body, SWF swf); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java index 2e2fae597..0aa91ea11 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java @@ -22,7 +22,6 @@ 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.ActionList; -import com.jpexs.decompiler.flash.action.ActionListReader; import com.jpexs.decompiler.flash.action.ConstantPoolTooBigException; import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; @@ -47,8 +46,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; /** * Defines a button character @@ -180,21 +177,7 @@ public class DefineButtonTag extends ButtonTag implements ASMSource { */ @Override public ActionList getActions() throws InterruptedException { - try { - int prevLength = actionBytes.getPos(); - SWFInputStream rri = new SWFInputStream(swf, actionBytes.getArray()); - if (prevLength != 0) { - rri.seek(prevLength); - } - - ActionList list = ActionListReader.readActionListTimeout(listeners, rri, getVersion(), prevLength, prevLength + actionBytes.getLength(), toString()/*FIXME?*/); - return list; - } catch (InterruptedException ex) { - throw ex; - } catch (Exception ex) { - Logger.getLogger(DefineButtonTag.class.getName()).log(Level.SEVERE, null, ex); - return new ActionList(); - } + return SWF.getCachedActionList(this, listeners); } @Override @@ -203,8 +186,8 @@ public class DefineButtonTag extends ButtonTag implements ASMSource { } @Override - public byte[] getActionBytes() { - return actionBytes.getRangeData(); + public ByteArrayRange getActionBytes() { + return actionBytes; } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoActionTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoActionTag.java index a183bb957..faec53f29 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoActionTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoActionTag.java @@ -22,7 +22,6 @@ 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.ActionList; -import com.jpexs.decompiler.flash.action.ActionListReader; import com.jpexs.decompiler.flash.action.ConstantPoolTooBigException; import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; @@ -33,8 +32,6 @@ import com.jpexs.helpers.Helper; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; /** * Instructs Flash Player to perform a list of actions when the current frame is @@ -134,21 +131,7 @@ public class DoActionTag extends Tag implements ASMSource { @Override public ActionList getActions() throws InterruptedException { - try { - int prevLength = actionBytes.getPos(); - SWFInputStream rri = new SWFInputStream(swf, actionBytes.getArray()); - if (prevLength != 0) { - rri.seek(prevLength); - } - - ActionList list = ActionListReader.readActionListTimeout(listeners, rri, getVersion(), prevLength, prevLength + actionBytes.getLength(), toString()/*FIXME?*/); - return list; - } catch (InterruptedException ex) { - throw ex; - } catch (Exception ex) { - Logger.getLogger(DoActionTag.class.getName()).log(Level.SEVERE, null, ex); - return new ActionList(); - } + return SWF.getCachedActionList(this, listeners); } @Override @@ -157,8 +140,8 @@ public class DoActionTag extends Tag implements ASMSource { } @Override - public byte[] getActionBytes() { - return actionBytes.getRangeData(); + public ByteArrayRange getActionBytes() { + return actionBytes; } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java index d1f498f82..99ff05466 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java @@ -22,7 +22,6 @@ 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.ActionList; -import com.jpexs.decompiler.flash.action.ActionListReader; import com.jpexs.decompiler.flash.action.ConstantPoolTooBigException; import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; @@ -36,8 +35,6 @@ import com.jpexs.helpers.Helper; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; /** * @@ -132,21 +129,7 @@ public class DoInitActionTag extends Tag implements CharacterIdTag, ASMSource { @Override public ActionList getActions() throws InterruptedException { - try { - int prevLength = actionBytes.getPos(); - SWFInputStream rri = new SWFInputStream(swf, actionBytes.getArray()); - if (prevLength != 0) { - rri.seek(prevLength); - } - - ActionList list = ActionListReader.readActionListTimeout(listeners, rri, getVersion(), prevLength, prevLength + actionBytes.getLength(), toString()/*FIXME?*/); - return list; - } catch (InterruptedException ex) { - throw ex; - } catch (Exception ex) { - Logger.getLogger(DoInitActionTag.class.getName()).log(Level.SEVERE, null, ex); - return new ActionList(); - } + return SWF.getCachedActionList(this, listeners); } @Override @@ -155,8 +138,8 @@ public class DoInitActionTag extends Tag implements CharacterIdTag, ASMSource { } @Override - public byte[] getActionBytes() { - return actionBytes.getRangeData(); + public ByteArrayRange getActionBytes() { + return actionBytes; } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ASMSource.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ASMSource.java index e4a81aa90..13bacc8b7 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ASMSource.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ASMSource.java @@ -23,6 +23,7 @@ import com.jpexs.decompiler.flash.action.ConstantPoolTooBigException; import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.helpers.ByteArrayRange; import java.util.List; /** @@ -67,7 +68,7 @@ public interface ASMSource extends Exportable { public void setModified(); - public byte[] getActionBytes(); + public ByteArrayRange getActionBytes(); public void setActionBytes(byte[] actionBytes); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/BUTTONCONDACTION.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/BUTTONCONDACTION.java index 97b9af475..53467b4c3 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/BUTTONCONDACTION.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/BUTTONCONDACTION.java @@ -21,7 +21,6 @@ import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.action.Action; import com.jpexs.decompiler.flash.action.ActionList; -import com.jpexs.decompiler.flash.action.ActionListReader; import com.jpexs.decompiler.flash.action.ConstantPoolTooBigException; import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; @@ -36,8 +35,6 @@ import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; /** * Actions to execute at particular button events @@ -50,11 +47,6 @@ public class BUTTONCONDACTION implements ASMSource, Serializable { private Tag tag; - @Override - public SWF getSwf() { - return swf; - } - // Constructor for Generic tag editor. public BUTTONCONDACTION() { swf = null; @@ -62,12 +54,6 @@ public class BUTTONCONDACTION implements ASMSource, Serializable { actionBytes = new ByteArrayRange(SWFInputStream.BYTE_ARRAY_EMPTY); } - @Override - public void setSourceTag(Tag t) { - this.tag = t; - this.swf = t.getSwf(); - } - public BUTTONCONDACTION(SWF swf, SWFInputStream sis, Tag tag) throws IOException { this.swf = swf; this.tag = tag; @@ -86,6 +72,11 @@ public class BUTTONCONDACTION implements ASMSource, Serializable { actionBytes = sis.readByteRangeEx(condActionSize <= 0 ? sis.available() : condActionSize - 4, "actionBytes"); } + @Override + public SWF getSwf() { + return swf; + } + /** * Is this BUTTONCONDACTION last in the list? */ @@ -207,22 +198,7 @@ public class BUTTONCONDACTION implements ASMSource, Serializable { */ @Override public ActionList getActions() throws InterruptedException { - try { - int prevLength = actionBytes.getPos(); - SWFInputStream rri = new SWFInputStream(swf, actionBytes.getArray()); - if (prevLength != 0) { - rri.seek(prevLength); - } - - ActionList list = ActionListReader.readActionListTimeout(listeners, rri, swf.version, prevLength, prevLength + actionBytes.getLength(), toString()/*FIXME?*/); - return list; - - } catch (InterruptedException ex) { - throw ex; - } catch (Exception ex) { - Logger.getLogger(BUTTONCONDACTION.class.getName()).log(Level.SEVERE, null, ex); - return new ActionList(); - } + return SWF.getCachedActionList(this, listeners); } @Override @@ -231,8 +207,8 @@ public class BUTTONCONDACTION implements ASMSource, Serializable { } @Override - public byte[] getActionBytes() { - return actionBytes.getRangeData(); + public ByteArrayRange getActionBytes() { + return actionBytes; } @Override @@ -349,4 +325,10 @@ public class BUTTONCONDACTION implements ASMSource, Serializable { public Tag getSourceTag() { return tag; } + + @Override + public void setSourceTag(Tag t) { + this.tag = t; + this.swf = t.getSwf(); + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/CLIPACTIONRECORD.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/CLIPACTIONRECORD.java index 4c486f759..1a52f1616 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/CLIPACTIONRECORD.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/CLIPACTIONRECORD.java @@ -21,7 +21,6 @@ import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.action.Action; import com.jpexs.decompiler.flash.action.ActionList; -import com.jpexs.decompiler.flash.action.ActionListReader; import com.jpexs.decompiler.flash.action.ConstantPoolTooBigException; import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; @@ -35,8 +34,6 @@ import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; /** * Event handler @@ -194,21 +191,7 @@ public class CLIPACTIONRECORD implements ASMSource, Serializable { @Override public ActionList getActions() throws InterruptedException { - try { - int prevLength = actionBytes.getPos(); - SWFInputStream rri = new SWFInputStream(swf, actionBytes.getArray()); - if (prevLength != 0) { - rri.seek(prevLength); - } - - ActionList list = ActionListReader.readActionListTimeout(listeners, rri, swf.version, prevLength, prevLength + actionBytes.getLength(), toString()/*FIXME?*/); - return list; - } catch (InterruptedException ex) { - throw ex; - } catch (Exception ex) { - Logger.getLogger(CLIPACTIONRECORD.class.getName()).log(Level.SEVERE, null, ex); - return new ActionList(); - } + return SWF.getCachedActionList(this, listeners); } @Override @@ -217,8 +200,8 @@ public class CLIPACTIONRECORD implements ASMSource, Serializable { } @Override - public byte[] getActionBytes() { - return actionBytes.getRangeData(); + public ByteArrayRange getActionBytes() { + return actionBytes; } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java index 7182dc74c..287631fcc 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java @@ -2194,8 +2194,8 @@ public class Graph { exprList.add(expr); checkContinueAtTheEnd(commands, currentLoop); ret.add(index, li = new DoWhileItem(null, currentLoop, commands, exprList)); - } + loopTypeFound = true; } } @@ -2263,7 +2263,6 @@ public class Graph { } return ret; - } protected void checkGraph(List allBlocks) { diff --git a/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java b/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java index 175b4ef7d..f1671e7e4 100644 --- a/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java @@ -347,7 +347,7 @@ public class ActionPanel extends JPanel implements SearchListener