- New AS2 class detector

- Reference helper class moved to helper package.
This commit is contained in:
Jindra Petřík
2018-01-22 22:06:40 +01:00
parent def79bd7a7
commit da586b105f
25 changed files with 763 additions and 308 deletions

View File

@@ -12,7 +12,8 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* License along with this library.
*/
package com.jpexs.decompiler.flash.abc.avm2;
import com.jpexs.decompiler.flash.EndOfStreamException;
@@ -264,7 +265,7 @@ import com.jpexs.decompiler.flash.abc.avm2.model.clauses.DeclarationAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.clauses.ForEachInAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.clauses.ForInAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.parser.script.PropertyAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.parser.script.PropertyAVM2Item;
import com.jpexs.helpers.Reference;
import com.jpexs.decompiler.flash.abc.types.ABCException;
import com.jpexs.decompiler.flash.abc.types.AssignedValue;
import com.jpexs.decompiler.flash.abc.types.ConvertData;

View File

@@ -12,7 +12,8 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* License along with this library.
*/
package com.jpexs.decompiler.flash.abc.avm2.deobfuscation;
import com.jpexs.decompiler.flash.BaseLocalData;
@@ -32,7 +33,7 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocalTypeIn
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnValueIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnVoidIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ThrowIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ThrowIns;
import com.jpexs.helpers.Reference;
import com.jpexs.decompiler.flash.abc.types.MethodBody;
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
import com.jpexs.decompiler.flash.abc.types.traits.Trait;

View File

@@ -12,7 +12,8 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* License along with this library.
*/
package com.jpexs.decompiler.flash.abc.avm2.deobfuscation;
import com.jpexs.decompiler.flash.BaseLocalData;
@@ -30,7 +31,7 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnValueIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnVoidIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ThrowIns;
import com.jpexs.decompiler.flash.abc.avm2.model.NullAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.NullAVM2Item;
import com.jpexs.helpers.Reference;
import com.jpexs.decompiler.flash.abc.types.MethodBody;
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
import com.jpexs.decompiler.graph.Graph;

View File

@@ -12,7 +12,8 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* License along with this library.
*/
package com.jpexs.decompiler.flash.abc.avm2.graph;
import com.jpexs.decompiler.flash.BaseLocalData;
@@ -571,8 +572,8 @@ public class AVM2Graph extends Graph {
}
@Override
@Override
protected void finalProcessAfter(List<GraphTargetItem> list, int level, FinalProcessLocalData localData) {
protected void finalProcessAfter(List<GraphTargetItem> list, int level, FinalProcessLocalData localData, String path) {
super.finalProcessAfter(list, level, localData, path);
for (int i = 0; i < list.size(); i++) {
if (list.get(i) instanceof SetLocalAVM2Item) {
SetLocalAVM2Item ri = (SetLocalAVM2Item) list.get(i);
@@ -585,7 +586,7 @@ public class AVM2Graph extends Graph {
}
@Override
@Override
protected void finalProcess(List<GraphTargetItem> list, int level, FinalProcessLocalData localData, String path) throws InterruptedException {
if (level == 0) {
if (!list.isEmpty()) {
@@ -702,7 +703,7 @@ public class AVM2Graph extends Graph {
}
}
//Handle for loops at the end:
//Handle for loops at the end:
super.finalProcess(list, level, localData, path);
}
@Override

View File

@@ -12,7 +12,8 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* License along with this library.
*/
package com.jpexs.decompiler.flash.abc.avm2.graph;
import com.jpexs.decompiler.flash.BaseLocalData;
@@ -21,7 +22,7 @@ import com.jpexs.decompiler.flash.abc.AVM2LocalData;
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
import com.jpexs.decompiler.flash.abc.avm2.ConvertOutput;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.helpers.Reference;
import com.jpexs.decompiler.flash.abc.types.MethodBody;
import com.jpexs.decompiler.graph.DottedChain;
import com.jpexs.decompiler.graph.GraphPart;

View File

@@ -12,7 +12,8 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* License along with this library.
*/
package com.jpexs.decompiler.flash.abc.avm2.instructions;
import com.jpexs.decompiler.flash.abc.ABC;
@@ -29,7 +30,7 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.IncLocalIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocalTypeIns;
import com.jpexs.decompiler.flash.abc.avm2.model.AVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item;
import com.jpexs.helpers.Reference;
import com.jpexs.decompiler.flash.abc.types.MethodBody;
import com.jpexs.decompiler.flash.abc.types.Multiname;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;

View File

@@ -12,9 +12,11 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* License along with this library.
*/
package com.jpexs.decompiler.flash.abc.avm2.parser.script;
import com.jpexs.helpers.Reference;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.SourceGeneratorLocalData;
import com.jpexs.decompiler.flash.abc.ABC;

View File

@@ -12,9 +12,11 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* License along with this library.
*/
package com.jpexs.decompiler.flash.abc.avm2.parser.script;
import com.jpexs.helpers.Reference;
import com.jpexs.decompiler.flash.SWC;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SourceGeneratorLocalData;

View File

@@ -12,9 +12,11 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* License along with this library.
*/
package com.jpexs.decompiler.flash.abc.avm2.parser.script;
import com.jpexs.helpers.Reference;
import com.jpexs.decompiler.flash.SourceGeneratorLocalData;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instructions;

View File

@@ -12,9 +12,11 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* License along with this library.
*/
package com.jpexs.decompiler.flash.abc.avm2.parser.script;
import com.jpexs.helpers.Reference;
import com.jpexs.decompiler.flash.SourceGeneratorLocalData;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;

View File

@@ -12,9 +12,11 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* License along with this library.
*/
package com.jpexs.decompiler.flash.abc.avm2.parser.script;
import com.jpexs.helpers.Reference;
import com.jpexs.decompiler.flash.SourceGeneratorLocalData;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instructions;
import com.jpexs.decompiler.flash.abc.types.Multiname;

View File

@@ -12,9 +12,11 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* License along with this library.
*/
package com.jpexs.decompiler.flash.abc.avm2.parser.script;
import com.jpexs.helpers.Reference;
import com.jpexs.decompiler.flash.SourceGeneratorLocalData;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instructions;

View File

@@ -12,9 +12,11 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* License along with this library.
*/
package com.jpexs.decompiler.flash.abc.avm2.parser.script;
import com.jpexs.helpers.Reference;
import com.jpexs.decompiler.flash.SourceGeneratorLocalData;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.types.Namespace;

View File

@@ -12,9 +12,11 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* License along with this library.
*/
package com.jpexs.decompiler.flash.abc.avm2.parser.script;
import com.jpexs.helpers.Reference;
import com.jpexs.decompiler.flash.SourceGeneratorLocalData;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;

View File

@@ -12,9 +12,11 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* License along with this library.
*/
package com.jpexs.decompiler.flash.abc.avm2.parser.script;
import com.jpexs.helpers.Reference;
import com.jpexs.decompiler.flash.SourceGeneratorLocalData;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;

View File

@@ -21,7 +21,7 @@ import com.jpexs.decompiler.flash.BaseLocalData;
import com.jpexs.decompiler.flash.DisassemblyListener;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.abc.avm2.parser.script.Reference;
import com.jpexs.helpers.Reference;
import com.jpexs.decompiler.flash.action.deobfuscation.ActionDeobfuscator;
import com.jpexs.decompiler.flash.action.model.ActionItem;
import com.jpexs.decompiler.flash.action.model.CallMethodActionItem;
@@ -1214,262 +1214,6 @@ public abstract class Action implements GraphSourceItem {
return ti;
}
public static List<GraphTargetItem> checkClass(List<GraphTargetItem> output) {
if (true) {
//return output;
}
List<GraphTargetItem> ret = new ArrayList<>();
List<MyEntry<GraphTargetItem, GraphTargetItem>> traits = new ArrayList<>();
List<Boolean> traitsStatic = new ArrayList<>();
GraphTargetItem className;
GraphTargetItem extendsOp = null;
List<GraphTargetItem> implementsOp = new ArrayList<>();
boolean ok = true;
int prevCount = 0;
for (GraphTargetItem t : output) {
if (t instanceof IfItem) {
IfItem it = (IfItem) t;
if (it.expression instanceof NotItem) {
NotItem nti = (NotItem) it.expression;
if ((nti.value instanceof GetMemberActionItem) || (nti.value instanceof GetVariableActionItem)) {
if ((it.onTrue.size() == 1) && (it.onTrue.get(0) instanceof SetMemberActionItem) && (((SetMemberActionItem) it.onTrue.get(0)).value instanceof NewObjectActionItem)) {
// ignore
} else {
List<GraphTargetItem> parts = it.onTrue;
className = getWithoutGlobal(nti.value);
if (parts.size() >= 1) {
int ipos = 0;
while ((parts.get(ipos) instanceof PopItem) || ((parts.get(ipos) instanceof IfItem) && ((((IfItem) parts.get(ipos)).onTrue.size() == 1) && (((IfItem) parts.get(ipos)).onTrue.get(0) instanceof SetMemberActionItem) && (((SetMemberActionItem) ((IfItem) parts.get(ipos)).onTrue.get(0)).value instanceof NewObjectActionItem)))) {
ipos++;
}
if (parts.get(ipos) instanceof ExtendsActionItem) {
ExtendsActionItem et = (ExtendsActionItem) parts.get(ipos);
extendsOp = getWithoutGlobal(et.superclass);
ipos++;
}
int instanceReg = -1;
int classReg = -1;
if (parts.get(ipos) instanceof StoreRegisterActionItem) {
StoreRegisterActionItem sr = (StoreRegisterActionItem) parts.get(ipos);
instanceReg = sr.register.number;
if (sr.value instanceof GetMemberActionItem) {
GetMemberActionItem gm = (GetMemberActionItem) sr.value;
//gm.memberName should be "prototype"
if (gm.object instanceof TemporaryRegister) {
TemporaryRegister tm = (TemporaryRegister) gm.object;
classReg = tm.getRegId();
if (tm.value instanceof SetMemberActionItem) {
SetMemberActionItem sm = (SetMemberActionItem) tm.value;
if (sm.value instanceof StoreRegisterActionItem) {
sr = (StoreRegisterActionItem) sm.value;
if (sr.value instanceof FunctionActionItem) {
((FunctionActionItem) (sr.value)).calculatedFunctionName = sm.objectName; //(className instanceof GetMemberActionItem) ? ((GetMemberActionItem) className).memberName : className;
//This is probably a constructor
traits.add(new MyEntry<>(((FunctionActionItem) (sr.value)).calculatedFunctionName, ((FunctionActionItem) sr.value)));
traitsStatic.add(false);
}
}
}
}
}
} else if (parts.get(ipos) instanceof SetMemberActionItem) {
SetMemberActionItem sm = (SetMemberActionItem) parts.get(0);
if (sm.value instanceof FunctionActionItem) {
FunctionActionItem f = (FunctionActionItem) sm.value;
if (f.actions.isEmpty()) {
if (parts.size() == 2) {
if (parts.get(1) instanceof ImplementsOpActionItem) {
ImplementsOpActionItem iot = (ImplementsOpActionItem) parts.get(1);
implementsOp = iot.superclasses;
} else {
//ok = false;
break;
}
}
List<GraphTargetItem> output2 = new ArrayList<>();
for (int i = 0; i < prevCount; i++) {
output2.add(output.get(i));
}
output2.add(new InterfaceActionItem(sm.objectName, implementsOp));
return output2;
}
}
}
for (; ipos < parts.size(); ipos++) {
if (parts.get(ipos) instanceof ImplementsOpActionItem) {
ImplementsOpActionItem io = (ImplementsOpActionItem) parts.get(ipos);
implementsOp = io.superclasses;
continue;
} else if (parts.get(ipos) instanceof SetMemberActionItem) {
SetMemberActionItem sm = (SetMemberActionItem) parts.get(ipos);
if (sm.object instanceof TemporaryRegister) {
TemporaryRegister treg = (TemporaryRegister) sm.object;
if (classReg > -1 && treg.getRegId() == classReg) {
} else if (instanceReg > -1 && treg.getRegId() == instanceReg) {
} else if (sm.object.value instanceof SetMemberActionItem) {
SetMemberActionItem sm2 = (SetMemberActionItem) sm.object.value;
if ((sm2.objectName instanceof DirectValueActionItem) && "prototype".equals(((DirectValueActionItem) sm2.objectName).getAsString())) {
instanceReg = treg.getRegId();
extendsOp = getWithoutGlobal(sm2.object);
} else {
classReg = treg.getRegId();
GraphTargetItem val = sm2.value;
if (val instanceof StoreRegisterActionItem) {
val = val.value;
}
if (val instanceof FunctionActionItem) {
//Is this a constructor?
//((FunctionActionItem) (constructor)).calculatedFunctionName = (className instanceof GetMemberActionItem) ? ((GetMemberActionItem) className).memberName : className;
}
}
}
}
int rnum = -1;
if (sm.object instanceof DirectValueActionItem) {
DirectValueActionItem dv = (DirectValueActionItem) sm.object;
if (dv.value instanceof RegisterNumber) {
RegisterNumber rn = (RegisterNumber) dv.value;
rnum = rn.number;
}
}
if (sm.object instanceof TemporaryRegister) {
rnum = ((TemporaryRegister) sm.object).getRegId();
}
if (rnum == instanceReg || rnum == classReg) {
if (sm.value instanceof FunctionActionItem) {
((FunctionActionItem) sm.value).calculatedFunctionName = sm.objectName;
}
traits.add(new MyEntry<>(sm.objectName, sm.value));
traitsStatic.add(rnum == classReg);
}
} else if (parts.get(ipos) instanceof PushItem) {
if (parts.get(ipos).value instanceof CallMethodActionItem) {
CallMethodActionItem cm = (CallMethodActionItem) parts.get(ipos).value;
if (cm.methodName instanceof DirectValueActionItem) {
if ("addProperty".equals(((DirectValueActionItem) cm.methodName).getAsString())) {
int rnum = -1;
if (cm.scriptObject instanceof DirectValueActionItem) {
DirectValueActionItem dv = (DirectValueActionItem) cm.scriptObject;
if (dv.value instanceof RegisterNumber) {
RegisterNumber rn = (RegisterNumber) dv.value;
rnum = rn.number;
}
}
if (cm.scriptObject instanceof TemporaryRegister) {
rnum = ((TemporaryRegister) cm.scriptObject).getRegId();
}
if (cm.arguments.size() > 1) {
GraphTargetItem propertyName = cm.arguments.get(0); //name
GraphTargetItem propertyGetter = cm.arguments.get(1); //getter
GraphTargetItem propertySetter = cm.arguments.get(2); //setter
if ((propertyName instanceof DirectValueActionItem) && ((DirectValueActionItem) propertyName).isString()) {
String propertyNameStr = ((DirectValueActionItem) propertyName).getAsString();
if (propertyGetter instanceof GetMemberActionItem) {
if (((GetMemberActionItem) propertyGetter).object instanceof TemporaryRegister) {
if (((TemporaryRegister) ((GetMemberActionItem) propertyGetter).object).getRegId() == rnum) {
if (((GetMemberActionItem) propertyGetter).memberName instanceof DirectValueActionItem) {
DirectValueActionItem mNameDv = (DirectValueActionItem) ((GetMemberActionItem) propertyGetter).memberName;
if (mNameDv.isString()) {
String getterNameStr = mNameDv.getAsString();
if (getterNameStr.equals("__get__" + propertyNameStr)) {
//TODO: handle setter
}
}
}
}
}
} else if (propertyGetter instanceof FunctionActionItem) {
FunctionActionItem getterFunc = (FunctionActionItem) propertyGetter;
if (getterFunc.actions.isEmpty() && getterFunc.functionName.isEmpty() && ((FunctionActionItem) propertyGetter).paramNames.isEmpty()) {
//well, no getter then
} else {
logger.severe("unexpected getter value for property " + propertyNameStr);
}
} else {
logger.severe("unexpected getter value for property " + propertyNameStr + ": " + propertyGetter.getClass().getSimpleName());
}
if (propertySetter instanceof GetMemberActionItem) {
if (((GetMemberActionItem) propertySetter).object instanceof TemporaryRegister) {
if (((TemporaryRegister) ((GetMemberActionItem) propertySetter).object).getRegId() == rnum) {
if (((GetMemberActionItem) propertySetter).memberName instanceof DirectValueActionItem) {
DirectValueActionItem mNameDv = (DirectValueActionItem) ((GetMemberActionItem) propertySetter).memberName;
if (mNameDv.isString()) {
String getterNameStr = mNameDv.getAsString();
if (getterNameStr.equals("__set__" + propertyNameStr)) {
//TODO: handle setter
}
}
}
}
}
} else if (propertySetter instanceof FunctionActionItem) {
FunctionActionItem setterFunc = (FunctionActionItem) propertySetter;
if (setterFunc.actions.isEmpty() && setterFunc.functionName.isEmpty() && ((FunctionActionItem) propertySetter).paramNames.isEmpty()) {
//well, no setter then
} else {
logger.severe("unexpected setter value for property " + propertyNameStr);
}
//no setter
} else {
logger.severe("unexpected setter value for property " + propertyNameStr + ": " + propertySetter.getClass().getSimpleName());
}
}
}
}
}
}
} else {
break;
}
}
boolean isAClass = !(traits.isEmpty() && extendsOp == null && implementsOp.isEmpty());
if (isAClass) {
List<GraphTargetItem> output2 = new ArrayList<>();
for (int i = 0; i < prevCount; i++) {
output2.add(output.get(i));
}
output2.add(new ClassActionItem(className, extendsOp, implementsOp, traits, traitsStatic));
return output2;
} else {
ok = false;
}
} else {
ok = false;
}
}
} else {
ok = false;
}
} else {
ok = false;
}
} else if (!(t instanceof PopItem)) {
prevCount++;
//ok = false;
}
if (!ok) {
break;
}
}
return output;
}
@Override
public boolean ignoredLoops() {
return false;

View File

@@ -12,7 +12,8 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* License along with this library.
*/
package com.jpexs.decompiler.flash.action;
import com.jpexs.decompiler.flash.BaseLocalData;
@@ -81,7 +82,7 @@ public class ActionGraph extends Graph {
}
@Override
@Override
public void finalProcessStack(TranslateStack stack, List<GraphTargetItem> output, String path) {
if (stack.size() > 0) {
for (int i = stack.size() - 1; i >= 0; i--) {
//System.err.println(stack.get(i));
@@ -96,12 +97,10 @@ public class ActionGraph extends Graph {
}
@Override
@Override
protected void finalProcess(List<GraphTargetItem> list, int level, FinalProcessLocalData localData) throws InterruptedException {
List<GraphTargetItem> ret = Action.checkClass(list);
if (ret != list) {
list.clear();
list.addAll(ret);
protected void finalProcess(List<GraphTargetItem> list, int level, FinalProcessLocalData localData, String path) throws InterruptedException {
ActionScript2ClassDetector detector = new ActionScript2ClassDetector();
detector.checkClass(list, path);
int targetStart;
int targetEnd;
@@ -188,7 +187,7 @@ public class ActionGraph extends Graph {
}
}
//Handle for loops at the end:
//Handle for loops at the end:
super.finalProcess(list, level, localData, path);
}

View File

@@ -12,11 +12,12 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* License along with this library.
*/
package com.jpexs.decompiler.flash.action;
import com.jpexs.decompiler.flash.BaseLocalData;
import com.jpexs.decompiler.flash.BaseLocalData;
import com.jpexs.helpers.Reference;
import com.jpexs.decompiler.graph.GraphPart;
import com.jpexs.decompiler.graph.GraphSource;
import com.jpexs.decompiler.graph.GraphSourceItem;

View File

@@ -0,0 +1,685 @@
/*
* Copyright (C) 2010-2018 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package com.jpexs.decompiler.flash.action;
import com.jpexs.decompiler.flash.action.model.CallFunctionActionItem;
import com.jpexs.helpers.Reference;
import com.jpexs.decompiler.flash.action.model.CallMethodActionItem;
import com.jpexs.decompiler.flash.action.model.DirectValueActionItem;
import com.jpexs.decompiler.flash.action.model.ExtendsActionItem;
import com.jpexs.decompiler.flash.action.model.FunctionActionItem;
import com.jpexs.decompiler.flash.action.model.GetMemberActionItem;
import com.jpexs.decompiler.flash.action.model.GetVariableActionItem;
import com.jpexs.decompiler.flash.action.model.ImplementsOpActionItem;
import com.jpexs.decompiler.flash.action.model.NewMethodActionItem;
import com.jpexs.decompiler.flash.action.model.NewObjectActionItem;
import com.jpexs.decompiler.flash.action.model.SetMemberActionItem;
import com.jpexs.decompiler.flash.action.model.SetVariableActionItem;
import com.jpexs.decompiler.flash.action.model.StoreRegisterActionItem;
import com.jpexs.decompiler.flash.action.model.TemporaryRegister;
import com.jpexs.decompiler.flash.action.model.clauses.ClassActionItem;
import com.jpexs.decompiler.flash.action.model.clauses.InterfaceActionItem;
import com.jpexs.decompiler.flash.action.swf4.RegisterNumber;
import com.jpexs.decompiler.flash.ecma.Null;
import com.jpexs.decompiler.flash.helpers.collections.MyEntry;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.model.IfItem;
import com.jpexs.decompiler.graph.model.NotItem;
import com.jpexs.decompiler.graph.model.PopItem;
import com.jpexs.decompiler.graph.model.PushItem;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author JPEXS
*/
public class ActionScript2ClassDetector {
private static final Logger logger = Logger.getLogger(ActionScript2ClassDetector.class.getName());
private class AssertException extends Exception {
private final String condition;
public AssertException(String condition) {
super(condition);
this.condition = condition;
}
public String getCondition() {
return condition;
}
}
/**
* Checks whether an item is direct submember of path. a.b.c.d is submember
* of a.b.c, x.y.z is not submember of x,
*
* @param item
* @param objectPath
* @param newPathItem New submember name
* @return
*/
private boolean isMemberOfPath(GraphTargetItem item, List<String> objectPath, Reference<String> newPathItem) {
List<String> path = getMembersPath(item);
if (path == null) {
return false;
}
if (path.size() != objectPath.size() + 1) {
return false;
}
for (int i = 0; i < objectPath.size(); i++) {
if (!path.get(i).equals(objectPath.get(i))) {
return false;
}
}
newPathItem.setVal(path.get(path.size() - 1));
return true;
}
/**
* Gets path of variable and its getMembers: a.b.c.d => [a,b,c,d]
*
* @param item
* @return List of path or null if not members path
*/
private List<String> getMembersPath(GraphTargetItem item) {
List<String> ret = new ArrayList<>();
while (item instanceof GetMemberActionItem) {
GetMemberActionItem mem = (GetMemberActionItem) item;
if (!(mem.memberName instanceof DirectValueActionItem)) {
return null;
}
DirectValueActionItem dv = ((DirectValueActionItem) mem.memberName);
if (!dv.isString()) {
return null;
}
ret.add(0, dv.getAsString());
item = mem.object;
}
if (!(item instanceof GetVariableActionItem)) {
return null;
}
GetVariableActionItem gv = (GetVariableActionItem) item;
if (!(gv.name instanceof DirectValueActionItem)) {
return null;
}
DirectValueActionItem dv = ((DirectValueActionItem) gv.name);
if (!dv.isString()) {
return null;
}
String varName = dv.getAsString();
ret.add(0, varName);
return ret;
}
private GraphTargetItem setMemberToGetMember(GraphTargetItem item) {
if (item instanceof SetMemberActionItem) {
return new GetMemberActionItem(null, null, ((SetMemberActionItem) item).object, ((SetMemberActionItem) item).objectName);
} else if (item instanceof SetVariableActionItem) {
return new GetVariableActionItem(null, null, ((SetVariableActionItem) item).name);
}
return null;
}
private GraphTargetItem newToGetMember(GraphTargetItem nobj) throws AssertException {
if (nobj instanceof NewMethodActionItem) {
NewMethodActionItem nm = (NewMethodActionItem) nobj;
return new GetMemberActionItem(nobj.getSrc(), nobj.getLineStartItem(), nm.scriptObject, nm.methodName);
} else if (nobj instanceof NewObjectActionItem) {
NewObjectActionItem no = (NewObjectActionItem) nobj;
return new GetVariableActionItem(nobj.getSrc(), nobj.getLineStartItem(), no.objectName);
}
throw new AssertException("NewMethod or NewObject expected");
}
private List<String> getSetMembersPath(GraphTargetItem item) {
if (item instanceof SetVariableActionItem) {
SetVariableActionItem sv = (SetVariableActionItem) item;
if (!(sv.name instanceof DirectValueActionItem)) {
return null;
}
DirectValueActionItem nDv = (DirectValueActionItem) sv.name;
if (!nDv.isString()) {
return null;
}
List<String> ret = new ArrayList<>();
ret.add(nDv.getAsString());
return ret;
} else if (item instanceof SetMemberActionItem) {
SetMemberActionItem sm = (SetMemberActionItem) item;
if (!(sm.objectName instanceof DirectValueActionItem)) {
return null;
}
DirectValueActionItem onDv = (DirectValueActionItem) sm.objectName;
if (!onDv.isString()) {
return null;
}
String currentMemberName = onDv.getAsString();
List<String> path = getMembersPath(sm.object);
if (path == null) {
return null;
}
path.add(currentMemberName);
return path;
} else {
return null;
}
}
/**
* Get register id or -1 if not found
*
* @param item
* @return
*/
private int getAsRegisterNum(GraphTargetItem item, String assertName) throws AssertException {
if (item instanceof DirectValueActionItem) {
DirectValueActionItem dv = (DirectValueActionItem) item;
if (dv.value instanceof RegisterNumber) {
RegisterNumber rn = (RegisterNumber) dv.value;
return rn.number;
}
}
if (item instanceof TemporaryRegister) {
TemporaryRegister tr = (TemporaryRegister) item;
return tr.getRegId();
}
throw new AssertException("not a register - " + assertName);
}
/*private boolean isInstanceRegister(GraphTargetItem item, Reference<Integer> instanceReg, Reference<Integer> classReg,Reference<GraphTargetItem> extracted, String assertName) throws AssertException {
if (item instanceof DirectValueActionItem) {
DirectValueActionItem dv = (DirectValueActionItem) item;
if (dv.value instanceof RegisterNumber) {
RegisterNumber rn = (RegisterNumber) dv.value;
if (rn.number == instanceReg.getVal()) {
return true;
} else if (rn.number == classReg.getVal()) {
return false;
}else{
throw new AssertException(assertName + " - unknown register");
}
}
}
if (item instanceof TemporaryRegister) {
TemporaryRegister tr = (TemporaryRegister) item;
if (!"prototype".equals(getAsString(gm.memberName, "memberName"))) {
throw new AssertException("memberName not \"prototype\"");
}
return tr.getRegId();
}
}
*/
public static GraphTargetItem getWithoutGlobal(GraphTargetItem ti) {
GraphTargetItem t = ti;
if (!(t instanceof GetMemberActionItem)) {
return ti;
}
GetMemberActionItem lastMember = null;
while (((GetMemberActionItem) t).object instanceof GetMemberActionItem) {
lastMember = (GetMemberActionItem) t;
t = ((GetMemberActionItem) t).object;
}
if (((GetMemberActionItem) t).object instanceof GetVariableActionItem) {
GetVariableActionItem v = (GetVariableActionItem) ((GetMemberActionItem) t).object;
if (v.name instanceof DirectValueActionItem) {
if (((DirectValueActionItem) v.name).value instanceof String) {
if (((DirectValueActionItem) v.name).value.equals("_global")) {
GetVariableActionItem gvt = new GetVariableActionItem(null, null, ((GetMemberActionItem) t).memberName);
if (lastMember == null) {
return gvt;
} else {
lastMember.object = gvt;
}
}
}
}
}
return ti;
}
private String getAsString(GraphTargetItem item, String itemName) throws AssertException {
if (!(item instanceof DirectValueActionItem)) {
throw new AssertException(itemName + " not DirectValue");
}
DirectValueActionItem mnDv = (DirectValueActionItem) item;
if (!mnDv.isString()) {
throw new AssertException(itemName + " not string");
}
return mnDv.getAsString();
}
public void checkClass(List<GraphTargetItem> commands, String scriptPath) {
/*
class a.b.c.D:
if(!_global.a)
{
_global.a = new Object();
}
§§pop();
if(!_global.a.b)
{
_global.a.b = new Object();
}
§§pop();
if(!_global.a.b.c)
{
_global.a.b.c = new Object();
}
§§pop();
if(!_global.a.b.c.D)
{
...
§§push(ASSetPropFlags(a.b.c.D.prototype,null,1));
}
§§pop();
*/
List<String> pathToSearchInIfCond = new ArrayList<>();
pathToSearchInIfCond.add("_global");
looppos:
for (int pos = 0; pos < commands.size(); pos++) {
//start with _global.
if (pathToSearchInIfCond.size() > 1) {
pathToSearchInIfCond.clear();
pathToSearchInIfCond.add("_global");
}
loopcheck:
for (int checkPos = pos; checkPos < commands.size(); checkPos++) {
GraphTargetItem t = commands.get(checkPos);
if (t instanceof IfItem) {
IfItem it = (IfItem) t;
if (it.expression instanceof NotItem) {
NotItem nti = (NotItem) it.expression;
GraphTargetItem condType = nti.value;
Reference<String> newMemberNameRef = new Reference<>("");
if (isMemberOfPath(condType, pathToSearchInIfCond, newMemberNameRef)) {
pathToSearchInIfCond.add(newMemberNameRef.getVal());
//_global.a.b.c = new Object();
if ((it.onTrue.size() == 1) && (it.onTrue.get(0) instanceof SetMemberActionItem) && (((SetMemberActionItem) it.onTrue.get(0)).value instanceof NewObjectActionItem)) {
//skip §§pop item if its there right after if
if (checkPos + 1 < commands.size()) {
GraphTargetItem tnext = commands.get(checkPos + 1);
if (tnext instanceof PopItem) {
checkPos++;
}
}
continue loopcheck;
}
List<GraphTargetItem> parts = it.onTrue;
List<String> classNamePath = pathToSearchInIfCond;
classNamePath.remove(0); //remove "_global"
int ppos = 0;
GraphTargetItem item = parts.get(ppos);
GraphTargetItem extendsOp = null;
List<GraphTargetItem> implementsOp = new ArrayList<>();
if (item instanceof ExtendsActionItem) {
ExtendsActionItem et = (ExtendsActionItem) parts.get(ppos);
extendsOp = getWithoutGlobal(et.superclass);
ppos++;
item = parts.get(ppos);
}
try {
int instanceReg = -1;
int classReg = -1;
GraphTargetItem classNameTargetPath = null;
GraphTargetItem constructor = null;
if (item instanceof StoreRegisterActionItem) {
StoreRegisterActionItem sr = (StoreRegisterActionItem) item;
instanceReg = sr.register.number;
if (sr.value instanceof GetMemberActionItem) {
GetMemberActionItem gm = (GetMemberActionItem) sr.value;
if (gm.object instanceof TemporaryRegister) {
TemporaryRegister treg = (TemporaryRegister) gm.object;
classReg = treg.getRegId();
if (!"prototype".equals(getAsString(gm.memberName, "memberName"))) {
throw new AssertException("memberName not \"prototype\"");
}
if ((treg.value instanceof SetMemberActionItem) || (treg.value instanceof SetVariableActionItem)) {
List<String> path = getSetMembersPath(treg.value);
if (path == null || path.isEmpty()) {
logger.severe("Cannot detect class - tempreg value is not a path");
break loopcheck;
}
//remove _global if it's there - happens for classes in global package
if ("_global".equals(path.get(0))) {
path.remove(0);
}
if (classNamePath.equals(path)) {
//can start with _global for classes on top level
classNameTargetPath = getWithoutGlobal(setMemberToGetMember(treg.value));
//treg.value.value is the value being set - treg.value is setmember ot setvariable
if (!(treg.value.value instanceof StoreRegisterActionItem)) {
throw new AssertException("Constructor expected to be in storeregister");
}
if (!(treg.value.value.value instanceof FunctionActionItem)) {
throw new AssertException("Constructor expected as functionitem");
}
constructor = treg.value.value.value;
} else {
throw new AssertException("temporaryreg value does not match class path");
}
} else {
throw new AssertException("temporaryreg value not setmember/setvariable");
}
} else {
throw new AssertException("Getmember does not have TemporaryRegister as object");
}
} else {
throw new AssertException("Not Getmember in StoreRegister");
}
ppos++;
}
List<MyEntry<GraphTargetItem, GraphTargetItem>> traits = new ArrayList<>();
List<Boolean> traitsStatic = new ArrayList<>();
loopsetmembers:
for (; ppos < parts.size(); ppos++) {
item = parts.get(ppos);
if (item instanceof SetMemberActionItem) {
SetMemberActionItem sm = (SetMemberActionItem) item;
GraphTargetItem regValue;
int currentRegId = -1;
if (sm.object instanceof TemporaryRegister) {
TemporaryRegister tempReg = (TemporaryRegister) sm.object;
currentRegId = tempReg.getRegId();
regValue = tempReg.value;
} else if ((sm.object instanceof DirectValueActionItem) && (((DirectValueActionItem) sm.object).value instanceof RegisterNumber)) {
DirectValueActionItem dv = (DirectValueActionItem) sm.object;
RegisterNumber rn = ((RegisterNumber) dv.value);
currentRegId = rn.number;
regValue = dv.computedRegValue;
} else {
//might be an interface
List<String> path = getSetMembersPath(item);
if (path == null || path.isEmpty()) {
throw new AssertException("invalid setmember");
}
//remove _global if it's there - happens for classes in global package
if ("_global".equals(path.get(0))) {
path.remove(0);
}
if (!path.equals(classNamePath)) {
throw new AssertException("wrong path in setmember");
}
GraphTargetItem interfaceClass = getWithoutGlobal(setMemberToGetMember(item));
if (!(sm.value instanceof FunctionActionItem)) {
logger.severe("Cannot detect class - not a function in setmember");
break loopcheck;
}
FunctionActionItem f = (FunctionActionItem) sm.value;
if (!"".equals(f.functionName)) {
throw new AssertException("not unnamed func in setmember");
}
if (!f.actions.isEmpty()) {
throw new AssertException("not empty function in setmember");
}
if (!f.paramNames.isEmpty()) {
throw new AssertException("not empty params for function in setmember");
}
ppos++;
for (; ppos < parts.size(); ppos++) {
item = parts.get(ppos);
if (item instanceof ImplementsOpActionItem) {
if (!implementsOp.isEmpty()) {
throw new AssertException("multiple implementsAction");
}
ImplementsOpActionItem io = (ImplementsOpActionItem) item;
implementsOp = io.superclasses;
} else {
throw new AssertException("unknown iface item: " + item.getClass().getSimpleName());
}
}
InterfaceActionItem ifsItem = new InterfaceActionItem(interfaceClass, implementsOp);
for (int k = pos; k <= checkPos; k++) {
commands.remove(pos);
}
commands.add(pos, ifsItem);
//remove §§pop after, if it's there
if (pos + 1 < commands.size()) {
if (commands.get(pos + 1) instanceof PopItem) {
commands.remove(pos + 1);
}
}
// goto next line and check next classes
continue looppos;
}
//it was register .. continue class detection
if (currentRegId != instanceReg && currentRegId != classReg) {
if (!(regValue instanceof SetMemberActionItem)) {
throw new AssertException("temp register do not contain setmember");
}
SetMemberActionItem sm2 = (SetMemberActionItem) regValue;
GraphTargetItem pathSource;
boolean isPrototype;
if ("prototype".equals(getAsString(sm2.objectName, "objectName"))) {
pathSource = sm2.object;
isPrototype = true;
} else {
pathSource = setMemberToGetMember(sm2);
isPrototype = false;
}
List<String> memPath = getMembersPath(pathSource);
if (memPath == null) {
throw new AssertException("Invalid pathsource");
}
if (!classNamePath.equals(memPath)) {
throw new AssertException("Invalid path of setmember:" + String.join(".", memPath));
}
classNameTargetPath = pathSource;
if (!(sm2.value instanceof StoreRegisterActionItem)) {
throw new AssertException("Not storeregister");
}
StoreRegisterActionItem sr = (StoreRegisterActionItem) sm2.value;
if (sr.register.number != currentRegId) {
throw new AssertException("Invalid storeregister");
}
if (isPrototype && ((sr.value instanceof NewMethodActionItem) || (sr.value instanceof NewObjectActionItem))) {
extendsOp = newToGetMember(sr.value);
instanceReg = currentRegId;
} else if (!isPrototype && (sr.value instanceof FunctionActionItem)) { //constructor
constructor = sr.value;
classReg = currentRegId;
} else {
throw new AssertException("invalid storeregister value: " + sr.value.getClass().getSimpleName());
}
}
MyEntry<GraphTargetItem, GraphTargetItem> trait = new MyEntry<>(sm.objectName, sm.value);
if (sm.value instanceof FunctionActionItem) {
FunctionActionItem f = (FunctionActionItem) sm.value;
f.calculatedFunctionName = sm.objectName;
}
traits.add(trait);
if (currentRegId == instanceReg) {
traitsStatic.add(false);
} else if (currentRegId == classReg) {
traitsStatic.add(true);
}
} else if (item instanceof ImplementsOpActionItem) {
ImplementsOpActionItem iot = (ImplementsOpActionItem) item;
implementsOp = iot.superclasses;
} else {
break loopsetmembers;
}
}
looppushes:
for (; ppos < parts.size(); ppos++) {
item = parts.get(ppos);
if (item instanceof PushItem) {
PushItem pi = (PushItem) item;
if (pi.value instanceof CallMethodActionItem) {
CallMethodActionItem cm = (CallMethodActionItem) pi.value;
String pushMethodName = getAsString(cm.methodName, "push methodName");
if ("addProperty".equals(pushMethodName)) {
int rnumObject = getAsRegisterNum(cm.scriptObject, "addProperty not on register");
if ((rnumObject != instanceReg) && (rnumObject != classReg)) {
throw new AssertException("unexpected addProperty object register " + rnumObject);
}
if (cm.arguments.size() != 3) {
throw new AssertException("invalid number of arguments to addProperty: " + cm.arguments.size());
}
GraphTargetItem propertyName = cm.arguments.get(0);
GraphTargetItem propertyGetter = cm.arguments.get(1);
GraphTargetItem propertySetter = cm.arguments.get(2);
String propertyNameStr = getAsString(propertyName, "propertyName");
if (propertyGetter instanceof GetMemberActionItem) {
int regId = getAsRegisterNum(((GetMemberActionItem) propertyGetter).object, "getter member not register");
if (rnumObject != regId) {
throw new AssertException("getter register does not match property register " + regId + " <=> " + rnumObject);
}
String getterNameStr = getAsString(((GetMemberActionItem) propertyGetter).memberName, "getter memberName");
if (!(getterNameStr.equals("__get__" + propertyNameStr))) {
throw new AssertException("getter does not match property name");
}
//TODO: handle getter HERE
} else if (propertyGetter instanceof FunctionActionItem) {
FunctionActionItem getterFunc = (FunctionActionItem) propertyGetter;
if (!(getterFunc.actions.isEmpty() && getterFunc.functionName.isEmpty() && ((FunctionActionItem) propertyGetter).paramNames.isEmpty())) {
logger.severe("Cannot detect class - unexpected getter value for property " + propertyNameStr);
break loopcheck;
}
//we got empty getter
} else {
logger.severe("Cannot detect class - unexpected getter value for property " + propertyNameStr + ": " + propertyGetter.getClass().getSimpleName());
break loopcheck;
}
if (propertySetter instanceof GetMemberActionItem) {
int regId = getAsRegisterNum(((GetMemberActionItem) propertySetter).object, "setter member");
if (rnumObject != regId) {
throw new AssertException("setter register does not match property register " + regId + " <=> " + rnumObject);
}
String setterNameStr = getAsString(((GetMemberActionItem) propertySetter).memberName, "setter memberNAme");
if (!(setterNameStr.equals("__set__" + propertyNameStr))) {
throw new AssertException("setter does not match property name");
}
//TODO: handle setter HERE
} else if (propertySetter instanceof FunctionActionItem) {
FunctionActionItem setterFunc = (FunctionActionItem) propertySetter;
if (!(setterFunc.actions.isEmpty() && setterFunc.functionName.isEmpty() && ((FunctionActionItem) propertySetter).paramNames.isEmpty())) {
throw new AssertException("unexpected getter value for property " + propertyNameStr);
}
//we got empty setter
} else {
throw new AssertException("unexpected setter value for property " + propertyNameStr + ": " + propertySetter.getClass().getSimpleName());
}
} else {
throw new AssertException("unknown push method name: " + pushMethodName);
}
} else if (pi.value instanceof CallFunctionActionItem) {
CallFunctionActionItem cf = (CallFunctionActionItem) pi.value;
String funName = getAsString(cf.functionName, "pushitem function name");
if (funName.equals("ASSetPropFlags")) {
//it should be ASSetPropFlags(a.b.c.D.prototype,null,1) as it sets prototype to hidden
//see http://www.ryanjuckett.com/programming/how-to-use-assetpropflags-in-actionscript-2-0/
if (cf.arguments.size() != 3) {
throw new AssertException("Invalid number of arguments to ASSetPropFlags:" + cf.arguments.size() + ", 3 expected");
}
GraphTargetItem obj = cf.arguments.get(0);
GraphTargetItem props = cf.arguments.get(1);
GraphTargetItem flags = cf.arguments.get(2);
List<String> path = getMembersPath(obj);
if (path != null && !path.isEmpty() && "_global".equals(path.get(0))) { //For classes in toplevel package, there's _global in path
path.remove(0); //remove that _global
}
List<String> classPathWithPrototype = new ArrayList<>();
classPathWithPrototype.addAll(classNamePath);
classPathWithPrototype.add("prototype");
if (!classPathWithPrototype.equals(path)) {
throw new AssertException("ASSetPropFlags not on prototype");
}
if (!((props instanceof DirectValueActionItem) && (((DirectValueActionItem) props).value == Null.INSTANCE))) {
throw new AssertException("ASSetPropFlags properties param not null");
}
if (!((flags instanceof DirectValueActionItem) && (((DirectValueActionItem) flags).value == (Long) 1L))) {
throw new AssertException("ASSetPropFlags flags not set to 1");
}
} else {
throw new AssertException("unknown pushitem function call " + funName);
}
} else {
throw new AssertException("unknown pushitem - " + pi.value.getClass().getSimpleName());
}
} else {
throw new AssertException("unknown item - " + item.getClass().getSimpleName());
}
}//end loop pushes
if (constructor != null) { //constructor should be there always, but just in calse
//add constructor as trait
traitsStatic.add(0, false);
DirectValueActionItem classBaseName = new DirectValueActionItem(classNamePath.get(classNamePath.size() - 1));
((FunctionActionItem) constructor).calculatedFunctionName = classBaseName;
traits.add(0, new MyEntry<>(classBaseName, constructor));
} else {
throw new AssertException("No constructor found");
}
ClassActionItem clsItem = new ClassActionItem(classNameTargetPath, extendsOp, implementsOp, traits, traitsStatic);
for (int k = pos; k <= checkPos; k++) {
commands.remove(pos);
}
commands.add(pos, clsItem);
//remove §§pop after, if it's there
if (pos + 1 < commands.size()) {
if (commands.get(pos + 1) instanceof PopItem) {
commands.remove(pos + 1);
}
}
// goto next line and check next classes
continue looppos;
} catch (AssertException ex) {
logger.log(Level.WARNING, "{0}: Cannot detect class - {1}", new Object[]{scriptPath, ex.getCondition()});
break loopcheck;
}
} else {
break loopcheck; //not !_global.a.b or not member of previous
}
} else {
break loopcheck; //not an if !
}
} else {
break loopcheck; //not an if
}
} //loopcheck
}//looppos
}
}

View File

@@ -12,7 +12,8 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* License along with this library.
*/
package com.jpexs.decompiler.graph;
import com.jpexs.decompiler.flash.BaseLocalData;
@@ -643,25 +644,25 @@ public class Graph {
System.err.println("</loopspre>");//*/
List<GraphTargetItem> ret = printGraph(new HashMap<>(), new HashMap<>(), localData, stack, allParts, null, heads.get(0), null, loops, staticOperation, path);
processIfs(ret);
processIfs(ret);
finalProcessStack(stack, ret);
finalProcessStack(stack, ret, path);
finalProcessAll(ret, 0, new FinalProcessLocalData(), path);
return ret;
}
public void finalProcessStack(TranslateStack stack, List<GraphTargetItem> output, String path) {
}
private void finalProcessAll(List<GraphTargetItem> list, int level, FinalProcessLocalData localData) throws InterruptedException {
private void finalProcessAll(List<GraphTargetItem> list, int level, FinalProcessLocalData localData, String path) throws InterruptedException {
finalProcess(list, level, localData, path);
for (GraphTargetItem item : list) {
if (item instanceof Block) {
List<List<GraphTargetItem>> subs = ((Block) item).getSubs();
for (List<GraphTargetItem> sub : subs) {
for (List<GraphTargetItem> sub : subs) {
finalProcessAll(sub, level + 1, localData, path);
}
}
}
}
finalProcessAfter(list, level, localData, path);
}
private boolean processSubBlk(Block b, GraphTargetItem replacement) {
@@ -703,7 +704,7 @@ public class Graph {
return allSubPush && atleastOne;
}
protected void finalProcessAfter(List<GraphTargetItem> list, int level, FinalProcessLocalData localData, String path) {
if (list.size() >= 2) {
if (list.get(list.size() - 1) instanceof ExitItem) {
ExitItem e = (ExitItem) list.get(list.size() - 1);
@@ -719,7 +720,7 @@ public class Graph {
}
}
protected void finalProcess(List<GraphTargetItem> list, int level, FinalProcessLocalData localData, String path) throws InterruptedException {
//For detection based on debug line information
boolean[] toDelete = new boolean[list.size()];

View File

@@ -12,8 +12,9 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. */
package com.jpexs.decompiler.flash.abc.avm2.parser.script;
* License along with this library.
*/
package com.jpexs.helpers;
/**
*