AS3 p-code more RAbcDasm like (parenthesis after True/False/Undefined/Null trait kinds)

AS3 method trait p-code indentation
AS3 editation of body traits (slot/const only)
This commit is contained in:
Jindra Petřík
2021-01-25 19:28:13 +01:00
parent 7083b75f8e
commit 58463d505d
13 changed files with 128 additions and 77 deletions

View File

@@ -1146,24 +1146,24 @@ public class AVM2Code implements Cloneable {
return s.toString();
}
public String toASMSource() {
return toASMSource(new AVM2ConstantPool());
public String toASMSource(ABC abc) {
return toASMSource(abc, abc.constants);
}
public String toASMSource(AVM2ConstantPool constants) {
public String toASMSource(ABC abc, AVM2ConstantPool constants) {
HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), false);
toASMSource(constants, null, null, new ArrayList<>(), ScriptExportMode.PCODE, writer);
toASMSource(abc, constants, null, null, new ArrayList<>(), ScriptExportMode.PCODE, writer);
return writer.toString();
}
public GraphTextWriter toASMSource(AVM2ConstantPool constants, MethodInfo info, MethodBody body, ScriptExportMode exportMode, GraphTextWriter writer) {
return toASMSource(constants, info, body, new ArrayList<>(), exportMode, writer);
public GraphTextWriter toASMSource(ABC abc, AVM2ConstantPool constants, MethodInfo info, MethodBody body, ScriptExportMode exportMode, GraphTextWriter writer) {
return toASMSource(abc, constants, info, body, new ArrayList<>(), exportMode, writer);
}
public GraphTextWriter toASMSource(AVM2ConstantPool constants, MethodInfo info, MethodBody body, List<Integer> outputMap, ScriptExportMode exportMode, GraphTextWriter writer) {
public GraphTextWriter toASMSource(ABC abc, AVM2ConstantPool constants, MethodInfo info, MethodBody body, List<Integer> outputMap, ScriptExportMode exportMode, GraphTextWriter writer) {
if (info != null) {
writer.appendNoHilight("method").newLine();
writer.appendNoHilight("method").indent().newLine();
writer.appendNoHilight("name ");
writer.hilightSpecial(info.name_index == 0 ? "null" : "\"" + Helper.escapeActionScriptString(info.getName(constants)) + "\"", HighlightSpecialType.METHOD_NAME);
writer.newLine();
@@ -1229,7 +1229,7 @@ public class AVM2Code implements Cloneable {
for (int i = 0; i < info.optional.length; i++) {
ValueKind vk = info.optional[i];
writer.appendNoHilight("optional ");
writer.hilightSpecial(vk.toString(constants), HighlightSpecialType.OPTIONAL, i);
writer.hilightSpecial(vk.toASMString(constants), HighlightSpecialType.OPTIONAL, i);
writer.newLine();
}
}
@@ -1241,7 +1241,7 @@ public class AVM2Code implements Cloneable {
Set<Long> importantOffsets = getImportantOffsets(body, true);
if (body != null) {
writer.appendNoHilight("body").newLine();
writer.appendNoHilight("body").indent().newLine();
writer.appendNoHilight("maxstack ");
writer.appendNoHilight(body.max_stack);
@@ -1282,10 +1282,14 @@ public class AVM2Code implements Cloneable {
writer.hilightSpecial(exception.name_index == 0 ? "null" : constants.getMultiname(exception.name_index).toString(constants, new ArrayList<>()), HighlightSpecialType.TRY_NAME, e);
writer.newLine();
}
for (Trait t : body.traits.traits) {
t.convertTraitHeader(abc, writer);
writer.unindent().appendNoHilight("end ; trait").newLine();
}
}
writer.newLine();
writer.appendNoHilight("code").newLine();
writer.appendNoHilight("code").indent().newLine();
int ip = 0;
int largeLimit = 20000;
boolean markOffsets = code.size() <= largeLimit;
@@ -1301,7 +1305,11 @@ public class AVM2Code implements Cloneable {
writer.newLine();
}
if (Configuration.showAllAddresses.get() || importantOffsets.contains(addr)) {
writer.appendNoHilight("ofs" + Helper.formatAddress(addr) + ":");
String label = "ofs" + Helper.formatAddress(addr) + ":";
writer.unindent().unindent().unindent();
writer.appendNoHilight(label);
writer.newLine();
writer.indent().indent().indent();
}
/*for (int e = 0; e < body.exceptions.length; e++) {
if (body.exceptions[e].start == ofs) {
@@ -1330,12 +1338,12 @@ public class AVM2Code implements Cloneable {
} else if (exportMode == ScriptExportMode.CONSTANTS) {
writer.appendNoHilight("Constant export mode is not supported.").newLine();
}
writer.appendNoHilight("end ; code").newLine();
writer.unindent().appendNoHilight("end ; code").newLine();
if (body != null) {
writer.appendNoHilight("end ; body").newLine();
writer.unindent().appendNoHilight("end ; body").newLine();
}
if (info != null) {
writer.appendNoHilight("end ; method").newLine();
writer.unindent().appendNoHilight("end ; method").newLine();
}
return writer;

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.parser.pcode;
import com.jpexs.decompiler.flash.abc.ABC;
@@ -37,6 +38,7 @@ import com.jpexs.decompiler.flash.abc.types.traits.Trait;
import com.jpexs.decompiler.flash.abc.types.traits.TraitFunction;
import com.jpexs.decompiler.flash.abc.types.traits.TraitMethodGetterSetter;
import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst;
import com.jpexs.decompiler.flash.abc.types.traits.Traits;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.helpers.Helper;
import java.io.IOException;
@@ -48,6 +50,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Stack;
/**
*
@@ -190,8 +193,7 @@ public class ASM3Parser {
}
public static boolean parseSlotConst(ABC abc, Reader reader, AVM2ConstantPool constants, TraitSlotConst tsc) throws IOException, AVM2ParseException {
private static boolean parseSlotConst(ABC abc, Flasm3Lexer lexer, AVM2ConstantPool constants, TraitSlotConst tsc) throws IOException, AVM2ParseException {
expected(ParsedSymbol.TYPE_KEYWORD_TRAIT, "trait", lexer);
ParsedSymbol symb = lexer.lex();
if (symb.type == ParsedSymbol.TYPE_KEYWORD_SLOT) {
@@ -220,6 +222,11 @@ public class ASM3Parser {
return true;
}
public static boolean parseSlotConst(ABC abc, Reader reader, AVM2ConstantPool constants, TraitSlotConst tsc) throws IOException, AVM2ParseException {
Flasm3Lexer lexer = new Flasm3Lexer(reader);
return parseSlotConst(abc, lexer, constants, tsc);
}
private static int parseNamespaceSet(AVM2ConstantPool constants, Flasm3Lexer lexer) throws AVM2ParseException, IOException {
List<Integer> namespaceList = new ArrayList<>();
ParsedSymbol s = lexer.lex();
@@ -519,12 +526,23 @@ public class ASM3Parser {
break;
case ParsedSymbol.TYPE_KEYWORD_TRUE:
value_kind = ValueKind.CONSTANT_True;
expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer);
expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer);
break;
case ParsedSymbol.TYPE_KEYWORD_FALSE:
value_kind = ValueKind.CONSTANT_False;
expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer);
expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer);
break;
case ParsedSymbol.TYPE_KEYWORD_NULL:
value_kind = ValueKind.CONSTANT_Null;
expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer);
expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer);
break;
case ParsedSymbol.TYPE_KEYWORD_UNDEFINED:
value_kind = ValueKind.CONSTANT_Undefined;
expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer);
expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer);
break;
case ParsedSymbol.TYPE_KEYWORD_NAMESPACE:
case ParsedSymbol.TYPE_KEYWORD_PACKAGEINTERNALNS:
@@ -571,7 +589,6 @@ public class ASM3Parser {
public static AVM2Code parse(ABC abc, Reader reader, Trait trait, MissingSymbolHandler missingHandler, MethodBody body, MethodInfo info) throws IOException, AVM2ParseException, InterruptedException {
AVM2ConstantPool constants = abc.constants;
AVM2Code code = new AVM2Code();
AVM2Code code = new AVM2Code();
boolean autoCloseBlocks = true; //TODO? Put to false. But how about old imports?
List<OffsetItem> offsetItems = new ArrayList<>();
List<LabelItem> labelItems = new ArrayList<>();
@@ -591,54 +608,62 @@ public class ASM3Parser {
List<Integer> paramTypes = new ArrayList<>();
List<Integer> paramNames = new ArrayList<>();
List<ValueKind> optional = new ArrayList<>();
Stack<Integer> blockStack = new Stack<>();
body.traits = new Traits();
do {
symb = lexer.lex();
if (Arrays.asList(ParsedSymbol.TYPE_KEYWORD_BODY, ParsedSymbol.TYPE_KEYWORD_CODE, ParsedSymbol.TYPE_KEYWORD_METHOD).contains(symb.type)) {
if (Arrays.asList(ParsedSymbol.TYPE_KEYWORD_BODY, ParsedSymbol.TYPE_KEYWORD_CODE, ParsedSymbol.TYPE_KEYWORD_METHOD).contains(symb.type)) {
blockStack.push(symb.type);
continue;
}
if (symb.type == ParsedSymbol.TYPE_KEYWORD_TRAIT) {
if (symb.type == ParsedSymbol.TYPE_KEYWORD_TRAIT) {
blockStack.push(symb.type);
if (trait == null) {
throw new AVM2ParseException("No trait expected", lexer.yyline());
}
}
symb = lexer.lex();
switch (symb.type) {
case ParsedSymbol.TYPE_KEYWORD_METHOD:
case ParsedSymbol.TYPE_KEYWORD_GETTER:
case ParsedSymbol.TYPE_KEYWORD_SETTER:
if (!(trait instanceof TraitMethodGetterSetter)) {
throw new AVM2ParseException("Unxpected trait type", lexer.yyline());
}
TraitMethodGetterSetter tm = (TraitMethodGetterSetter) trait;
switch (symb.type) {
case ParsedSymbol.TYPE_KEYWORD_METHOD:
tm.kindType = Trait.TRAIT_METHOD;
break;
case ParsedSymbol.TYPE_KEYWORD_GETTER:
tm.kindType = Trait.TRAIT_GETTER;
break;
case ParsedSymbol.TYPE_KEYWORD_SETTER:
tm.kindType = Trait.TRAIT_SETTER;
break;
}
tm.name_index = parseMultiName(constants, lexer);
parseTraitParams(abc, lexer, trait);
expected(ParsedSymbol.TYPE_KEYWORD_DISPID, "dispid", lexer);
symb = lexer.lex();
expected(symb, ParsedSymbol.TYPE_INTEGER, "Integer");
if (blockStack.contains(ParsedSymbol.TYPE_KEYWORD_BODY)) {
lexer.pushback(symb);
TraitSlotConst tsc = new TraitSlotConst();
parseSlotConst(abc, lexer, constants, tsc);
body.traits.addTrait(tsc);
} else {
symb = lexer.lex();
switch (symb.type) {
case ParsedSymbol.TYPE_KEYWORD_METHOD:
case ParsedSymbol.TYPE_KEYWORD_GETTER:
case ParsedSymbol.TYPE_KEYWORD_SETTER:
if (!(trait instanceof TraitMethodGetterSetter)) {
throw new AVM2ParseException("Unxpected trait type", lexer.yyline());
}
TraitMethodGetterSetter tm = (TraitMethodGetterSetter) trait;
switch (symb.type) {
case ParsedSymbol.TYPE_KEYWORD_METHOD:
tm.kindType = Trait.TRAIT_METHOD;
break;
case ParsedSymbol.TYPE_KEYWORD_GETTER:
tm.kindType = Trait.TRAIT_GETTER;
break;
case ParsedSymbol.TYPE_KEYWORD_SETTER:
tm.kindType = Trait.TRAIT_SETTER;
break;
}
tm.name_index = parseMultiName(constants, lexer);
parseTraitParams(abc, lexer, trait);
expected(ParsedSymbol.TYPE_KEYWORD_DISPID, "dispid", lexer);
symb = lexer.lex();
expected(symb, ParsedSymbol.TYPE_INTEGER, "Integer");
tm.disp_id = (int) (long) (Long) symb.value;
break;
case ParsedSymbol.TYPE_KEYWORD_FUNCTION:
if (!(trait instanceof TraitFunction)) {
throw new AVM2ParseException("Unxpected trait type", lexer.yyline());
}
//NAME
parseTraitParams(abc, lexer, trait);
break;
case ParsedSymbol.TYPE_KEYWORD_FUNCTION:
if (!(trait instanceof TraitFunction)) {
throw new AVM2ParseException("Unxpected trait type", lexer.yyline());
}
//NAME
parseTraitParams(abc, lexer, trait);
break;
}
}
continue;
}
@@ -793,11 +818,10 @@ public class ASM3Parser {
continue;
}
if (symb.type == ParsedSymbol.TYPE_KEYWORD_END) {
if (symb.type == ParsedSymbol.TYPE_KEYWORD_END) {
if (openedBlocks > 0) {
openedBlocks--;
if (blockStack.isEmpty()) {
throw new AVM2ParseException("End block encountered but there is no block opened", lexer.yyline());
}
blockStack.pop();
continue;
}
if (symb.type == ParsedSymbol.TYPE_INSTRUCTION_NAME) {
@@ -1065,8 +1089,8 @@ public class ASM3Parser {
}
} while (symb.type != ParsedSymbol.TYPE_EOF);
if (!autoCloseBlocks && openedBlocks > 0) {
if (!autoCloseBlocks && !blockStack.isEmpty()) {
throw new AVM2ParseException("End of the block expected: " + blockStack.size() + "x", lexer.yyline());
}
code.compact();

View File

@@ -284,7 +284,7 @@ public final class MethodBody implements Cloneable {
System.err.println("Decompiling " + path);
}
if (exportMode != ScriptExportMode.AS) {
getCode().toASMSource(abc.constants, abc.method_info.get(this.method_info), this, exportMode, writer);
getCode().toASMSource(abc, abc.constants, abc.method_info.get(this.method_info), this, exportMode, writer);
} else {
if ((DEBUG_FIXED != null && !path.endsWith(DEBUG_FIXED)) || (!Configuration.decompile.get())) {
writer.appendNoHilight(Helper.getDecompilationSkippedComment()).newLine();
@@ -337,7 +337,7 @@ public final class MethodBody implements Cloneable {
public GraphTextWriter toString(final String path, ScriptExportMode exportMode, final ABC abc, final Trait trait, final GraphTextWriter writer, final List<DottedChain> fullyQualifiedNames) throws InterruptedException {
if (exportMode != ScriptExportMode.AS) {
getCode().toASMSource(abc.constants, abc.method_info.get(this.method_info), this, exportMode, writer);
getCode().toASMSource(abc, abc.constants, abc.method_info.get(this.method_info), this, exportMode, writer);
} else {
if ((DEBUG_FIXED != null && !path.endsWith(DEBUG_FIXED)) || (!Configuration.decompile.get())) {
//writer.startMethod(this.method_info);

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.types;
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
@@ -187,16 +188,16 @@ public class ValueKind {
ret = "Utf8(\"" + Helper.escapeActionScriptString(constants.getString(value_index)) + "\")";
break;
case CONSTANT_True:
case CONSTANT_True:
ret = "True()";
break;
case CONSTANT_False:
case CONSTANT_False:
ret = "False()";
break;
case CONSTANT_Null:
case CONSTANT_Null:
ret = "Null()";
break;
case CONSTANT_Undefined:
case CONSTANT_Undefined:
ret = "Undefined()";
break;
case CONSTANT_Namespace:
case CONSTANT_PackageInternalNs:

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.types.traits;
import com.jpexs.decompiler.flash.IdentifiersDeobfuscation;
@@ -391,7 +392,7 @@ public abstract class Trait implements Cloneable, Serializable {
writer.hilightSpecial(traitType, HighlightSpecialType.TRAIT_TYPE);
writer.appendNoHilight(" ");
writer.hilightSpecial(abc.constants.multinameToString(name_index), HighlightSpecialType.TRAIT_NAME);
writer.hilightSpecial(abc.constants.multinameToString(name_index), HighlightSpecialType.TRAIT_NAME);
writer.indent();
if ((kindFlags & ATTR_Final) > 0) {
writer.newLine();
writer.append("flag ");
@@ -419,6 +420,7 @@ public abstract class Trait implements Cloneable, Serializable {
writer.append("\"");
writer.append(Helper.escapeActionScriptString(abc.constants.getString(abc.metadata_info.get(m).name_index)));
writer.append("\"");
writer.indent();
writer.newLine();
if (m >= 0 && m < abc.metadata_info.size()) {
for (int i = 0; i < abc.metadata_info.get(m).keys.length; i++) {
@@ -438,6 +440,7 @@ public abstract class Trait implements Cloneable, Serializable {
writer.newLine();
}
}
writer.unindent();
writer.append("end ; metadata");
}
}

View File

@@ -274,6 +274,9 @@ public class TraitClass extends Trait implements TraitWithSlot {
writer.appendNoHilight(" slotid ");
writer.hilightSpecial(Integer.toString(slot_id), HighlightSpecialType.SLOT_ID);
writer.newLine();
/*writer.appendNoHilight("class_info "); //not in RAbcDasm
writer.appendNoHilight("" + class_info);
writer.newLine();*/
return writer;
}

View File

@@ -143,6 +143,10 @@ public class TraitFunction extends Trait implements TraitWithSlot {
writer.newLine();
writer.appendNoHilight("slotid ");
writer.hilightSpecial(Integer.toString(slot_id), HighlightSpecialType.SLOT_ID);
writer.newLine();
/*writer.appendNoHilight("method_info ");//Not in RAbcDasm
writer.appendNoHilight("" + method_info);
writer.newLine();*/
return writer;
}

View File

@@ -224,6 +224,9 @@ public class TraitMethodGetterSetter extends Trait {
writer.appendNoHilight("dispid ");
writer.hilightSpecial("" + disp_id, HighlightSpecialType.DISP_ID);
writer.newLine();
/*writer.appendNoHilight("method_info ");//Not in RAbcDasm
writer.appendNoHilight("" + method_info);
writer.newLine();*/
return writer;
}

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.search;
import com.jpexs.decompiler.flash.SWF;
@@ -155,7 +156,7 @@ public class ActionScriptSearch {
if (bodyIndex != -1) {
MethodBody body = abc.bodies.get(bodyIndex);
HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), true);
HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), true);
abc.bodies.get(bodyIndex).getCode().toASMSource(abc, abc.constants, abc.method_info.get(body.method_info), body, ScriptExportMode.PCODE, writer);
String text = writer.toString();
if (pat.matcher(text).find()) {
ABCSearchResult searchResult = new ABCSearchResult(pack, methodInfo.getClassIndex(), methodInfo.getTraitId());