diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/BaseLocalData.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/BaseLocalData.java index 2a0bd7814..7d97dee6a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/BaseLocalData.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/BaseLocalData.java @@ -19,6 +19,7 @@ package com.jpexs.decompiler.flash; import com.jpexs.decompiler.graph.GraphPart; import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.SecondPassData; +import com.jpexs.helpers.Reference; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Set; @@ -55,6 +56,11 @@ public abstract class BaseLocalData { */ public Set usedDeobfuscations = new LinkedHashSet<>(); + /** + * Max temp index + */ + public Reference maxTempIndex = new Reference<>(0); + /** * Constructor. */ 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 d98e71364..e472992f7 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java @@ -3823,7 +3823,7 @@ public final class SWF implements SWFContainerItem, Timelined, Openable { break; } - stack.setConnectedOutput(0, output); + stack.setConnectedOutput(0, output, localData); ins.translate(localData, stack, output, staticOperation, path); if (ins.isExit()) { break; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/AVM2LocalData.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/AVM2LocalData.java index 24d93ca7d..6b7bc1386 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/AVM2LocalData.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/AVM2LocalData.java @@ -298,6 +298,7 @@ public class AVM2LocalData extends BaseLocalData { bottomSetLocals = localData.bottomSetLocals; swfVersion = localData.swfVersion; usedDeobfuscations = localData.usedDeobfuscations; + maxTempIndex = localData.maxTempIndex; } /** diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java index e41dfb5fe..959614f63 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java @@ -1826,6 +1826,7 @@ public class AVM2Code implements Cloneable { /** * Converts to source output. * + * @param maxTempIndex Max temp index * @param output Output * @param swfVersion SWF version * @param switchParts Switch parts @@ -1857,7 +1858,7 @@ public class AVM2Code implements Cloneable { * @throws ConvertException On convert error * @throws InterruptedException On interrupt */ - public void toSourceOutput(List output, int swfVersion, Set switchParts, List callStack, AbcIndexing abcIndex, Map> setLocalPosToGetLocalPos, boolean thisHasDefaultToPrimitive, Reference lineStartItem, String path, GraphPart part, boolean processJumps, boolean isStatic, int scriptIndex, int classIndex, HashMap localRegs, TranslateStack stack, ScopeStack scopeStack, ScopeStack localScopeStack, ABC abc, MethodBody body, int start, int end, HashMap localRegNames, HashMap localRegTypes, List fullyQualifiedNames, boolean[] visited, HashMap localRegAssignmentIps, LinkedIdentityHashSet bottomStackSetLocals, Set usedDeobfuscations) throws ConvertException, InterruptedException { + public void toSourceOutput(Reference maxTempIndex, List output, int swfVersion, Set switchParts, List callStack, AbcIndexing abcIndex, Map> setLocalPosToGetLocalPos, boolean thisHasDefaultToPrimitive, Reference lineStartItem, String path, GraphPart part, boolean processJumps, boolean isStatic, int scriptIndex, int classIndex, HashMap localRegs, TranslateStack stack, ScopeStack scopeStack, ScopeStack localScopeStack, ABC abc, MethodBody body, int start, int end, HashMap localRegNames, HashMap localRegTypes, List fullyQualifiedNames, boolean[] visited, HashMap localRegAssignmentIps, LinkedIdentityHashSet bottomStackSetLocals, Set usedDeobfuscations) throws ConvertException, InterruptedException { boolean debugMode = DEBUG_MODE; if (debugMode) { System.err.println("OPEN SubSource:" + start + "-" + end + " " + code.get(start).toString() + " to " + code.get(end).toString()); @@ -1976,7 +1977,7 @@ public class AVM2Code implements Cloneable { } else */ if ((ins.definition instanceof ReturnValueIns) || (ins.definition instanceof ReturnVoidIns) || (ins.definition instanceof ThrowIns)) { - ins.definition.translate(usedDeobfuscations, swfVersion, switchParts, callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, localScopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssignmentIps, ip, this, thisHasDefaultToPrimitive, bottomStackSetLocals); + ins.definition.translate(maxTempIndex, usedDeobfuscations, swfVersion, switchParts, callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, localScopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssignmentIps, ip, this, thisHasDefaultToPrimitive, bottomStackSetLocals); //ip = end + 1; break; } else if (ins.definition instanceof NewFunctionIns) { @@ -2012,13 +2013,13 @@ public class AVM2Code implements Cloneable { } } // What to do when hasDup is false? - ins.definition.translate(usedDeobfuscations, swfVersion, switchParts, callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, localScopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssignmentIps, ip, this, thisHasDefaultToPrimitive, bottomStackSetLocals); + ins.definition.translate(maxTempIndex, usedDeobfuscations, swfVersion, switchParts, callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, localScopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssignmentIps, ip, this, thisHasDefaultToPrimitive, bottomStackSetLocals); NewFunctionAVM2Item nft = (NewFunctionAVM2Item) stack.peek(); nft.functionName = functionName; ip++; } else { try { - ins.definition.translate(usedDeobfuscations, swfVersion, switchParts, callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, localScopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssignmentIps, ip, this, thisHasDefaultToPrimitive, bottomStackSetLocals); + ins.definition.translate(maxTempIndex, usedDeobfuscations, swfVersion, switchParts, callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, localScopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssignmentIps, ip, this, thisHasDefaultToPrimitive, bottomStackSetLocals); if (stack.size() == 1 && (stack.peek() instanceof SetLocalAVM2Item)) { bottomStackSetLocals.add((SetLocalAVM2Item) stack.peek()); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorGetSet.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorGetSet.java index b6d4f7bd0..69de53324 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorGetSet.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorGetSet.java @@ -236,7 +236,7 @@ public class AVM2DeobfuscatorGetSet extends SWFDecompilerAdapter { return; } - stack.setConnectedOutput(0, output); + stack.setConnectedOutput(0, output, localData); ins.translate(localData, stack, output, 0, ""); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorRegistersOld.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorRegistersOld.java index baff114a4..5196c43e3 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorRegistersOld.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorRegistersOld.java @@ -326,7 +326,7 @@ public class AVM2DeobfuscatorRegistersOld extends AVM2DeobfuscatorSimpleOld { continue outer; } - stack.setConnectedOutput(0, output); + stack.setConnectedOutput(0, output, localData); ins.translate(localData, stack, output, 0, ""); if (def instanceof SetLocalTypeIns) { int regId = ((SetLocalTypeIns) def).getRegisterId(ins); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimpleOld.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimpleOld.java index cc1e0a468..b626ee0f4 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimpleOld.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimpleOld.java @@ -370,7 +370,7 @@ public class AVM2DeobfuscatorSimpleOld extends AVM2DeobfuscatorZeroJumpsNullPush } } - stack.setConnectedOutput(0, output); + stack.setConnectedOutput(0, output, localData); ins.translate(localData, stack, output, 0, ""); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java index 58ef447bf..476d684c1 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java @@ -339,7 +339,7 @@ public class AVM2Graph extends Graph { localData2.localScopeStack = new ScopeStack(); List targetOutput = new GraphPartMarkedArrayList<>(); - finallyTryTargetStack.setConnectedOutput(0, targetOutput); + finallyTryTargetStack.setConnectedOutput(0, targetOutput, localData); try { translatePart(targetOutput, localData2, finallyTryTargetPart, finallyTryTargetStack, 0 /*??*/, "try_target"); } catch (GraphPartChangeException ex1) { //should not happen diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2GraphSource.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2GraphSource.java index 7824dcee2..a399ca1cb 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2GraphSource.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2GraphSource.java @@ -200,7 +200,7 @@ public class AVM2GraphSource extends GraphSource { @Override public void translatePart(List output, Graph graph, GraphPart part, BaseLocalData localData, TranslateStack stack, int start, int end, int staticOperation, String path) throws InterruptedException { Reference lineStartItem = new Reference<>(localData.lineStartInstruction); - code.toSourceOutput(output, localData.swfVersion, localData.allSwitchParts, ((AVM2LocalData) localData).callStack, ((AVM2LocalData) localData).abcIndex, ((AVM2LocalData) localData).setLocalPosToGetLocalPos, ((AVM2LocalData) localData).thisHasDefaultToPrimitive, lineStartItem, path, part, false, isStatic, scriptIndex, classIndex, localRegs, stack, ((AVM2LocalData) localData).scopeStack, ((AVM2LocalData) localData).localScopeStack, abc, body, start, end, localRegNames, ((AVM2LocalData) localData).localRegTypes, fullyQualifiedNames, new boolean[size()], localRegAssignmentIps, ((AVM2LocalData) localData).bottomSetLocals, localData.usedDeobfuscations); + code.toSourceOutput(localData.maxTempIndex, output, localData.swfVersion, localData.allSwitchParts, ((AVM2LocalData) localData).callStack, ((AVM2LocalData) localData).abcIndex, ((AVM2LocalData) localData).setLocalPosToGetLocalPos, ((AVM2LocalData) localData).thisHasDefaultToPrimitive, lineStartItem, path, part, false, isStatic, scriptIndex, classIndex, localRegs, stack, ((AVM2LocalData) localData).scopeStack, ((AVM2LocalData) localData).localScopeStack, abc, body, start, end, localRegNames, ((AVM2LocalData) localData).localRegTypes, fullyQualifiedNames, new boolean[size()], localRegAssignmentIps, ((AVM2LocalData) localData).bottomSetLocals, localData.usedDeobfuscations); localData.lineStartInstruction = lineStartItem.getVal(); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/InstructionDefinition.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/InstructionDefinition.java index dc20e2ebe..c99a5786c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/InstructionDefinition.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/InstructionDefinition.java @@ -271,6 +271,7 @@ public abstract class InstructionDefinition implements Serializable { /** * Translates instruction to high level code. * + * @param maxTempIndex Max temp index * @param usedDeobfuscations Used deobfuscations * @param swfVersion SWF version * @param switchParts Switch parts @@ -300,7 +301,7 @@ public abstract class InstructionDefinition implements Serializable { * @param bottomSetLocals Bottom set locals * @throws InterruptedException On interrupt */ - public void translate(Set usedDeobfuscations, int swfVersion, Set switchParts, List callStack, AbcIndexing abcIndex, Map> setLocalPosToGetLocalPos, Reference lineStartItem, boolean isStatic, int scriptIndex, int classIndex, HashMap localRegs, TranslateStack stack, ScopeStack scopeStack, ScopeStack localScopeStack, AVM2Instruction ins, List output, MethodBody body, ABC abc, HashMap localRegNames, HashMap localRegTypes, List fullyQualifiedNames, String path, HashMap localRegsAssignmentIps, int ip, AVM2Code code, boolean thisHasDefaultToPrimitive, LinkedIdentityHashSet bottomSetLocals) throws InterruptedException { + public void translate(Reference maxTempIndex, Set usedDeobfuscations, int swfVersion, Set switchParts, List callStack, AbcIndexing abcIndex, Map> setLocalPosToGetLocalPos, Reference lineStartItem, boolean isStatic, int scriptIndex, int classIndex, HashMap localRegs, TranslateStack stack, ScopeStack scopeStack, ScopeStack localScopeStack, AVM2Instruction ins, List output, MethodBody body, ABC abc, HashMap localRegNames, HashMap localRegTypes, List fullyQualifiedNames, String path, HashMap localRegsAssignmentIps, int ip, AVM2Code code, boolean thisHasDefaultToPrimitive, LinkedIdentityHashSet bottomSetLocals) throws InterruptedException { AVM2LocalData localData = new AVM2LocalData(); localData.allSwitchParts = switchParts; localData.isStatic = isStatic; @@ -325,6 +326,7 @@ public abstract class InstructionDefinition implements Serializable { localData.bottomSetLocals = bottomSetLocals; localData.swfVersion = swfVersion; localData.usedDeobfuscations = usedDeobfuscations; + localData.maxTempIndex = maxTempIndex; translate(localData, stack, ins, output, path); lineStartItem.setVal(localData.lineStartInstruction); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/stack/DupIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/stack/DupIns.java index 166ef1910..979ea1ad6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/stack/DupIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/stack/DupIns.java @@ -29,6 +29,7 @@ import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.TranslateStack; import com.jpexs.decompiler.graph.model.DuplicateItem; import com.jpexs.decompiler.graph.model.DuplicateSourceItem; +import com.jpexs.decompiler.graph.model.HasTempIndex; import java.util.List; /** @@ -56,14 +57,23 @@ public class DupIns extends InstructionDefinition { @Override public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List output, String path) { GraphTargetItem v = stack.pop(); + int temp = 0; + if (v instanceof NewActivationAVM2Item || v instanceof ExceptionAVM2Item) { stack.push(v); } else { - stack.push(new DuplicateSourceItem(AVM2GraphTargetDialect.INSTANCE, ins, localData.lineStartInstruction, v)); + if (v instanceof HasTempIndex) { + temp = ((HasTempIndex) v).getTempIndex(); + stack.push(v); + } else { + temp = localData.maxTempIndex.getVal() + 1; + localData.maxTempIndex.setVal(temp); + stack.push(new DuplicateSourceItem(AVM2GraphTargetDialect.INSTANCE, ins, localData.lineStartInstruction, v, temp)); + } } //stack.push(v); - stack.push(new DuplicateItem(AVM2GraphTargetDialect.INSTANCE, ins, localData.lineStartInstruction, v)); + stack.push(new DuplicateItem(AVM2GraphTargetDialect.INSTANCE, ins, localData.lineStartInstruction, v, temp)); //v.moreSrc.add(new GraphSourceItemPos(ins, 0)); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/stack/SwapIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/stack/SwapIns.java index d11b303ac..153f1da58 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/stack/SwapIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/stack/SwapIns.java @@ -30,9 +30,13 @@ import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.SimpleValue; import com.jpexs.decompiler.graph.TranslateStack; import com.jpexs.decompiler.graph.model.DuplicateItem; +import com.jpexs.decompiler.graph.model.DuplicateSourceItem; +import com.jpexs.decompiler.graph.model.HasTempIndex; import com.jpexs.decompiler.graph.model.PopItem; import com.jpexs.decompiler.graph.model.PushItem; +import com.jpexs.decompiler.graph.model.SetTemporaryItem; import com.jpexs.decompiler.graph.model.SwapItem; +import com.jpexs.decompiler.graph.model.TemporaryItem; import java.util.List; /** @@ -65,11 +69,13 @@ public class SwapIns extends InstructionDefinition { GraphTargetItem o2 = stack.pop(); - /*stack.push(o1); - stack.push(o2); - o1.getMoreSrc().add(new GraphSourceItemPos(ins, 0)); - o2.getMoreSrc().add(new GraphSourceItemPos(ins, 0)); - */ + /*if (true) { + stack.push(o1); + stack.push(o2); + o1.getMoreSrc().add(new GraphSourceItemPos(ins, 0)); + o2.getMoreSrc().add(new GraphSourceItemPos(ins, 0)); + return; + }*/ if (((o1 instanceof ExceptionAVM2Item) && (o2 instanceof ExceptionAVM2Item)) || ( @@ -94,6 +100,7 @@ public class SwapIns extends InstructionDefinition { return; } + /* stack.finishBlock(output); if (!(o2 instanceof PopItem)) { output.add(new PushItem(o2)); @@ -101,7 +108,35 @@ public class SwapIns extends InstructionDefinition { if (!(o2 instanceof PopItem && o1 instanceof PopItem)) { output.add(new PushItem(o1)); } - output.add(new SwapItem(AVM2GraphTargetDialect.INSTANCE, ins, localData.lineStartInstruction)); + output.add(new SwapItem(AVM2GraphTargetDialect.INSTANCE, ins, localData.lineStartInstruction)); + */ + /*if (o2 instanceof HasTempIndex) { + stack.push(o1); + stack.push(o2); + return; + }*/ + /* + if (o2 instanceof SetTemporaryItem || o2 instanceof DuplicateSourceItem) { + HasTempIndex ti = (HasTempIndex) o2; + stack.addToOutput(new SetTemporaryItem(AVM2GraphTargetDialect.INSTANCE, ins, localData.lineStartInstruction, o2.value, ti.getTempIndex(), "swap")); + stack.push(o1); + stack.push(new TemporaryItem(AVM2GraphTargetDialect.INSTANCE, ins, localData.lineStartInstruction, o2, ti.getTempIndex())); + return; + } + + if (o2 instanceof TemporaryItem || o2 instanceof DuplicateItem) { + stack.push(o1); + stack.push(o2); + return; + } + */ + int temp = localData.maxTempIndex.getVal() + 1; + localData.maxTempIndex.setVal(temp); + stack.finishBlock(output); + stack.addToOutput(new SetTemporaryItem(AVM2GraphTargetDialect.INSTANCE, ins, localData.lineStartInstruction, o2, temp, "swap")); + stack.push(o1); + stack.push(new TemporaryItem(AVM2GraphTargetDialect.INSTANCE, ins, localData.lineStartInstruction, o2, temp)); + stack.finishBlock(output); } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3Parser.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3Parser.java index f47cddef4..66f26b6b4 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3Parser.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3Parser.java @@ -2451,7 +2451,7 @@ public class ActionScript3Parser { break; //Both ASs case "dup": - ret = new DuplicateItem(DIALECT, null, null, expression(allOpenedNamespaces, thisType, pkg, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, true, variables, false, abc)); + ret = new DuplicateItem(DIALECT, null, null, expression(allOpenedNamespaces, thisType, pkg, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, true, variables, false, abc), 0); allowMemberOrCall = true; break; case "push": diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java index 64d3e4b8f..8f2c09e9d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java @@ -76,7 +76,9 @@ import com.jpexs.decompiler.graph.model.LabelItem; import com.jpexs.decompiler.graph.model.PopItem; import com.jpexs.decompiler.graph.model.PushItem; import com.jpexs.decompiler.graph.model.ScriptEndItem; +import com.jpexs.decompiler.graph.model.SetTemporaryItem; import com.jpexs.decompiler.graph.model.SwitchItem; +import com.jpexs.decompiler.graph.model.TemporaryItem; import com.jpexs.decompiler.graph.model.TrueItem; import com.jpexs.decompiler.graph.model.WhileItem; import com.jpexs.helpers.Helper; @@ -342,6 +344,17 @@ public class ActionGraph extends Graph { } } } + if (it instanceof SetTemporaryItem) { + SetTemporaryItem st = (SetTemporaryItem) it; + if (st.value instanceof GetPropertyActionItem) { + GetPropertyActionItem gp = (GetPropertyActionItem) st.value; + if (gp.propertyIndex == 11 /*_target*/) { + list.remove(t); + t--; + continue; + } + } + } if (it instanceof SetTargetActionItem) { SetTargetActionItem st = (SetTargetActionItem) it; if (st.target.isEmpty()) { @@ -362,6 +375,11 @@ public class ActionGraph extends Graph { t--; continue; } + if (st.target instanceof TemporaryItem) { + list.remove(t); + t--; + continue; + } if ((st.target instanceof DirectValueActionItem) && st.target.getResult().equals("")) { if (targetStart > -1) { targetEnd = t; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionScript2Parser.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionScript2Parser.java index bb66b0fd7..a3d8865e2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionScript2Parser.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionScript2Parser.java @@ -1869,7 +1869,7 @@ public class ActionScript2Parser { break; //Both ASs case "dup": - ret = new DuplicateItem(DIALECT, null, null, expression(inFunction, inMethod, inTellTarget, allowRemainder, variables, functions, false, hasEval)); + ret = new DuplicateItem(DIALECT, null, null, expression(inFunction, inMethod, inTellTarget, allowRemainder, variables, functions, false, hasEval), 0); allowMemberOrCall = true; break; case "push": diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf5/ActionPushDuplicate.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf5/ActionPushDuplicate.java index d826d617e..4354fc048 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf5/ActionPushDuplicate.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf5/ActionPushDuplicate.java @@ -68,7 +68,8 @@ public class ActionPushDuplicate extends Action { @Override public void translate(Set usedDeobfuscations, Map> uninitializedClassTraits, SecondPassData secondPassData, boolean insideDoInitAction, GraphSourceItem lineStartAction, TranslateStack stack, List output, HashMap regNames, HashMap variables, HashMap functions, int staticOperation, String path) { GraphTargetItem value = stack.peek(); - stack.push(new DuplicateItem(ActionGraphTargetDialect.INSTANCE, this, lineStartAction, value)); + //TODO: implement logic similar to Avm2 + stack.push(new DuplicateItem(ActionGraphTargetDialect.INSTANCE, this, lineStartAction, value, 0)); value.getMoreSrc().add(new GraphSourceItemPos(this, 0)); } 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 830053ad2..76c9ab4ca 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java @@ -2390,7 +2390,7 @@ public class Graph { */ protected final void translatePart(List output, BaseLocalData localData, GraphPart part, TranslateStack stack, int staticOperation, String path) throws InterruptedException, GraphPartChangeException { List sub = part.getSubParts(); - stack.setConnectedOutput(0, output); + stack.setConnectedOutput(0, output, localData); int end; for (GraphPart p : sub) { if (p.end == -1) { @@ -3370,7 +3370,7 @@ public class Graph { if (code.size() <= part.start) { if (!(!ret.isEmpty() && ret.get(ret.size() - 1) instanceof ExitItem)) { - stack.setConnectedOutput(0, ret); + stack.setConnectedOutput(0, ret, localData); stack.addToOutput(new ScriptEndItem(dialect)); } return ret; @@ -3503,7 +3503,7 @@ public class Graph { if (currentRet instanceof GraphPartMarkedArrayList) { ((GraphPartMarkedArrayList) currentRet).startPart(part); } - stack.setConnectedOutput(0, currentRet); + stack.setConnectedOutput(0, currentRet, localData); if (checkPartOutput(currentRet, foundGotos, partCodes, partCodePos, visited, code, localData, allParts, stack, parent, part, stopPart, stopPartKind, loops, throwStates, currentLoop, staticOperation, path, recursionLevel)) { parseNext = false; } else { @@ -3512,7 +3512,7 @@ public class Graph { do { exHappened = false; try { - stack.setConnectedOutput(currentRet.size(), output); + stack.setConnectedOutput(currentRet.size(), output, localData); code.translatePart(output, this, part, localData, stack, ipStart, part.end, staticOperation, path); } catch (GraphPartChangeException ex) { //Special case for ifFrameLoaded when it's over multiple parts //output.addAll(ex.getOutput()); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/TranslateStack.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/TranslateStack.java index 776df75ff..400aad6b7 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/TranslateStack.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/TranslateStack.java @@ -16,6 +16,7 @@ */ package com.jpexs.decompiler.graph; +import com.jpexs.decompiler.flash.BaseLocalData; import com.jpexs.decompiler.flash.abc.avm2.model.FindPropertyAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.NewActivationAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.clauses.ExceptionAVM2Item; @@ -23,11 +24,16 @@ import com.jpexs.decompiler.graph.model.BranchStackResistant; import com.jpexs.decompiler.graph.model.BreakItem; import com.jpexs.decompiler.graph.model.CommaExpressionItem; import com.jpexs.decompiler.graph.model.ContinueItem; +import com.jpexs.decompiler.graph.model.DuplicateItem; +import com.jpexs.decompiler.graph.model.DuplicateSourceItem; import com.jpexs.decompiler.graph.model.ExitItem; +import com.jpexs.decompiler.graph.model.HasTempIndex; import com.jpexs.decompiler.graph.model.PopItem; import com.jpexs.decompiler.graph.model.PushItem; import com.jpexs.decompiler.graph.model.ScriptEndItem; +import com.jpexs.decompiler.graph.model.SetTemporaryItem; import com.jpexs.decompiler.graph.model.SwapItem; +import com.jpexs.decompiler.graph.model.TemporaryItem; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -60,6 +66,8 @@ public class TranslateStack extends Stack { private Map marks = new HashMap<>(); public List outputQueue = new ArrayList<>(); + + public BaseLocalData localData = null; @Override public synchronized Object clone() { @@ -75,9 +83,10 @@ public class TranslateStack extends Stack { } - public void setConnectedOutput(int prevOutputSize, List connectedOutput) { + public void setConnectedOutput(int prevOutputSize, List connectedOutput, BaseLocalData localData) { this.prevOutputSize = prevOutputSize; this.connectedOutput = connectedOutput; + this.localData = localData; } @Override @@ -86,7 +95,7 @@ public class TranslateStack extends Stack { if (item instanceof FindPropertyAVM2Item) { finishBlock(connectedOutput); } else { - outputQueue.add(item); + outputQueue.add(item); item = new CommaExpressionItem(item.dialect, null, item.lineStartItem, outputQueue); outputQueue = new ArrayList<>(); } @@ -226,6 +235,39 @@ public class TranslateStack extends Stack { connectedOutput.addAll(oldQueue); } + if (isEmpty() && connectedOutput != null) { + for (int i = connectedOutput.size() - 1; i >= 0; i--) { + GraphTargetItem item = connectedOutput.get(i); + if (item instanceof Block) { + break; + } + if (item instanceof PushItem) { + PushItem pi = (PushItem) item; + if (pi.value instanceof SetTemporaryItem) { + SetTemporaryItem st = (SetTemporaryItem) pi.value; + connectedOutput.set(i, st); + return new TemporaryItem(pi.dialect, pi.value.getSrc(), pi.value.getLineStartItem(), pi.value, st.tempIndex); + } else if (pi.value instanceof DuplicateSourceItem) { + DuplicateSourceItem ds = (DuplicateSourceItem) pi.value; + connectedOutput.set(i, new SetTemporaryItem(pi.dialect, ds.getSrc(), ds.getLineStartItem(), ds.value, ds.tempIndex,"push")); + return new TemporaryItem(pi.dialect, pi.value.getSrc(), pi.value.getLineStartItem(), ds.value, ds.tempIndex); + } /*else if (pi.value instanceof DuplicateItem) { + DuplicateItem d = (DuplicateItem) pi.value; + //connectedOutput.remove(i); + connectedOutput.set(i, new SetTemporaryItem(pi.dialect, d.getSrc(), d.getLineStartItem(), d.value, d.tempIndex)); + return new TemporaryItem(pi.dialect, pi.value.getSrc(), pi.value.getLineStartItem(), pi.value, d.tempIndex); + } */else if (pi.value instanceof TemporaryItem) { + connectedOutput.remove(i); + return pi.value; + } else { + int temp = localData.maxTempIndex.getVal() + 1; + localData.maxTempIndex.setVal(temp); + connectedOutput.set(i, new SetTemporaryItem(pi.dialect, pi.value.getSrc(), pi.value.getLineStartItem(), pi.value, temp, "push")); + return new TemporaryItem(pi.dialect, pi.value.getSrc(), pi.value.getLineStartItem(), pi.value, temp); + } + } + } + } if (path != null) { if (this.isEmpty()) { @@ -260,10 +302,25 @@ public class TranslateStack extends Stack { } } + private boolean isAllTemp() { + for (int i = 0; i < size(); i++) { + GraphTargetItem item = get(i); + if (item instanceof TemporaryItem) { + continue; + } + if (item instanceof DuplicateItem) { + continue; + } + return false; + } + return true; + } + public void addToOutput(GraphTargetItem item) { if (isEmpty() || peek() instanceof ExceptionAVM2Item || peek() instanceof NewActivationAVM2Item + //|| isAllTemp() ) { connectedOutput.add(item); return; @@ -356,7 +413,7 @@ public class TranslateStack extends Stack { if (output.size() < 3) { return; } - if (!(output.get(output.size() - 1) instanceof SwapItem)) { + if (!(output.get(output.size() - 1) instanceof PushItem)) { return; } @@ -364,13 +421,34 @@ public class TranslateStack extends Stack { return; } - if (!(output.get(output.size() - 3) instanceof PushItem)) { + if (!(output.get(output.size() - 3) instanceof SetTemporaryItem)) { return; } + PushItem pi1 = (PushItem) output.get(output.size() - 1); + if (!(pi1.value instanceof TemporaryItem)) { + return; + } + + TemporaryItem ti = (TemporaryItem) pi1.value; + + SetTemporaryItem st = (SetTemporaryItem) output.get(output.size() - 3); + + if (!"swap".equals(st.getSuffix())) { + return; + } + + if (st.getTempIndex() != ti.getTempIndex()) { + return; + } + + PushItem pi2 = (PushItem) output.get(output.size() - 2); + output.remove(output.size() - 1); - push(((PushItem)output.remove(output.size() - 1)).value); - push(((PushItem)output.remove(output.size() - 1)).value); + output.remove(output.size() - 1); + output.remove(output.size() - 1); + push(pi2.value); + push(ti.value); //moveToStack(output); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/DuplicateItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/DuplicateItem.java index c2bf1fb1c..92441dde2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/DuplicateItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/DuplicateItem.java @@ -33,8 +33,9 @@ import java.util.Set; * * @author JPEXS */ -public class DuplicateItem extends GraphTargetItem implements SimpleValue { +public class DuplicateItem extends GraphTargetItem implements SimpleValue, HasTempIndex { + public int tempIndex; /** * Constructor. * @@ -43,8 +44,9 @@ public class DuplicateItem extends GraphTargetItem implements SimpleValue { * @param lineStartIns Line start item * @param value Value */ - public DuplicateItem(GraphTargetDialect dialect, GraphSourceItem src, GraphSourceItem lineStartIns, GraphTargetItem value) { + public DuplicateItem(GraphTargetDialect dialect, GraphSourceItem src, GraphSourceItem lineStartIns, GraphTargetItem value, int tempIndex) { super(dialect, src, lineStartIns, value.getPrecedence(), value); + this.tempIndex = tempIndex; } @Override @@ -62,9 +64,12 @@ public class DuplicateItem extends GraphTargetItem implements SimpleValue { /*if (!value.hasSideEffect() || !Configuration.displayDupInstructions.get()) { return value.appendTry(writer, localData); }*/ - writer.append("§§dup("); - value.appendTry(writer, localData); - return writer.append(")"); + if (tempIndex == 0) { + writer.append("§§dup("); + value.appendTry(writer, localData); + return writer.append(")"); + } + return writer.append("_temp_").append(tempIndex); } @Override @@ -137,4 +142,8 @@ public class DuplicateItem extends GraphTargetItem implements SimpleValue { return value.hasSideEffect(); } + @Override + public int getTempIndex() { + return tempIndex; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/DuplicateSourceItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/DuplicateSourceItem.java index 245521535..b511f12a1 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/DuplicateSourceItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/DuplicateSourceItem.java @@ -34,7 +34,9 @@ import java.util.Set; * * @author JPEXS */ -public class DuplicateSourceItem extends GraphTargetItem implements SimpleValue { +public class DuplicateSourceItem extends GraphTargetItem implements SimpleValue, HasTempIndex { + + public int tempIndex; /** * Constructor. @@ -44,10 +46,11 @@ public class DuplicateSourceItem extends GraphTargetItem implements SimpleValue * @param lineStartIns Line start item * @param value Value */ - public DuplicateSourceItem(GraphTargetDialect dialect, GraphSourceItem src, GraphSourceItem lineStartIns, GraphTargetItem value) { + public DuplicateSourceItem(GraphTargetDialect dialect, GraphSourceItem src, GraphSourceItem lineStartIns, GraphTargetItem value, int tempIndex) { super(dialect, src, lineStartIns, value.getPrecedence(), value); + this.tempIndex = tempIndex; } - + @Override public Object getResult() { return value.getResult(); @@ -63,9 +66,18 @@ public class DuplicateSourceItem extends GraphTargetItem implements SimpleValue /*if (!value.hasSideEffect() || !Configuration.displayDupInstructions.get()) { return value.appendTry(writer, localData); }*/ - writer.append("§§dupsrc("); - value.appendTry(writer, localData); - return writer.append(")"); + if (tempIndex == 0) { + writer.append("§§dupsrc("); + value.appendTry(writer, localData); + return writer.append(")"); + } + GraphTargetItem val = value; + while ((val instanceof HasTempIndex) && ((HasTempIndex) val).getTempIndex() == tempIndex) { + val = val.value; + } + writer.append("_tempdup_").append(tempIndex).append(" = "); + val.appendTry(writer, localData); + return writer; } @Override @@ -138,4 +150,8 @@ public class DuplicateSourceItem extends GraphTargetItem implements SimpleValue return value.hasSideEffect(); } + @Override + public int getTempIndex() { + return tempIndex; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/HasTempIndex.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/HasTempIndex.java new file mode 100644 index 000000000..be1504ebe --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/HasTempIndex.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2010-2025 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.graph.model; + +/** + * + * @author JPEXS + */ +public interface HasTempIndex { + public int getTempIndex(); +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/SetTemporaryItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/SetTemporaryItem.java new file mode 100644 index 000000000..2c12a88c4 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/SetTemporaryItem.java @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2010-2025 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.graph.model; + +import com.jpexs.decompiler.flash.SourceGeneratorLocalData; +import com.jpexs.decompiler.flash.helpers.GraphTextWriter; +import com.jpexs.decompiler.graph.CompilationException; +import com.jpexs.decompiler.graph.GraphSourceItem; +import com.jpexs.decompiler.graph.GraphTargetDialect; +import com.jpexs.decompiler.graph.GraphTargetItem; +import com.jpexs.decompiler.graph.SimpleValue; +import com.jpexs.decompiler.graph.SourceGenerator; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * Duplicate item. + * + * @author JPEXS + */ +public class SetTemporaryItem extends GraphTargetItem implements SimpleValue, HasTempIndex { + + private static final boolean SHOW_SUFFIX = false; + + public int tempIndex; + private final String suffix; + + public String getSuffix() { + return suffix; + } + + /** + * Constructor. + * + * @param dialect Dialect + * @param src Source + * @param lineStartIns Line start item + * @param value Value + */ + public SetTemporaryItem(GraphTargetDialect dialect, GraphSourceItem src, GraphSourceItem lineStartIns, GraphTargetItem value, int tempIndex, String suffix) { + super(dialect, src, lineStartIns, value.getPrecedence(), value); + this.tempIndex = tempIndex; + this.suffix = suffix; + } + + @Override + public Object getResult() { + return value.getResult(); + } + + @Override + public Double getResultAsNumber() { + return value.getResultAsNumber(); + } + + @Override + public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException { + GraphTargetItem val = value; + while ((val instanceof HasTempIndex) && ((HasTempIndex) val).getTempIndex() == tempIndex) { + val = val.value; + } + writer.append("_temp"); + if (SHOW_SUFFIX) { + writer.append(suffix); + } + writer.append("_").append(tempIndex).append(" = "); + val.appendTry(writer, localData); + return writer; + } + + @Override + public GraphTargetItem getNotCoerced() { + return value.getNotCoerced(); + } + + @Override + public GraphTargetItem getNotCoercedNoDup() { + return this; + } + + @Override + public GraphTargetItem getThroughRegister() { + return value.getThroughRegister(); + } + + @Override + public GraphTargetItem getThroughDuplicate() { + return value.getThroughDuplicate(); + } + + @Override + public boolean isCompileTime(Set dependencies) { + if (dependencies.contains(value)) { + return false; + } + if (!((value instanceof SimpleValue) && ((SimpleValue) value).isSimpleValue())) { + dependencies.add(value); + } + return value.isCompileTime(dependencies); + } + + @Override + public boolean isVariableComputed() { + return value.isVariableComputed(); + } + + @Override + public List toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException { + return new ArrayList<>(); + } + + @Override + public boolean hasReturnValue() { + return true; + } + + @Override + public GraphTargetItem simplify(String implicitCoerce) { + return this; + } + + @Override + public GraphTargetItem returnType() { + return value.returnType(); + } + + @Override + public boolean isSimpleValue() { + return ((value instanceof SimpleValue) && ((SimpleValue) value).isSimpleValue()); + } + + @Override + public boolean hasSideEffect() { + return value.hasSideEffect(); + } + + @Override + public int getTempIndex() { + return tempIndex; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/TemporaryItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/TemporaryItem.java new file mode 100644 index 000000000..7bdfca456 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/TemporaryItem.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2010-2025 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.graph.model; + +import com.jpexs.decompiler.flash.SourceGeneratorLocalData; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.helpers.GraphTextWriter; +import com.jpexs.decompiler.graph.CompilationException; +import com.jpexs.decompiler.graph.GraphSourceItem; +import com.jpexs.decompiler.graph.GraphTargetDialect; +import com.jpexs.decompiler.graph.GraphTargetItem; +import com.jpexs.decompiler.graph.SimpleValue; +import com.jpexs.decompiler.graph.SourceGenerator; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * Duplicate item. + * + * @author JPEXS + */ +public class TemporaryItem extends GraphTargetItem implements SimpleValue, HasTempIndex { + + public int tempIndex; + /** + * Constructor. + * + * @param dialect Dialect + * @param src Source + * @param lineStartIns Line start item + * @param value Value + */ + public TemporaryItem(GraphTargetDialect dialect, GraphSourceItem src, GraphSourceItem lineStartIns, GraphTargetItem value, int tempIndex) { + super(dialect, src, lineStartIns, value.getPrecedence(), value); + this.tempIndex = tempIndex; + } + + @Override + public Object getResult() { + return value.getResult(); + } + + @Override + public Double getResultAsNumber() { + return value.getResultAsNumber(); + } + + @Override + public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException { + return writer.append("_temp_").append(tempIndex); + } + + @Override + public GraphTargetItem getNotCoerced() { + return value.getNotCoerced(); + } + + @Override + public GraphTargetItem getNotCoercedNoDup() { + return this; + } + + @Override + public GraphTargetItem getThroughRegister() { + return value.getThroughRegister(); + } + + @Override + public GraphTargetItem getThroughDuplicate() { + return value.getThroughDuplicate(); + } + + @Override + public boolean isCompileTime(Set dependencies) { + if (dependencies.contains(value)) { + return false; + } + if (!((value instanceof SimpleValue) && ((SimpleValue) value).isSimpleValue())) { + dependencies.add(value); + } + return value.isCompileTime(dependencies); + } + + @Override + public boolean isVariableComputed() { + return value.isVariableComputed(); + } + + @Override + public List toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException { + return new ArrayList<>(); + } + + @Override + public boolean hasReturnValue() { + return true; + } + + @Override + public GraphTargetItem simplify(String implicitCoerce) { + return this; + } + + @Override + public GraphTargetItem returnType() { + return value.returnType(); + } + + @Override + public boolean isSimpleValue() { + return ((value instanceof SimpleValue) && ((SimpleValue) value).isSimpleValue()); + } + + @Override + public boolean hasSideEffect() { + return value.hasSideEffect(); + } + + @Override + public int getTempIndex() { + return tempIndex; + } + +}