#1260, #1438 AS1/2 direct editing on(xxx), onClipEvent(xxx) handlers

This commit is contained in:
Jindra Petřík
2021-02-14 11:26:29 +01:00
parent d4a5e03462
commit 03f033035f
16 changed files with 295 additions and 39 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;
import com.jpexs.decompiler.flash.action.Action;
@@ -2079,12 +2080,13 @@ public class SWFInputStream implements AutoCloseable {
* @param swf
* @param tag
* @param name
* @param parentClipActions
* @return CLIPACTIONRECORD value
* @throws IOException
*/
*/
public CLIPACTIONRECORD readCLIPACTIONRECORD(SWF swf, Tag tag, String name, CLIPACTIONS parentClipActions) throws IOException {
newDumpLevel(name, "CLIPACTIONRECORD");
newDumpLevel(name, "CLIPACTIONRECORD");
CLIPACTIONRECORD ret = new CLIPACTIONRECORD(swf, this, tag, parentClipActions);
endDumpLevel();
if (ret.eventFlags.isClear()) {
return null;
@@ -2108,7 +2110,7 @@ public class SWFInputStream implements AutoCloseable {
ret.allEventFlags = readCLIPEVENTFLAGS("allEventFlags");
CLIPACTIONRECORD cr;
ret.clipActionRecords = new ArrayList<>();
ret.clipActionRecords = new ArrayList<>();
while ((cr = readCLIPACTIONRECORD(swf, tag, "record", ret)) != null) {
ret.clipActionRecords.add(cr);
}
endDumpLevel();

View File

@@ -138,6 +138,9 @@ import com.jpexs.decompiler.flash.helpers.StringBuilderTextWriter;
import com.jpexs.decompiler.flash.helpers.collections.MyEntry;
import com.jpexs.decompiler.flash.tags.DoInitActionTag;
import com.jpexs.decompiler.flash.tags.base.ASMSource;
import com.jpexs.decompiler.flash.types.BUTTONCONDACTION;
import com.jpexs.decompiler.flash.types.CLIPACTIONRECORD;
import com.jpexs.decompiler.flash.types.CLIPEVENTFLAGS;
import com.jpexs.decompiler.graph.CompilationException;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetItem;
@@ -226,10 +229,12 @@ public class ActionScript2Parser {
private final int swfVersion;
private List<String> swfClasses = new ArrayList<>();
private final ASMSource targetSource;
public ActionScript2Parser(SWF swf) {
public ActionScript2Parser(SWF swf, ASMSource targetSource) {
this.swfVersion = swf.version;
parseSwfClasses(swf);
this.targetSource = targetSource;
}
private long uniqLast = 0;
@@ -1841,8 +1846,7 @@ public class ActionScript2Parser {
} else if (newvar instanceof VariableActionItem) {
ret = new NewObjectActionItem(null, null, newvar, args);
}
}
else if (newvar instanceof ToNumberActionItem) {
} else if (newvar instanceof ToNumberActionItem) {
List<GraphTargetItem> args = new ArrayList<>();
if (((ToNumberActionItem) newvar).value != null) {
args.add(((ToNumberActionItem) newvar).value);
@@ -1996,6 +2000,172 @@ public class ActionScript2Parser {
this.constantPool = constantPool;
lexer = new ActionScriptLexer(new StringReader(str));
BUTTONCONDACTION newButtonCond = new BUTTONCONDACTION();
if (targetSource instanceof BUTTONCONDACTION) {
ParsedSymbol symb = lexer.lex();
if (symb.type != SymbolType.IDENTIFIER || !"on".equals(symb.value)) {
throw new ActionParseException("on keyword expected but " + symb + " found", lexer.yyline());
}
expectedType(SymbolType.PARENT_OPEN);
symb = lexer.lex();
boolean condEmpty = true;
while (symb.type == SymbolType.IDENTIFIER) {
condEmpty = false;
switch ((String) symb.value) {
case "press":
newButtonCond.condOverUpToOverDown = true;
break;
case "release":
newButtonCond.condOverDownToOverUp = true;
break;
case "releaseOutside":
newButtonCond.condOutDownToIdle = true;
break;
case "rollOver":
newButtonCond.condIdleToOverUp = true;
break;
case "rollOut":
newButtonCond.condOverUpToIddle = true;
break;
case "dragOut":
newButtonCond.condOverDownToOutDown = true;
break;
case "dragOver":
newButtonCond.condOutDownToOverDown = true;
break;
case "keyPress":
symb = lexer.lex();
expected(symb, lexer.yyline(), SymbolType.STRING);
Integer key = CLIPACTIONRECORD.stringToKey((String) symb.value);
if (key == null) {
throw new ActionParseException("Invalid key", lexer.yyline());
}
newButtonCond.condKeyPress = key;
break;
default:
throw new ActionParseException("Unrecognized event type", lexer.yyline());
}
symb = lexer.lex();
if (symb.type == SymbolType.PARENT_CLOSE) {
break;
}
expected(symb, lexer.yyline(), SymbolType.COMMA);
symb = lexer.lex();
}
expected(symb, lexer.yyline(), SymbolType.PARENT_CLOSE);
if (condEmpty) {
throw new ActionParseException("condition must be non empty", lexer.yyline());
}
expectedType(SymbolType.CURLY_OPEN);
}
CLIPEVENTFLAGS newClipEventFlags = new CLIPEVENTFLAGS();
int newClipActionRecordKey = 0;
if (targetSource instanceof CLIPACTIONRECORD) {
ParsedSymbol symb = lexer.lex();
if (symb.type != SymbolType.IDENTIFIER || (!"on".equals(symb.value) && !"onClipEvent".equals(symb.value))) {
throw new ActionParseException("on or onClipEvent keyword expected but " + symb + " found", lexer.yyline());
}
expectedType(SymbolType.PARENT_OPEN);
if ("on".equals(symb.value)) {
symb = lexer.lex();
boolean condEmpty = true;
while (symb.type == SymbolType.IDENTIFIER) {
condEmpty = false;
switch ((String) symb.value) {
case "press":
newClipEventFlags.clipEventPress = true;
break;
case "release":
newClipEventFlags.clipEventRelease = true;
break;
case "releaseOutside":
newClipEventFlags.clipEventReleaseOutside = true;
break;
case "rollOver":
newClipEventFlags.clipEventRollOver = true;
break;
case "rollOut":
newClipEventFlags.clipEventRollOut = true;
break;
case "dragOut":
newClipEventFlags.clipEventDragOut = true;
break;
case "dragOver":
newClipEventFlags.clipEventDragOver = true;
break;
case "initialize":
newClipEventFlags.clipEventInitialize = true;
break;
case "construct":
newClipEventFlags.clipEventConstruct = true;
break;
case "keyPress":
symb = lexer.lex();
expected(symb, lexer.yyline(), SymbolType.STRING);
Integer key = CLIPACTIONRECORD.stringToKey((String) symb.value);
if (key == null) {
throw new ActionParseException("Invalid key", lexer.yyline());
}
newClipActionRecordKey = key;
newClipEventFlags.clipEventKeyPress = true;
break;
default:
throw new ActionParseException("Unrecognized event type", lexer.yyline());
}
symb = lexer.lex();
if (symb.type == SymbolType.PARENT_CLOSE) {
break;
}
expected(symb, lexer.yyline(), SymbolType.COMMA);
symb = lexer.lex();
}
expected(symb, lexer.yyline(), SymbolType.PARENT_CLOSE);
if (condEmpty) {
throw new ActionParseException("condition must be non empty", lexer.yyline());
}
} else if ("onClipEvent".equals(symb.value)) {
symb = lexer.lex();
expected(symb, lexer.yyline(), SymbolType.IDENTIFIER);
switch ((String) symb.value) {
case "keyUp":
newClipEventFlags.clipEventKeyUp = true;
break;
case "keyDown":
newClipEventFlags.clipEventKeyDown = true;
break;
case "mouseUp":
newClipEventFlags.clipEventMouseUp = true;
break;
case "mouseDown":
newClipEventFlags.clipEventMouseDown = true;
break;
case "mouseMove":
newClipEventFlags.clipEventMouseMove = true;
break;
case "unload":
newClipEventFlags.clipEventUnload = true;
break;
case "enterFrame":
newClipEventFlags.clipEventEnterFrame = true;
break;
case "load":
newClipEventFlags.clipEventLoad = true;
break;
case "data":
newClipEventFlags.clipEventData = true;
break;
default:
throw new ActionParseException("Unrecognized clipEvent type", lexer.yyline());
}
expectedType(SymbolType.PARENT_CLOSE);
}
expectedType(SymbolType.CURLY_OPEN);
}
List<VariableActionItem> vars = new ArrayList<>();
List<FunctionActionItem> functions = new ArrayList<>();
retTree.addAll(commands(false, false, 0, vars, functions));
@@ -2034,9 +2204,34 @@ public class ActionScript2Parser {
v.setBoxedValue(new GetVariableActionItem(null, null, pushConst(varName)));
}
}
if ((targetSource instanceof BUTTONCONDACTION) || (targetSource instanceof CLIPACTIONRECORD)) {
expectedType(SymbolType.CURLY_CLOSE);
}
if (lexer.lex().type != SymbolType.EOF) {
throw new ActionParseException("Parsing finished before end of the file", lexer.yyline());
}
if (targetSource instanceof BUTTONCONDACTION) {
BUTTONCONDACTION targetButtonCond = (BUTTONCONDACTION) targetSource;
targetButtonCond.condIdleToOverDown = newButtonCond.condIdleToOverDown;
targetButtonCond.condIdleToOverUp = newButtonCond.condIdleToOverUp;
targetButtonCond.condOutDownToIdle = newButtonCond.condOutDownToIdle;
targetButtonCond.condOutDownToOverDown = newButtonCond.condOutDownToOverDown;
targetButtonCond.condOverDownToIdle = newButtonCond.condOverDownToIdle;
targetButtonCond.condOverDownToOutDown = newButtonCond.condOverDownToOutDown;
targetButtonCond.condOverDownToOverUp = newButtonCond.condOverDownToOverUp;
targetButtonCond.condOverUpToIddle = newButtonCond.condOverUpToIddle;
targetButtonCond.condOverUpToOverDown = newButtonCond.condOverUpToOverDown;
targetButtonCond.condKeyPress = newButtonCond.condKeyPress;
}
if (targetSource instanceof CLIPACTIONRECORD) {
CLIPACTIONRECORD targetClipActionRecord = (CLIPACTIONRECORD) targetSource;
targetClipActionRecord.eventFlags = newClipEventFlags;
targetClipActionRecord.keyCode = newClipActionRecordKey;
targetClipActionRecord.getParentClipActions().calculateAllEventFlags();
}
return retTree;
}

View File

@@ -73,7 +73,7 @@ public class AS2ScriptImporter {
if (new File(fileName).exists()) {
String txt = Helper.readTextFile(fileName);
ActionScript2Parser par = new ActionScript2Parser(asm.getSwf());
ActionScript2Parser par = new ActionScript2Parser(asm.getSwf(), asm);
try {
asm.setActions(par.actionsFromString(txt));
} catch (ActionParseException ex) {

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.types;
import com.jpexs.decompiler.flash.DisassemblyListener;
@@ -169,7 +170,7 @@ public class BUTTONCONDACTION implements ASMSource, Serializable {
*/
@Override
public String toString() {
public String toString() {
return "BUTTONCONDACTION " + getHeader(false);
}
/**
@@ -289,10 +290,10 @@ public class BUTTONCONDACTION implements ASMSource, Serializable {
if (condOverUpToIddle) {
events.add("rollOut");
}
}
if (condOverDownToOutDown || condOverDownToIdle) {
events.add("dragOut");
}
}
if (condOutDownToOverDown || condIdleToOverDown) {
events.add("dragOver");
}
if (condKeyPress > 0) {
@@ -337,7 +338,7 @@ public class BUTTONCONDACTION implements ASMSource, Serializable {
@Override
public String getExportFileName() {
public String getExportFileName() {
return "BUTTONCONDACTION " + getHeader(true);
}
@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.types;
import com.jpexs.decompiler.flash.DisassemblyListener;
@@ -44,12 +45,17 @@ import java.util.List;
public class CLIPACTIONRECORD implements ASMSource, Serializable {
private String scriptName = "-";
private CLIPACTIONS parentClipActions;
@Override
public String getScriptName() {
return scriptName;
}
public CLIPACTIONS getParentClipActions() {
return parentClipActions;
}
public static String keyToString(int key) {
if ((key < CLIPACTIONRECORD.KEYNAMES.length) && (key > 0) && (CLIPACTIONRECORD.KEYNAMES[key] != null)) {
return CLIPACTIONRECORD.KEYNAMES[key];
@@ -58,6 +64,20 @@ public class CLIPACTIONRECORD implements ASMSource, Serializable {
}
}
public static Integer stringToKey(String str) {
for (int i = 0; i < KEYNAMES.length; i++) {
if (KEYNAMES[i] != null) {
if (str.equals(KEYNAMES[i])) {
return i;
}
}
}
if (str.length() == 1) {
return (int) str.charAt(0);
}
return null;
}
public static final String[] KEYNAMES = {
null,
"<Left>",
@@ -113,7 +133,11 @@ public class CLIPACTIONRECORD implements ASMSource, Serializable {
this.scriptName = scriptName;
}
public void setParentClipActions(CLIPACTIONS parentClipActions) {
this.parentClipActions = parentClipActions;
}
public CLIPACTIONRECORD(SWF swf, SWFInputStream sis, Tag tag, CLIPACTIONS parentClipActions) throws IOException {
this.swf = swf;
this.tag = tag;
eventFlags = sis.readCLIPEVENTFLAGS("eventFlags");
@@ -126,6 +150,7 @@ public class CLIPACTIONRECORD implements ASMSource, Serializable {
actionRecordSize--;
}
actionBytes = sis.readByteRangeEx(actionRecordSize, "actionBytes", DumpInfoSpecialType.ACTION_BYTES, sis.getPos());
this.parentClipActions = parentClipActions;
}
@Override
@@ -157,7 +182,7 @@ public class CLIPACTIONRECORD implements ASMSource, Serializable {
*/
@Override
public String toString() {
public String toString() {
return "CLIPACTIONRECORD " + eventFlags.getHeader(keyCode, false);
}
/**
@@ -293,7 +318,7 @@ public class CLIPACTIONRECORD implements ASMSource, Serializable {
@Override
public String getExportFileName() {
public String getExportFileName() {
return "CLIPACTIONRECORD " + eventFlags.getHeader(keyCode, true);
}
@Override

View File

@@ -12,14 +12,18 @@
* 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.types;
import com.jpexs.decompiler.flash.types.annotations.Reserved;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Define event handlers for a sprite character
@@ -41,4 +45,24 @@ public class CLIPACTIONS implements Serializable {
* Individual event handlers
*/
public List<CLIPACTIONRECORD> clipActionRecords = new ArrayList<>();
public void calculateAllEventFlags() {
Field[] fields = allEventFlags.getClass().getDeclaredFields();
try {
for (Field f : fields) {
if (!f.getName().startsWith("clipEvent")) {
continue;
}
f.set(allEventFlags, false);
for (CLIPACTIONRECORD car : clipActionRecords) {
if (f.getBoolean(car.eventFlags)) {
f.set(allEventFlags, true);
}
}
}
} catch (IllegalArgumentException | IllegalAccessException ex) {
Logger.getLogger(CLIPACTIONS.class.getName()).log(Level.SEVERE, null, ex);
}
}
}