fix: direct edit properties with getters/setters (#2655)

Fixes #2655
This commit is contained in:
Jindra Petřík
2026-03-07 19:02:24 +01:00
parent 2ebdd4e166
commit db9cd78e2c
13 changed files with 626 additions and 167 deletions

View File

@@ -712,11 +712,9 @@ public class ActionScript2ClassDetector {
}
if (pos >= 0 && func.actions.get(pos) instanceof ReturnActionItem) {
GraphTargetItem val = func.actions.get(pos);
if (val.value instanceof CallMethodActionItem) {
if (((CallMethodActionItem) val.value).methodName instanceof DirectValueActionItem) {
if (((CallMethodActionItem) val.value).methodName.toString().startsWith("__get__")) {
func.actions.remove(pos);
}
if (val.value instanceof GetMemberActionItem) {
if (((GetMemberActionItem) val.value).isGetter) {
func.actions.remove(pos);
}
}
}

View File

@@ -18,6 +18,8 @@ package com.jpexs.decompiler.flash.action.model;
import com.jpexs.decompiler.flash.IdentifiersDeobfuscation;
import com.jpexs.decompiler.flash.SourceGeneratorLocalData;
import com.jpexs.decompiler.flash.action.parser.script.ActionSourceGenerator;
import com.jpexs.decompiler.flash.action.swf4.ActionPush;
import com.jpexs.decompiler.flash.action.swf4.RegisterNumber;
import com.jpexs.decompiler.flash.action.swf5.ActionCallMethod;
import com.jpexs.decompiler.flash.ecma.Undefined;
@@ -52,26 +54,12 @@ public class CallMethodActionItem extends ActionItem {
/**
* Arguments
*/
public List<GraphTargetItem> arguments;
public List<GraphTargetItem> arguments;
/**
* Special - getter
* Is getter
*/
public static int SPECIAL_GETTER = 1;
/**
* Special - setter
*/
public static int SPECIAL_SETTER = 2;
/**
* Special
*/
private int special = 0;
/**
* Setter/getter variable name
*/
private String setterGetterVarName = null;
public boolean isGetter = false;
@Override
public void visit(GraphTargetVisitorInterface visitor) {
@@ -92,51 +80,11 @@ public class CallMethodActionItem extends ActionItem {
super(instruction, lineStartIns, PRECEDENCE_PRIMARY);
this.methodName = methodName;
this.arguments = arguments;
this.scriptObject = scriptObject;
if (methodName instanceof DirectValueActionItem) {
DirectValueActionItem dv = (DirectValueActionItem) methodName;
if (dv.isString()) {
String methodNameStr = dv.getAsString();
if (methodNameStr.startsWith("__get__") && arguments.isEmpty()) {
special = SPECIAL_GETTER;
setterGetterVarName = methodNameStr.substring(7);
} else if (methodNameStr.startsWith("__set__") && arguments.size() == 1) {
special = SPECIAL_SETTER;
setterGetterVarName = methodNameStr.substring(7);
precedence = PRECEDENCE_ASSIGNMENT;
}
}
}
this.scriptObject = scriptObject;
}
@Override
public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException {
if (special == SPECIAL_GETTER) {
if (scriptObject.getPrecedence() > this.precedence) {
writer.append("(");
scriptObject.toString(writer, localData);
writer.append(")");
} else {
scriptObject.toString(writer, localData);
}
writer.allowWrapHere().append(".");
writer.append(setterGetterVarName);
return writer;
} else if (special == SPECIAL_SETTER) {
if (scriptObject.getPrecedence() > this.precedence) {
writer.append("(");
scriptObject.toString(writer, localData);
writer.append(")");
} else {
scriptObject.toString(writer, localData);
}
writer.allowWrapHere().append(".");
writer.append(setterGetterVarName);
writer.append(" = ");
arguments.get(0).toStringNL(writer, localData);
return writer;
}
public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException {
if (methodName instanceof DirectValueActionItem) {
boolean blankMethod = false;
@@ -210,6 +158,23 @@ public class CallMethodActionItem extends ActionItem {
@Override
public List<GraphSourceItem> toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException {
if (isGetter) {
ActionSourceGenerator asGenerator = (ActionSourceGenerator) generator;
String charset = asGenerator.getCharset();
String methodNameAsStr = ((DirectValueActionItem) methodName).getAsString();
return toSourceMerge(
localData, generator,
toSourceCall(localData, generator, arguments),
new ActionPush((Long) (long) 0, charset),
scriptObject,
asGenerator.pushConst("__get__" + methodNameAsStr),
new ActionCallMethod(),
new ActionPush(Undefined.INSTANCE, charset),
new ActionCallMethod()
);
}
return toSourceMerge(localData, generator, toSourceCall(localData, generator, arguments), scriptObject, methodName, new ActionCallMethod());
}

View File

@@ -18,6 +18,9 @@ package com.jpexs.decompiler.flash.action.model;
import com.jpexs.decompiler.flash.IdentifiersDeobfuscation;
import com.jpexs.decompiler.flash.SourceGeneratorLocalData;
import com.jpexs.decompiler.flash.action.parser.script.ActionSourceGenerator;
import com.jpexs.decompiler.flash.action.swf4.ActionPush;
import com.jpexs.decompiler.flash.action.swf5.ActionCallMethod;
import com.jpexs.decompiler.flash.action.swf5.ActionDelete;
import com.jpexs.decompiler.flash.action.swf5.ActionDelete2;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
@@ -48,6 +51,11 @@ public class DeleteActionItem extends ActionItem {
*/
public GraphTargetItem propertyName;
/**
* Is getter
*/
public boolean isGetter = false;
@Override
public void visit(GraphTargetVisitorInterface visitor) {
visitor.visit(object);
@@ -108,6 +116,23 @@ public class DeleteActionItem extends ActionItem {
@Override
public List<GraphSourceItem> toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException {
if (isGetter) {
ActionSourceGenerator asGenerator = (ActionSourceGenerator) generator;
String charset = asGenerator.getCharset();
String propertyNameAsStr = ((DirectValueActionItem) propertyName).getAsString();
return toSourceMerge(
localData, generator,
new ActionPush((Long) (long) 0, charset),
object,
asGenerator.pushConst("__get__" + propertyNameAsStr),
new ActionCallMethod(),
new ActionDelete2()
);
}
if (object == null) {
return toSourceMerge(localData, generator, propertyName, new ActionDelete2());
}

View File

@@ -18,6 +18,9 @@ package com.jpexs.decompiler.flash.action.model;
import com.jpexs.decompiler.flash.IdentifiersDeobfuscation;
import com.jpexs.decompiler.flash.SourceGeneratorLocalData;
import com.jpexs.decompiler.flash.action.parser.script.ActionSourceGenerator;
import com.jpexs.decompiler.flash.action.swf4.ActionPush;
import com.jpexs.decompiler.flash.action.swf5.ActionCallMethod;
import com.jpexs.decompiler.flash.action.swf5.ActionGetMember;
import com.jpexs.decompiler.flash.helpers.CodeFormatting;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
@@ -54,6 +57,11 @@ public class GetMemberActionItem extends ActionItem {
*/
public boolean printObfuscatedMemberName = false;
/**
* Is getter
*/
public boolean isGetter = false;
@Override
public void visit(GraphTargetVisitorInterface visitor) {
visitor.visit(object);
@@ -148,6 +156,12 @@ public class GetMemberActionItem extends ActionItem {
@Override
public List<GraphSourceItem> toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException {
ActionSourceGenerator asGenerator = (ActionSourceGenerator) generator;
String charset = asGenerator.getCharset();
if (isGetter) {
String memberNameAsStr = ((DirectValueActionItem) memberName).getAsString();
return toSourceMerge(localData, generator, new ActionPush((Long) (long) 0, charset), object, asGenerator.pushConst("__get__" + memberNameAsStr), new ActionCallMethod());
}
return toSourceMerge(localData, generator, object, memberName, new ActionGetMember());
}

View File

@@ -18,6 +18,9 @@ package com.jpexs.decompiler.flash.action.model;
import com.jpexs.decompiler.flash.IdentifiersDeobfuscation;
import com.jpexs.decompiler.flash.SourceGeneratorLocalData;
import com.jpexs.decompiler.flash.action.parser.script.ActionSourceGenerator;
import com.jpexs.decompiler.flash.action.swf4.ActionPush;
import com.jpexs.decompiler.flash.action.swf5.ActionCallMethod;
import com.jpexs.decompiler.flash.action.swf5.ActionNewMethod;
import com.jpexs.decompiler.flash.ecma.Undefined;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
@@ -52,6 +55,11 @@ public class NewMethodActionItem extends ActionItem {
* Arguments
*/
public List<GraphTargetItem> arguments;
/**
* Is getter
*/
public boolean isGetter;
@Override
public void visit(GraphTargetVisitorInterface visitor) {
@@ -132,6 +140,24 @@ public class NewMethodActionItem extends ActionItem {
@Override
public List<GraphSourceItem> toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException {
if (isGetter) {
ActionSourceGenerator asGenerator = (ActionSourceGenerator) generator;
String charset = asGenerator.getCharset();
String methodNameAsStr = ((DirectValueActionItem) methodName).getAsString();
return toSourceMerge(
localData, generator,
toSourceCall(localData, generator, arguments),
new ActionPush((Long) (long) 0, charset),
scriptObject,
asGenerator.pushConst("__get__" + methodNameAsStr),
new ActionCallMethod(),
new ActionPush(Undefined.INSTANCE, charset),
new ActionNewMethod()
);
}
return toSourceMerge(localData, generator, toSourceCall(localData, generator, arguments), scriptObject, methodName, new ActionNewMethod());
}

View File

@@ -25,6 +25,7 @@ import com.jpexs.decompiler.flash.action.swf4.ActionPush;
import com.jpexs.decompiler.flash.action.swf4.ActionSetProperty;
import com.jpexs.decompiler.flash.action.swf4.ActionSetVariable;
import com.jpexs.decompiler.flash.action.swf4.RegisterNumber;
import com.jpexs.decompiler.flash.action.swf5.ActionCallMethod;
import com.jpexs.decompiler.flash.action.swf5.ActionDecrement;
import com.jpexs.decompiler.flash.action.swf5.ActionSetMember;
import com.jpexs.decompiler.flash.action.swf5.ActionStoreRegister;
@@ -115,7 +116,8 @@ public class PostDecrementActionItem extends ActionItem implements SetTypeAction
}
@Override
public List<GraphSourceItem> toSourceIgnoreReturnValue(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException {
public List<GraphSourceItem> toSourceIgnoreReturnValue(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException {
ActionSourceGenerator asGenerator = (ActionSourceGenerator) generator;
String charset = asGenerator.getCharset();
@@ -133,13 +135,26 @@ public class PostDecrementActionItem extends ActionItem implements SetTypeAction
ret.addAll(gv.toSource(localData, generator));
ret.add(new ActionDecrement());
ret.add(new ActionSetVariable());
} else if (val instanceof GetMemberActionItem) {
} else if (val instanceof GetMemberActionItem) {
GetMemberActionItem mem = (GetMemberActionItem) val;
ret.addAll(mem.toSource(localData, generator));
ret.remove(ret.size() - 1); //ActionGetMember
ret.addAll(mem.toSource(localData, generator));
ret.add(new ActionDecrement());
ret.add(new ActionSetMember());
if (mem.isGetter) {
String memberNameAsStr = ((DirectValueActionItem) mem.memberName).getAsString();
ret.addAll(toSourceMerge(localData, generator,
mem,
new ActionDecrement(),
new ActionPush((Long) (long) 1, charset),
mem.object,
asGenerator.pushConst("__set__" + memberNameAsStr),
new ActionCallMethod(),
new ActionPop()
));
} else {
ret.addAll(mem.toSource(localData, generator));
ret.remove(ret.size() - 1); //ActionGetMember
ret.addAll(mem.toSource(localData, generator));
ret.add(new ActionDecrement());
ret.add(new ActionSetMember());
}
} else if ((val instanceof DirectValueActionItem) && ((DirectValueActionItem) val).value instanceof RegisterNumber) {
RegisterNumber rn = (RegisterNumber) ((DirectValueActionItem) val).value;
ret.add(new ActionPush(new RegisterNumber(rn.number), charset));

View File

@@ -25,7 +25,9 @@ import com.jpexs.decompiler.flash.action.swf4.ActionPush;
import com.jpexs.decompiler.flash.action.swf4.ActionSetProperty;
import com.jpexs.decompiler.flash.action.swf4.ActionSetVariable;
import com.jpexs.decompiler.flash.action.swf4.RegisterNumber;
import com.jpexs.decompiler.flash.action.swf5.ActionCallMethod;
import com.jpexs.decompiler.flash.action.swf5.ActionIncrement;
import com.jpexs.decompiler.flash.action.swf5.ActionPushDuplicate;
import com.jpexs.decompiler.flash.action.swf5.ActionSetMember;
import com.jpexs.decompiler.flash.action.swf5.ActionStoreRegister;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
@@ -116,7 +118,7 @@ public class PostIncrementActionItem extends ActionItem implements SetTypeAction
@Override
public List<GraphSourceItem> toSourceIgnoreReturnValue(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException {
ActionSourceGenerator asGenerator = (ActionSourceGenerator) generator;
String charset = asGenerator.getCharset();
@@ -134,13 +136,26 @@ public class PostIncrementActionItem extends ActionItem implements SetTypeAction
ret.addAll(gv.toSource(localData, generator));
ret.add(new ActionIncrement());
ret.add(new ActionSetVariable());
} else if (val instanceof GetMemberActionItem) {
} else if (val instanceof GetMemberActionItem) {
GetMemberActionItem mem = (GetMemberActionItem) val;
ret.addAll(mem.toSource(localData, generator));
ret.remove(ret.size() - 1); //ActionGetMember
ret.addAll(mem.toSource(localData, generator));
ret.add(new ActionIncrement());
ret.add(new ActionSetMember());
if (mem.isGetter) {
String memberNameAsStr = ((DirectValueActionItem) mem.memberName).getAsString();
ret.addAll(toSourceMerge(localData, generator,
mem,
new ActionIncrement(),
new ActionPush((Long) (long) 1, charset),
mem.object,
asGenerator.pushConst("__set__" + memberNameAsStr),
new ActionCallMethod(),
new ActionPop()
));
} else {
ret.addAll(mem.toSource(localData, generator));
ret.remove(ret.size() - 1); //ActionGetMember
ret.addAll(mem.toSource(localData, generator));
ret.add(new ActionIncrement());
ret.add(new ActionSetMember());
}
} else if ((val instanceof DirectValueActionItem) && ((DirectValueActionItem) val).value instanceof RegisterNumber) {
RegisterNumber rn = (RegisterNumber) ((DirectValueActionItem) val).value;
ret.add(new ActionPush(new RegisterNumber(rn.number), charset));

View File

@@ -19,8 +19,10 @@ package com.jpexs.decompiler.flash.action.model;
import com.jpexs.decompiler.flash.IdentifiersDeobfuscation;
import com.jpexs.decompiler.flash.SourceGeneratorLocalData;
import com.jpexs.decompiler.flash.action.parser.script.ActionSourceGenerator;
import com.jpexs.decompiler.flash.action.swf4.ActionPop;
import com.jpexs.decompiler.flash.action.swf4.ActionPush;
import com.jpexs.decompiler.flash.action.swf4.RegisterNumber;
import com.jpexs.decompiler.flash.action.swf5.ActionCallMethod;
import com.jpexs.decompiler.flash.action.swf5.ActionSetMember;
import com.jpexs.decompiler.flash.action.swf5.ActionStoreRegister;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
@@ -66,6 +68,11 @@ public class SetMemberActionItem extends ActionItem implements SetTypeActionItem
* Compound operator
*/
public String compoundOperator;
/**
* Is setter
*/
public boolean isSetter = false;
@Override
public void visit(GraphTargetVisitorInterface visitor) {
@@ -166,6 +173,12 @@ public class SetMemberActionItem extends ActionItem implements SetTypeActionItem
public List<GraphSourceItem> toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException {
ActionSourceGenerator asGenerator = (ActionSourceGenerator) generator;
String charset = asGenerator.getCharset();
if (isSetter) {
String objectNameAsStr = ((DirectValueActionItem) objectName).getAsString();
return toSourceMerge(localData, generator, value, new ActionPush((Long) (long) 1, charset), object, asGenerator.pushConst("__set__" + objectNameAsStr), new ActionCallMethod());
}
int tmpReg = asGenerator.getTempRegister(localData);
try {
return toSourceMerge(localData, generator, object, objectName, value, new ActionStoreRegister(tmpReg, charset), new ActionSetMember(), new ActionPush(new RegisterNumber(tmpReg), charset));
@@ -176,6 +189,10 @@ public class SetMemberActionItem extends ActionItem implements SetTypeActionItem
@Override
public List<GraphSourceItem> toSourceIgnoreReturnValue(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException {
if (isSetter) {
return toSourceMerge(localData, generator, toSource(localData, generator), new ActionPop());
}
return toSourceMerge(localData, generator, object, objectName, value, new ActionSetMember());
}

View File

@@ -24,10 +24,12 @@ import com.jpexs.decompiler.flash.action.model.GetPropertyActionItem;
import com.jpexs.decompiler.flash.action.model.GetVariableActionItem;
import com.jpexs.decompiler.flash.action.parser.script.ActionSourceGenerator;
import com.jpexs.decompiler.flash.action.parser.script.VariableActionItem;
import com.jpexs.decompiler.flash.action.swf4.ActionPop;
import com.jpexs.decompiler.flash.action.swf4.ActionPush;
import com.jpexs.decompiler.flash.action.swf4.ActionSetProperty;
import com.jpexs.decompiler.flash.action.swf4.ActionSetVariable;
import com.jpexs.decompiler.flash.action.swf4.RegisterNumber;
import com.jpexs.decompiler.flash.action.swf5.ActionCallMethod;
import com.jpexs.decompiler.flash.action.swf5.ActionDecrement;
import com.jpexs.decompiler.flash.action.swf5.ActionSetMember;
import com.jpexs.decompiler.flash.action.swf5.ActionStoreRegister;
@@ -63,6 +65,15 @@ public class PreDecrementActionItem extends UnaryOpItem {
@Override
public List<GraphSourceItem> toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException {
return toSourceBoth(localData, generator, true);
}
@Override
public List<GraphSourceItem> toSourceIgnoreReturnValue(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException {
return toSourceBoth(localData, generator, false);
}
private List<GraphSourceItem> toSourceBoth(SourceGeneratorLocalData localData, SourceGenerator generator, boolean wantResult) throws CompilationException {
ActionSourceGenerator asGenerator = (ActionSourceGenerator) generator;
String charset = asGenerator.getCharset();
List<GraphSourceItem> ret = new ArrayList<>();
@@ -77,21 +88,40 @@ public class PreDecrementActionItem extends UnaryOpItem {
ret.addAll(gv.toSource(localData, generator));
ret.add(new ActionDecrement());
int tmpReg = asGenerator.getTempRegister(localData);
ret.add(new ActionStoreRegister(tmpReg, charset));
ret.add(new ActionSetVariable());
ret.add(new ActionPush(new RegisterNumber(tmpReg), charset));
asGenerator.releaseTempRegister(localData, tmpReg);
} else if (val instanceof GetMemberActionItem) {
GetMemberActionItem mem = (GetMemberActionItem) val;
ret.addAll(mem.toSource(localData, generator));
ret.remove(ret.size() - 1); //ActionGetMember
ret.addAll(mem.toSource(localData, generator));
ret.add(new ActionDecrement());
int tmpReg = asGenerator.getTempRegister(localData);
ret.add(new ActionStoreRegister(tmpReg, charset));
ret.add(new ActionSetMember());
ret.add(new ActionPush(new RegisterNumber(tmpReg), charset));
asGenerator.releaseTempRegister(localData, tmpReg);
GetMemberActionItem mem = (GetMemberActionItem) val;
if (mem.isGetter) {
String memberNameAsStr = ((DirectValueActionItem) mem.memberName).getAsString();
ret.addAll(toSourceMerge(localData, generator,
mem,
new ActionDecrement()
));
ret.addAll(toSourceMerge(localData, generator, new ActionPush((Long) (long) 1, charset),
mem.object,
asGenerator.pushConst("__set__" + memberNameAsStr),
new ActionCallMethod()));
} else {
ret.addAll(mem.toSource(localData, generator));
ret.remove(ret.size() - 1); //ActionGetMember
ret.addAll(mem.toSource(localData, generator));
ret.add(new ActionDecrement());
int tmpReg = 0;
if (wantResult) {
tmpReg = asGenerator.getTempRegister(localData);
ret.add(new ActionStoreRegister(tmpReg, charset));
}
ret.add(new ActionSetMember());
if (wantResult) {
ret.add(new ActionPush(new RegisterNumber(tmpReg), charset));
asGenerator.releaseTempRegister(localData, tmpReg);
}
return ret;
}
} else if ((val instanceof DirectValueActionItem) && ((DirectValueActionItem) val).value instanceof RegisterNumber) {
RegisterNumber rn = (RegisterNumber) ((DirectValueActionItem) val).value;
ret.add(new ActionPush(new RegisterNumber(rn.number), charset));
@@ -106,6 +136,9 @@ public class PreDecrementActionItem extends UnaryOpItem {
ret.add(new ActionDecrement());
ret.add(new ActionSetProperty());
}
if (!wantResult) {
ret.add(new ActionPop());
}
return ret;
}

View File

@@ -24,10 +24,12 @@ import com.jpexs.decompiler.flash.action.model.GetPropertyActionItem;
import com.jpexs.decompiler.flash.action.model.GetVariableActionItem;
import com.jpexs.decompiler.flash.action.parser.script.ActionSourceGenerator;
import com.jpexs.decompiler.flash.action.parser.script.VariableActionItem;
import com.jpexs.decompiler.flash.action.swf4.ActionPop;
import com.jpexs.decompiler.flash.action.swf4.ActionPush;
import com.jpexs.decompiler.flash.action.swf4.ActionSetProperty;
import com.jpexs.decompiler.flash.action.swf4.ActionSetVariable;
import com.jpexs.decompiler.flash.action.swf4.RegisterNumber;
import com.jpexs.decompiler.flash.action.swf5.ActionCallMethod;
import com.jpexs.decompiler.flash.action.swf5.ActionIncrement;
import com.jpexs.decompiler.flash.action.swf5.ActionSetMember;
import com.jpexs.decompiler.flash.action.swf5.ActionStoreRegister;
@@ -64,6 +66,15 @@ public class PreIncrementActionItem extends UnaryOpItem {
@Override
public List<GraphSourceItem> toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException {
return toSourceBoth(localData, generator, true);
}
@Override
public List<GraphSourceItem> toSourceIgnoreReturnValue(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException {
return toSourceBoth(localData, generator, false);
}
private List<GraphSourceItem> toSourceBoth(SourceGeneratorLocalData localData, SourceGenerator generator, boolean wantResult) throws CompilationException {
ActionSourceGenerator asGenerator = (ActionSourceGenerator) generator;
String charset = asGenerator.getCharset();
List<GraphSourceItem> ret = new ArrayList<>();
@@ -84,16 +95,34 @@ public class PreIncrementActionItem extends UnaryOpItem {
ret.add(new ActionPush(new RegisterNumber(tmpReg), charset));
asGenerator.releaseTempRegister(localData, tmpReg);
} else if (val instanceof GetMemberActionItem) {
GetMemberActionItem mem = (GetMemberActionItem) val;
ret.addAll(mem.toSource(localData, generator));
ret.remove(ret.size() - 1); //ActionGetMember
ret.addAll(mem.toSource(localData, generator));
ret.add(new ActionIncrement());
int tmpReg = asGenerator.getTempRegister(localData);
ret.add(new ActionStoreRegister(tmpReg, charset));
ret.add(new ActionSetMember());
ret.add(new ActionPush(new RegisterNumber(tmpReg), charset));
asGenerator.releaseTempRegister(localData, tmpReg);
GetMemberActionItem mem = (GetMemberActionItem) val;
if (mem.isGetter) {
String memberNameAsStr = ((DirectValueActionItem) mem.memberName).getAsString();
ret.addAll(toSourceMerge(localData, generator,
mem,
new ActionIncrement()
));
ret.addAll(toSourceMerge(localData, generator, new ActionPush((Long) (long) 1, charset),
mem.object,
asGenerator.pushConst("__set__" + memberNameAsStr),
new ActionCallMethod()));
} else {
ret.addAll(mem.toSource(localData, generator));
ret.remove(ret.size() - 1); //ActionGetMember
ret.addAll(mem.toSource(localData, generator));
ret.add(new ActionIncrement());
int tmpReg = 0;
if (wantResult) {
tmpReg = asGenerator.getTempRegister(localData);
ret.add(new ActionStoreRegister(tmpReg, charset));
}
ret.add(new ActionSetMember());
if (wantResult) {
ret.add(new ActionPush(new RegisterNumber(tmpReg), charset));
asGenerator.releaseTempRegister(localData, tmpReg);
}
return ret;
}
} else if ((val instanceof DirectValueActionItem) && ((DirectValueActionItem) val).value instanceof RegisterNumber) {
RegisterNumber rn = (RegisterNumber) ((DirectValueActionItem) val).value;
ret.add(new ActionPush(new RegisterNumber(rn.number), charset));
@@ -108,6 +137,9 @@ public class PreIncrementActionItem extends UnaryOpItem {
ret.add(new ActionIncrement());
ret.add(new ActionSetProperty());
}
if (!wantResult) {
ret.add(new ActionPop());
}
return ret;
}

View File

@@ -132,7 +132,9 @@ import com.jpexs.decompiler.flash.action.parser.ActionParseException;
import com.jpexs.decompiler.flash.action.swf4.ActionIf;
import com.jpexs.decompiler.flash.action.swf4.ActionPush;
import com.jpexs.decompiler.flash.action.swf4.ConstantIndex;
import com.jpexs.decompiler.flash.action.swf4.RegisterNumber;
import com.jpexs.decompiler.flash.action.swf5.ActionConstantPool;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.ecma.Null;
import com.jpexs.decompiler.flash.ecma.Undefined;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
@@ -176,10 +178,13 @@ import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
/**
* ActionScript 1/2 parser.
@@ -280,6 +285,7 @@ public class ActionScript2Parser {
this.charset = swf.getCharset();
parseSwfClasses(swf);
this.targetSource = targetSource;
this.swf = swf;
}
private long uniqLast = 0;
@@ -461,9 +467,139 @@ public class ActionScript2Parser {
return retf;
}
private GetMemberActionItem getFirstGetMember(GraphTargetItem item) {
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;
}
if (!(mem.object instanceof GetMemberActionItem)) {
return mem;
}
item = mem.object;
}
return null;
}
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 DirectValueActionItem) {
DirectValueActionItem dv1 = (DirectValueActionItem) item;
if (dv1.value instanceof RegisterNumber) {
RegisterNumber rn = (RegisterNumber) dv1.value;
if ("this".equals(rn.name)) {
ret.add(0, "this");
return ret;
}
if ("super".equals(rn.name)) {
ret.add(0, "super");
return ret;
}
}
}
if (!((item instanceof GetVariableActionItem || item instanceof VariableActionItem))) {
return null;
}
if (item instanceof GetVariableActionItem) {
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;
}
if (item instanceof VariableActionItem) {
VariableActionItem v = (VariableActionItem) item;
ret.add(0, v.getVariableName());
return ret;
}
return null;
}
private void fetchGettersSetters(List<String> parts, Set<String> superGetProperties, Set<String> superSetProperties) {
if (parts == null) {
return;
}
String fullExtendsName = String.join(".", parts);
String clsName = parts.remove(parts.size() - 1);
String key;
if (Configuration.flattenASPackages.get()) {
key = "\\__Packages\\" + String.join(".", parts) + "\\" + clsName;
} else {
key = "\\__Packages\\" + String.join("\\", parts) + "\\" + clsName;
}
ASMSource extendsAsm = swf.getASMs(false).get(key);
if (extendsAsm == null) {
return;
}
List<GraphTargetItem> list = extendsAsm.getActionsToTree();
for (GraphTargetItem it2 : list) {
if (it2 instanceof ClassActionItem) {
ClassActionItem cai = (ClassActionItem) it2;
List<String> cName = getMembersPath(cai.className);
if (cName != null) {
String fullExtendsName2 = String.join(".", cName);
if (fullExtendsName.equals(fullExtendsName2)) {
for (MyEntry<GraphTargetItem, GraphTargetItem> entry : cai.traits) {
String keyAsStr = entry.getKey().toString();
if (keyAsStr.startsWith("__set__")) {
superSetProperties.add(keyAsStr.substring("__set__".length()));
}
if (keyAsStr.startsWith("__get__")) {
superGetProperties.add(keyAsStr.substring("__get__".length()));
}
}
}
}
if (cai.extendsOp != null) {
fetchGettersSetters(getMembersPath(cai.extendsOp), superGetProperties, superSetProperties);
}
}
}
}
private GraphTargetItem traits(boolean isInterface, GraphTargetItem nameStr, GraphTargetItem extendsStr, List<GraphTargetItem> implementsStr, List<VariableActionItem> variables, List<FunctionActionItem> functions, boolean inTellTarget, Reference<Boolean> hasEval) throws IOException, ActionParseException, InterruptedException {
GraphTargetItem ret = null;
Set<String> superGetProperties = new HashSet<>();
Set<String> superSetProperties = new HashSet<>();
Set<String> thisGetProperties = new HashSet<>();
Set<String> thisSetProperties = new HashSet<>();
if (extendsStr != null) {
fetchGettersSetters(getMembersPath(extendsStr), superGetProperties, superSetProperties);
}
thisGetProperties.addAll(superGetProperties);
thisSetProperties.addAll(superSetProperties);
/*for (int i = 0; i < nameStr.size() - 1; i++) {
List<GraphTargetItem> notBody = new ArrayList<>();
List<String> globalClassTypeStr = new ArrayList<>();
@@ -487,7 +623,6 @@ public class ActionScript2Parser {
List<String> globalClassTypeStr = new ArrayList<>();
globalClassTypeStr.add("_global");
globalClassTypeStr.addAll(nameStr);*/
ParsedSymbol s;
List<MyEntry<GraphTargetItem, GraphTargetItem>> traits = new ArrayList<>();
List<Boolean> traitsStatic = new ArrayList<>();
@@ -534,6 +669,16 @@ public class ActionScript2Parser {
if (fname.equals(classNameStr)) { //constructor
//actually there's no difference, it's instance trait
}
if (!isStatic) {
if (isGetter) {
thisGetProperties.add(fname);
}
if (isSetter) {
thisSetProperties.add(fname);
}
}
if (!isInterface) {
if (isStatic) {
FunctionActionItem ft = function(!isInterface, "", true, variables, functions, inTellTarget, hasEval);
@@ -596,6 +741,113 @@ public class ActionScript2Parser {
}
}
for (MyEntry<GraphTargetItem, GraphTargetItem> it : traits) {
GraphTargetItem val = it.getValue();
Set<GraphTargetItem> subItems = val.getAllSubItemsRecursively();
subItems.add(val);
for (GraphTargetItem si : subItems) {
if (si instanceof GetMemberActionItem) {
List<String> path = getMembersPath(si);
if (path != null) {
String varName = path.get(0);
String memberName = path.get(1);
switch (varName) {
case "this":
if (thisGetProperties.contains(memberName)) {
GetMemberActionItem gm = getFirstGetMember(si);
gm.isGetter = true;
}
break;
case "super":
if (superGetProperties.contains(memberName)) {
GetMemberActionItem gm = getFirstGetMember(si);
gm.isGetter = true;
}
break;
}
}
}
if (si instanceof SetMemberActionItem) {
SetMemberActionItem sm = (SetMemberActionItem) si;
if (sm.objectName instanceof DirectValueActionItem
&& (sm.object instanceof VariableActionItem)) {
String memberName = ((DirectValueActionItem) sm.objectName).getAsString();
VariableActionItem v = (VariableActionItem) sm.object;
if ("this".equals(v.getVariableName())) {
if (thisSetProperties.contains(memberName)) {
sm.isSetter = true;
}
}
if ("super".equals(v.getVariableName())) {
if (superSetProperties.contains(memberName)) {
sm.isSetter = true;
}
}
}
}
if (si instanceof CallMethodActionItem) {
CallMethodActionItem cm = (CallMethodActionItem) si;
if (cm.methodName instanceof DirectValueActionItem
&& (cm.scriptObject instanceof VariableActionItem)) {
String memberName = ((DirectValueActionItem) cm.methodName).getAsString();
VariableActionItem v = (VariableActionItem) cm.scriptObject;
if ("this".equals(v.getVariableName())) {
if (thisGetProperties.contains(memberName)) {
cm.isGetter = true;
}
}
if ("super".equals(v.getVariableName())) {
if (superGetProperties.contains(memberName)) {
cm.isGetter = true;
}
}
}
}
if (si instanceof NewMethodActionItem) {
NewMethodActionItem nm = (NewMethodActionItem) si;
if (nm.methodName instanceof DirectValueActionItem
&& (nm.scriptObject instanceof VariableActionItem)) {
String memberName = ((DirectValueActionItem) nm.methodName).getAsString();
VariableActionItem v = (VariableActionItem) nm.scriptObject;
if ("this".equals(v.getVariableName())) {
if (thisGetProperties.contains(memberName)) {
nm.isGetter = true;
}
}
if ("super".equals(v.getVariableName())) {
if (superGetProperties.contains(memberName)) {
nm.isGetter = true;
}
}
}
}
if (si instanceof DeleteActionItem) {
DeleteActionItem d = (DeleteActionItem) si;
if (d.propertyName instanceof DirectValueActionItem
&& (d.object instanceof VariableActionItem)) {
String memberName = ((DirectValueActionItem) d.propertyName).getAsString();
VariableActionItem v = (VariableActionItem) d.object;
if ("this".equals(v.getVariableName())) {
if (thisGetProperties.contains(memberName)) {
d.isGetter = true;
}
}
if ("super".equals(v.getVariableName())) {
if (superGetProperties.contains(memberName)) {
d.isGetter = true;
}
}
}
}
}
}
if (isInterface) {
return new InterfaceActionItem(nameStr, implementsStr);
} else {

View File

@@ -23,11 +23,14 @@ import com.jpexs.decompiler.flash.action.ActionScriptObject;
import com.jpexs.decompiler.flash.action.LocalDataArea;
import com.jpexs.decompiler.flash.action.as2.Trait;
import com.jpexs.decompiler.flash.action.model.CallMethodActionItem;
import com.jpexs.decompiler.flash.action.model.DirectValueActionItem;
import com.jpexs.decompiler.flash.action.model.GetMemberActionItem;
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.SecondPassData;
import com.jpexs.decompiler.graph.TranslateStack;
import com.jpexs.decompiler.graph.model.AnyItem;
import com.jpexs.helpers.utf8.Utf8Helper;
import java.util.ArrayList;
import java.util.HashMap;
@@ -93,6 +96,26 @@ public class ActionCallMethod extends Action {
for (long l = 0; l < numArgs; l++) {
args.add(stack.pop());
}
if (methodName instanceof DirectValueActionItem) {
DirectValueActionItem dv = (DirectValueActionItem) methodName;
if (dv.isString()) {
String methodNameStr = dv.getAsString();
if (methodNameStr.startsWith("__get__") && args.isEmpty()) {
String varName = methodNameStr.substring(7);
GetMemberActionItem gm = new GetMemberActionItem(this, lineStartAction, scriptObject, new DirectValueActionItem(varName));
gm.isGetter = true;
stack.push(gm);
return;
} else if (methodNameStr.startsWith("__set__") && args.size() == 1) {
String varName = methodNameStr.substring(7);
int outSize = output.size();
ActionSetMember.handleSetMember(true, args.get(0), new DirectValueActionItem(varName), scriptObject, this, usedDeobfuscations, uninitializedClassTraits, secondPassData, insideDoInitAction, lineStartAction, stack, output, regNames, variables, functions, staticOperation, path);
return;
}
}
}
stack.push(new CallMethodActionItem(this, lineStartAction, scriptObject, methodName, args));
}

View File

@@ -38,6 +38,7 @@ import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.SecondPassData;
import com.jpexs.decompiler.graph.TranslateStack;
import com.jpexs.decompiler.graph.model.AnyItem;
import com.jpexs.decompiler.graph.model.CompoundableBinaryOp;
import com.jpexs.helpers.utf8.Utf8Helper;
import java.util.HashMap;
@@ -86,11 +87,37 @@ public class ActionSetMember extends Action {
GraphTargetItem value = stack.pop().getThroughDuplicate();
GraphTargetItem memberName = stack.pop();
GraphTargetItem object = stack.pop();
handleSetMember(false, value, memberName, object, this, usedDeobfuscations, uninitializedClassTraits, secondPassData, insideDoInitAction, lineStartAction, stack, output, regNames, variables, functions, staticOperation, path);
}
public static void handleSetMember(
boolean setter,
GraphTargetItem value,
GraphTargetItem memberName,
GraphTargetItem object,
Action action,
Set<String> usedDeobfuscations,
Map<String, Map<String, Trait>> uninitializedClassTraits,
SecondPassData secondPassData,
boolean insideDoInitAction,
GraphSourceItem lineStartAction,
TranslateStack stack,
List<GraphTargetItem> output,
HashMap<Integer, String> regNames,
HashMap<String, GraphTargetItem> variables,
HashMap<String, GraphTargetItem> functions,
int staticOperation,
String path
) {
if (value instanceof IncrementActionItem) {
GraphTargetItem obj = ((IncrementActionItem) value).object;
if (!stack.isEmpty() && stack.peek().valueEquals(obj)) {
stack.pop();
stack.push(new PostIncrementActionItem(this, lineStartAction, obj));
stack.push(new PostIncrementActionItem(action, lineStartAction, obj));
if (setter) {
stack.push(new AnyItem());
}
return;
}
}
@@ -98,82 +125,99 @@ public class ActionSetMember extends Action {
GraphTargetItem obj = ((DecrementActionItem) value).object;
if (!stack.isEmpty() && stack.peek().valueEquals(obj)) {
stack.pop();
stack.push(new PostDecrementActionItem(this, lineStartAction, obj));
stack.push(new PostDecrementActionItem(action, lineStartAction, obj));
if (setter) {
stack.push(new AnyItem());
}
return;
}
}
if (value instanceof IncrementActionItem) {
if (((IncrementActionItem) value).object instanceof GetMemberActionItem) {
if (((GetMemberActionItem) ((IncrementActionItem) value).object).object.getThroughDuplicate().equals(object)) {
if (((GetMemberActionItem) ((IncrementActionItem) value).object).memberName.equals(memberName)) {
((GetMemberActionItem) ((IncrementActionItem) value).object).object = ((GetMemberActionItem) ((IncrementActionItem) value).object).object.getThroughDuplicate();
output.add(new PostIncrementActionItem(this, lineStartAction, ((IncrementActionItem) value).object));
return;
}
}
}
}
if (value instanceof DecrementActionItem) {
if (((DecrementActionItem) value).object instanceof GetMemberActionItem) {
if (((GetMemberActionItem) ((DecrementActionItem) value).object).object.getThroughDuplicate().valueEquals(object)) {
if (((GetMemberActionItem) ((DecrementActionItem) value).object).memberName.equals(memberName)) {
((GetMemberActionItem) ((DecrementActionItem) value).object).object = ((GetMemberActionItem) ((DecrementActionItem) value).object).object.getThroughDuplicate();
output.add(new PostDecrementActionItem(this, lineStartAction, ((DecrementActionItem) value).object.getThroughDuplicate()));
return;
}
}
}
}
SetMemberActionItem setMem = new SetMemberActionItem(this, lineStartAction, object, memberName, value);
GraphTargetItem inside = value.getNotCoercedNoDup();
if (inside instanceof StoreRegisterActionItem) {
inside = inside.value;
}
if (inside instanceof CompoundableBinaryOpAs12) {
if (!object.hasSideEffect() && !memberName.hasSideEffect()) {
CompoundableBinaryOp binaryOp = (CompoundableBinaryOp) inside;
if (binaryOp.getLeftSide() instanceof GetMemberActionItem) {
GetMemberActionItem getMember = (GetMemberActionItem) binaryOp.getLeftSide();
if (GraphTargetItem.objectsValueEquals(object, getMember.object.getThroughDuplicate()) && GraphTargetItem.objectsValueEquals(memberName, getMember.memberName)) {
setMem.setCompoundValue(binaryOp.getRightSide());
setMem.setCompoundOperator(binaryOp.getOperator());
}
}
}
}
GraphTargetItem ret = setMem;
if (value instanceof StoreRegisterActionItem) {
StoreRegisterActionItem sr = (StoreRegisterActionItem) value;
if (sr.define) {
value = sr.getValue();
((SetMemberActionItem) ret).setValue(value);
if (value instanceof IncrementActionItem) {
if (((IncrementActionItem) value).object instanceof GetMemberActionItem) {
if (((GetMemberActionItem) ((IncrementActionItem) value).object).valueEquals(((SetMemberActionItem) ret).getObject())) {
ret = new PreIncrementActionItem(this, lineStartAction, ((IncrementActionItem) value).object);
try {
if (value instanceof IncrementActionItem) {
if (((IncrementActionItem) value).object instanceof GetMemberActionItem) {
if (((GetMemberActionItem) ((IncrementActionItem) value).object).object.getThroughDuplicate().equals(object)) {
if (((GetMemberActionItem) ((IncrementActionItem) value).object).memberName.equals(memberName)) {
((GetMemberActionItem) ((IncrementActionItem) value).object).object = ((GetMemberActionItem) ((IncrementActionItem) value).object).object.getThroughDuplicate();
if (setter) {
output.add(new PreIncrementActionItem(action, lineStartAction, ((IncrementActionItem) value).object.getThroughDuplicate()));
} else {
output.add(new PostIncrementActionItem(action, lineStartAction, ((IncrementActionItem) value).object.getThroughDuplicate()));
}
return;
}
}
} else if (value instanceof DecrementActionItem) {
if (((DecrementActionItem) value).object instanceof GetMemberActionItem) {
if (((GetMemberActionItem) ((DecrementActionItem) value).object).valueEquals(((SetMemberActionItem) ret).getObject())) {
ret = new PreDecrementActionItem(this, lineStartAction, ((DecrementActionItem) value).object);
}
}
if (value instanceof DecrementActionItem) {
if (((DecrementActionItem) value).object instanceof GetMemberActionItem) {
if (((GetMemberActionItem) ((DecrementActionItem) value).object).object.getThroughDuplicate().valueEquals(object)) {
if (((GetMemberActionItem) ((DecrementActionItem) value).object).memberName.equals(memberName)) {
((GetMemberActionItem) ((DecrementActionItem) value).object).object = ((GetMemberActionItem) ((DecrementActionItem) value).object).object.getThroughDuplicate();
if (setter) {
output.add(new PreDecrementActionItem(action, lineStartAction, ((IncrementActionItem) value).object.getThroughDuplicate()));
} else {
output.add(new PostDecrementActionItem(action, lineStartAction, ((DecrementActionItem) value).object.getThroughDuplicate()));
}
return;
}
}
} else {
sr.temporary = true;
((SetMemberActionItem) ret).setValue(sr);
}
TemporaryRegister tr = new TemporaryRegister(sr.register.number, ret);
variables.put("__register" + sr.register.number, tr);
output.add(new TemporaryRegisterMark(tr));
return;
}
SetMemberActionItem setMem = new SetMemberActionItem(action, lineStartAction, object, memberName, value);
setMem.isSetter = setter;
GraphTargetItem inside = value.getNotCoercedNoDup();
if (inside instanceof StoreRegisterActionItem) {
inside = inside.value;
}
if (inside instanceof CompoundableBinaryOpAs12) {
if (!object.hasSideEffect() && !memberName.hasSideEffect()) {
CompoundableBinaryOp binaryOp = (CompoundableBinaryOp) inside;
if (binaryOp.getLeftSide() instanceof GetMemberActionItem) {
GetMemberActionItem getMember = (GetMemberActionItem) binaryOp.getLeftSide();
if (GraphTargetItem.objectsValueEquals(object, getMember.object.getThroughDuplicate()) && GraphTargetItem.objectsValueEquals(memberName, getMember.memberName)) {
setMem.setCompoundValue(binaryOp.getRightSide());
setMem.setCompoundOperator(binaryOp.getOperator());
}
}
}
}
GraphTargetItem ret = setMem;
if (value instanceof StoreRegisterActionItem) {
StoreRegisterActionItem sr = (StoreRegisterActionItem) value;
if (sr.define) {
value = sr.getValue();
((SetMemberActionItem) ret).setValue(value);
if (value instanceof IncrementActionItem) {
if (((IncrementActionItem) value).object instanceof GetMemberActionItem) {
if (((GetMemberActionItem) ((IncrementActionItem) value).object).valueEquals(((SetMemberActionItem) ret).getObject())) {
ret = new PreIncrementActionItem(action, lineStartAction, ((IncrementActionItem) value).object);
}
}
} else if (value instanceof DecrementActionItem) {
if (((DecrementActionItem) value).object instanceof GetMemberActionItem) {
if (((GetMemberActionItem) ((DecrementActionItem) value).object).valueEquals(((SetMemberActionItem) ret).getObject())) {
ret = new PreDecrementActionItem(action, lineStartAction, ((DecrementActionItem) value).object);
}
}
} else {
sr.temporary = true;
((SetMemberActionItem) ret).setValue(sr);
}
TemporaryRegister tr = new TemporaryRegister(sr.register.number, ret);
variables.put("__register" + sr.register.number, tr);
output.add(new TemporaryRegisterMark(tr));
return;
}
}
output.add(ret);
} finally {
if (setter) {
stack.push(output.remove(output.size() - 1));
}
}
output.add(ret);
}
@Override