Fixed AS3 XML embedded variables display and direct edit

This commit is contained in:
Jindra Petřík
2023-03-19 22:43:41 +01:00
parent 687035273c
commit 9967bc0937
17 changed files with 1018 additions and 958 deletions
@@ -30,10 +30,13 @@ import com.jpexs.decompiler.flash.abc.avm2.model.FindPropertyAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.GetLexAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.GetPropertyAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.GetSlotAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.LocalRegAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.RegExpAvm2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.StringAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.XMLAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.operations.AddAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.parser.script.SlotAVM2Item;
import com.jpexs.decompiler.flash.ecma.ObjectType;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateStack;
@@ -76,17 +79,28 @@ public class ConstructIns extends InstructionDefinition {
}
public static boolean walkXML(GraphTargetItem item, List<GraphTargetItem> list) {
boolean ret = true;
if (item instanceof StringAVM2Item) {
list.add(item);
} else if (item instanceof AddAVM2Item) {
ret = ret && walkXML(((AddAVM2Item) item).leftSide, list);
ret = ret && walkXML(((AddAVM2Item) item).rightSide, list);
boolean ret = walkXMLSub(item, list);
if (list.size() == 1) {
return true;
}
return ret;
}
public static boolean walkXMLSub(GraphTargetItem item, List<GraphTargetItem> list) {
boolean ret = false;
if (item instanceof AddAVM2Item) {
if (walkXMLSub(((AddAVM2Item) item).leftSide, list)) {
ret = true;
}
if (walkXMLSub(((AddAVM2Item) item).rightSide, list)) {
ret = true;
}
} else if ((item instanceof EscapeXElemAVM2Item) || (item instanceof EscapeXAttrAVM2Item)) {
ret = true;
list.add(item);
} else {
return false;
list.add(item);
}
return ret;
}
@@ -45,12 +45,30 @@ public class XMLAVM2Item extends AVM2Item {
}
@Override
public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException {
for (GraphTargetItem part : parts) {
public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException {
for (int i = 0; i < parts.size(); i++) {
GraphTargetItem part = parts.get(i);
GraphTargetItem partBefore = i > 0 ? parts.get(i - 1) : null;
GraphTargetItem partAfter = i < parts.size() - 1 ? parts.get(i + 1) : null;
if (part instanceof StringAVM2Item) {
writer.append(((StringAVM2Item) part).getValue());
} else {
String s = ((StringAVM2Item) part).getValue();
if (partAfter instanceof EscapeXAttrAVM2Item) {
if (s.endsWith("\"")) {
s = s.substring(0, s.length() - 1);
}
}
if (partBefore instanceof EscapeXAttrAVM2Item) {
if (s.startsWith("\"")) {
s = s.substring(1);
}
}
writer.append(s);
} else if ((part instanceof EscapeXElemAVM2Item) || (part instanceof EscapeXAttrAVM2Item)) {
part.toString(writer, localData);
} else {
writer.append("{");
part.appendTo(writer, localData);
writer.append("}");
}
}
return writer;
@@ -129,6 +129,7 @@ import java.util.Map;
import java.util.Stack;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
/**
*
@@ -1253,7 +1254,7 @@ public class ActionScript3Parser {
}
}
private List<GraphTargetItem> xmltag(List<List<NamespaceItem>> allOpenedNamespaces, TypeItem thisType, NamespaceItem pkg, Reference<Boolean> usesVars, List<String> openedTags, Reference<Integer> closedVarTags, Reference<Boolean> needsActivation, List<DottedChain> importedClasses, List<NamespaceItem> openedNamespaces, HashMap<String, Integer> registerVars, boolean inFunction, boolean inMethod, List<AssignableAVM2Item> variables) throws IOException, AVM2ParseException, InterruptedException {
private List<GraphTargetItem> xmltag(List<List<NamespaceItem>> allOpenedNamespaces, TypeItem thisType, NamespaceItem pkg, Reference<Boolean> usesVars, List<String> openedTags, Reference<Boolean> needsActivation, List<DottedChain> importedClasses, List<NamespaceItem> openedNamespaces, HashMap<String, Integer> registerVars, boolean inFunction, boolean inMethod, List<AssignableAVM2Item> variables) throws IOException, AVM2ParseException, InterruptedException {
ParsedSymbol s;
List<GraphTargetItem> rets = new ArrayList<>();
//GraphTargetItem ret = null;
@@ -1262,10 +1263,9 @@ public class ActionScript3Parser {
do {
s = lex();
List<String> sub = new ArrayList<>();
Reference<Integer> subclose = new Reference<>(0);
Reference<Boolean> subusesvars = new Reference<>(false);
switch (s.type) {
case XML_ATTRNAMEVAR_BEGIN: //add
case XML_ATTRNAMEVAR_BEGIN: // {...}= add
usesVars.setVal(true);
addS(rets, sb);
rets.add(expression(allOpenedNamespaces, thisType, pkg, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, true, variables, false));
@@ -1274,7 +1274,7 @@ public class ActionScript3Parser {
sb.append("=");
lexer.yybegin(ActionScriptLexer.XMLOPENTAGATTRIB);
break;
case XML_ATTRVALVAR_BEGIN: //esc_xattr
case XML_ATTRVALVAR_BEGIN: // ={...} esc_xattr
usesVars.setVal(true);
sb.append("\"");
addS(rets, sb);
@@ -1282,49 +1282,37 @@ public class ActionScript3Parser {
sb.append("\"");
expectedType(SymbolType.CURLY_CLOSE);
lexer.yybegin(ActionScriptLexer.XMLOPENTAG);
break;
case XML_INSTRATTRNAMEVAR_BEGIN: //add
usesVars.setVal(true);
addS(rets, sb);
rets.add(expression(allOpenedNamespaces, thisType, pkg, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, true, variables, false));
expectedType(SymbolType.CURLY_CLOSE);
expectedType(SymbolType.ASSIGN);
sb.append("=");
lexer.yybegin(ActionScriptLexer.XMLOPENTAGATTRIB);
break;
case XML_INSTRATTRVALVAR_BEGIN: //esc_xattr
usesVars.setVal(true);
sb.append("\"");
addS(rets, sb);
rets.add(new EscapeXAttrAVM2Item(null, null, expression(allOpenedNamespaces, thisType, pkg, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, true, variables, false)));
sb.append("\"");
expectedType(SymbolType.CURLY_CLOSE);
lexer.yybegin(ActionScriptLexer.XMLOPENTAG);
break;
case XML_VAR_BEGIN: //esc_xelem
break;
case XML_VAR_BEGIN: // {...} esc_xelem
usesVars.setVal(true);
addS(rets, sb);
rets.add(new EscapeXElemAVM2Item(null, null, expression(allOpenedNamespaces, thisType, pkg, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, true, variables, false)));
expectedType(SymbolType.CURLY_CLOSE);
lexer.yybegin(ActionScriptLexer.XML);
break;
case XML_FINISHVARTAG_BEGIN: //add
case XML_FINISHVARTAG_BEGIN: // </{...}> add
usesVars.setVal(true);
closedVarTags.setVal(closedVarTags.getVal() + 1);
sb.append("</");
addS(rets, sb);
rets.add(expression(allOpenedNamespaces, thisType, pkg, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, true, variables, false));
expectedType(SymbolType.CURLY_CLOSE);
expectedType(SymbolType.GREATER_THAN);
lexer.begin(ActionScriptLexer.XMLCLOSETAGFINISH);
s = lex();
while(s.isType(SymbolType.XML_TEXT)) {
sb.append(s.value);
s = lex();
}
expected(s, lexer.yyline(), SymbolType.GREATER_THAN);
sb.append(">");
addS(rets, sb);
lexer.yybegin(ActionScriptLexer.XML);
if (openedTags.isEmpty()) {
throw new AVM2ParseException("XML : Closing unopened tag", lexer.yyline());
}
openedTags.remove(openedTags.size() - 1);
break;
case XML_STARTVARTAG_BEGIN: //add
//openedTags.add("*");
//ret = add(ret, );
case XML_STARTVARTAG_BEGIN: // <{...}> add
GraphTargetItem ex = expression(allOpenedNamespaces, thisType, pkg, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, true, variables, false);
expectedType(SymbolType.CURLY_CLOSE);
lexer.yybegin(ActionScriptLexer.XMLOPENTAG);
@@ -1332,36 +1320,23 @@ public class ActionScript3Parser {
sb.append("<");
addS(rets, sb);
rets.add(ex);
rets.addAll(xmltag(allOpenedNamespaces, thisType, pkg, subusesvars, sub, subclose, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, variables));
closedVarTags.setVal(subclose.getVal() + subclose.getVal());
rets.addAll(xmltag(allOpenedNamespaces, thisType, pkg, subusesvars, sub, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, variables));
break;
case XML_INSTRVARTAG_BEGIN: //add
usesVars.setVal(true);
addS(rets, sb);
sb.append("<?");
addS(rets, sb);
rets.add(expression(allOpenedNamespaces, thisType, pkg, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, true, variables, false));
expectedType(SymbolType.CURLY_CLOSE);
lexer.yybegin(ActionScriptLexer.XMLINSTROPENTAG);
break;
case XML_STARTTAG_BEGIN:
case XML_STARTTAG_BEGIN: // <xxx>
sub.add(s.value.toString().trim().substring(1)); //remove < from beginning
List<GraphTargetItem> st = xmltag(allOpenedNamespaces, thisType, pkg, subusesvars, sub, closedVarTags, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, variables);
List<GraphTargetItem> st = xmltag(allOpenedNamespaces, thisType, pkg, subusesvars, sub, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, variables);
sb.append(s.value.toString());
addS(rets, sb);
rets.addAll(st);
closedVarTags.setVal(subclose.getVal() + subclose.getVal());
break;
/*case XML_STARTTAG_END:
sb.append(s.value.toString());
ret = addstr(ret,sb);
break;*/
case XML_FINISHTAG:
String tname = s.value.toString().substring(2, s.value.toString().length() - 1).trim();
if (openedTags.contains(tname)) {
openedTags.remove(tname);
} else if (openedTags.contains("*")) {
openedTags.remove("*");
if (openedTags.isEmpty()) {
throw new AVM2ParseException("XML : Closing unopened tag", lexer.yyline());
}
String lastTName = openedTags.get(openedTags.size() - 1);
if (lastTName.equals(tname) || lastTName.equals("*")) {
openedTags.remove(openedTags.size() - 1);
} else {
throw new AVM2ParseException("XML : Closing unopened tag", lexer.yyline());
}
@@ -1377,18 +1352,26 @@ public class ActionScript3Parser {
sb.append(s.value.toString());
break;
}
} while (!(openedTags.isEmpty() || closedVarTags.getVal() >= openedTags.size()));
} while (!openedTags.isEmpty());
addS(rets, sb);
return rets;
}
private GraphTargetItem xml(List<List<NamespaceItem>> allOpenedNamespaces, TypeItem thisType, NamespaceItem pkg, Reference<Boolean> needsActivation, List<DottedChain> importedClasses, List<NamespaceItem> openedNamespaces, HashMap<String, Integer> registerVars, boolean inFunction, boolean inMethod, List<AssignableAVM2Item> variables) throws IOException, AVM2ParseException, InterruptedException {
List<String> openedTags = new ArrayList<>();
int closedVarTags = 0;
GraphTargetItem ret = add(xmltag(allOpenedNamespaces, thisType, pkg, new Reference<>(false), openedTags, new Reference<>(closedVarTags), needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, variables));
List<String> openedTags = new ArrayList<>();
List<GraphTargetItem> xmlParts = xmltag(allOpenedNamespaces, thisType, pkg, new Reference<>(false), openedTags, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, variables);
lexer.setEnableWhiteSpace(true);
lexer.begin(ActionScriptLexer.YYINITIAL);
ParsedSymbol s = lexer.lex();
while (s.isType(SymbolType.XML_WHITESPACE)) {
addS(xmlParts, new StringBuilder(s.value.toString()));
s = lexer.lex();
}
lexer.setEnableWhiteSpace(false);
lexer.pushback(s);
GraphTargetItem ret = add(xmlParts);
ret = new XMLAVM2Item(ret);
lexer.yybegin(ActionScriptLexer.YYINITIAL);
//lexer.yybegin(ActionScriptLexer.YYINITIAL);
//TODO: Order of additions as in official compiler
return ret;
}
@@ -2282,6 +2265,7 @@ public class ActionScript3Parser {
break;
case XML_STARTTAG_BEGIN:
case XML_STARTVARTAG_BEGIN:
case XML_CDATA:
case XML_COMMENT:
lexer.pushback(s);
@@ -192,17 +192,20 @@ public enum SymbolType {
XML_STARTFINISHTAG_END(GraphTargetItem.PRECEDENCE_PRIMARY, false), // />
XML_COMMENT(GraphTargetItem.PRECEDENCE_PRIMARY, false), // <!-- ... -->
XML_CDATA(GraphTargetItem.PRECEDENCE_PRIMARY, false), //<![CDATA[ ... ]]>
XML_INSTR_BEGIN(GraphTargetItem.PRECEDENCE_PRIMARY, false), // <?xxx
XML_INSTR_END(GraphTargetItem.PRECEDENCE_PRIMARY, false), // ?>
XML_INSTR(GraphTargetItem.PRECEDENCE_PRIMARY, false), // <?xxx a b c ?>
//XML_INSTR_BEGIN(GraphTargetItem.PRECEDENCE_PRIMARY, false), // <?xxx
//XML_INSTR_END(GraphTargetItem.PRECEDENCE_PRIMARY, false), // ?>
XML_VAR_BEGIN(GraphTargetItem.PRECEDENCE_PRIMARY, false), // {
XML_ATTRIBUTENAME(GraphTargetItem.PRECEDENCE_PRIMARY, false), // aaa=
XML_ATTRIBUTEVALUE(GraphTargetItem.PRECEDENCE_PRIMARY, false), // "vvv"
XML_TEXT(GraphTargetItem.PRECEDENCE_PRIMARY, false),
XML_ATTRNAMEVAR_BEGIN(GraphTargetItem.PRECEDENCE_PRIMARY, false), // {...}=
XML_ATTRVALVAR_BEGIN(GraphTargetItem.PRECEDENCE_PRIMARY, false), // aaa={
XML_INSTRATTRNAMEVAR_BEGIN(GraphTargetItem.PRECEDENCE_PRIMARY, false), // {...}=
XML_INSTRATTRVALVAR_BEGIN(GraphTargetItem.PRECEDENCE_PRIMARY, false), // aaa={
XML_INSTRVARTAG_BEGIN(GraphTargetItem.PRECEDENCE_PRIMARY, false), // <?{
XML_END(GraphTargetItem.PRECEDENCE_PRIMARY, false),
XML_WHITESPACE(GraphTargetItem.PRECEDENCE_PRIMARY, false), //only when enabled - for example for XML
//XML_INSTRATTRNAMEVAR_BEGIN(GraphTargetItem.PRECEDENCE_PRIMARY, false), // {...}=
// XML_INSTRATTRVALVAR_BEGIN(GraphTargetItem.PRECEDENCE_PRIMARY, false), // aaa={
//XML_INSTRVARTAG_BEGIN(GraphTargetItem.PRECEDENCE_PRIMARY, false), // <?{
FILTER(GraphTargetItem.PRECEDENCE_PRIMARY, false),
DESCENDANTS(GraphTargetItem.PRECEDENCE_PRIMARY, false),
NATIVE,
@@ -86,10 +86,10 @@ public class FFDecAs3ScriptReplacer implements As3ScriptReplacerInterface {
abc.pack();//remove old deleted items
((Tag) abc.parentTag).setModified(true);
} catch (AVM2ParseException ex) {
//ex.printStackTrace();
ex.printStackTrace();
throw new As3ScriptReplaceException(new As3ScriptReplaceExceptionItem(null, ex.text, (int) ex.line));
} catch (CompilationException ex) {
//ex.printStackTrace();
ex.printStackTrace();
throw new As3ScriptReplaceException(new As3ScriptReplaceExceptionItem(null, ex.text, (int) ex.line));
}
}