/* * Copyright (C) 2010-2016 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.abc.avm2.parser.pcode; import com.jpexs.decompiler.flash.abc.ABC; import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool; import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; import com.jpexs.decompiler.flash.abc.avm2.instructions.DeobfuscatePopIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition; import com.jpexs.decompiler.flash.abc.avm2.instructions.UnknownInstruction; import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushShortIns; import com.jpexs.decompiler.flash.abc.avm2.parser.AVM2ParseException; import com.jpexs.decompiler.flash.abc.types.ABCException; import com.jpexs.decompiler.flash.abc.types.Float4; import com.jpexs.decompiler.flash.abc.types.MetadataInfo; import com.jpexs.decompiler.flash.abc.types.MethodBody; import com.jpexs.decompiler.flash.abc.types.MethodInfo; import com.jpexs.decompiler.flash.abc.types.Multiname; import com.jpexs.decompiler.flash.abc.types.Namespace; import com.jpexs.decompiler.flash.abc.types.NamespaceSet; import com.jpexs.decompiler.flash.abc.types.ValueKind; 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.configuration.Configuration; import com.jpexs.helpers.Helper; import java.io.IOException; import java.io.Reader; import java.util.AbstractMap; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; /** * * @author JPEXS */ public class ASM3Parser { private static class OffsetItem { public String label = ""; public long insPosition; public int insOperandIndex; public OffsetItem(String label, long insOffset, int insOperandIndex) { this.label = label; this.insPosition = insOffset; this.insOperandIndex = insOperandIndex; } } private static class CaseOffsetItem extends OffsetItem { public CaseOffsetItem(String label, long insOffset, int insOperandIndex) { super(label, insOffset, insOperandIndex); } } private static class LabelItem { public String label = ""; public int offset; public LabelItem(String label, int offset) { this.label = label; this.offset = offset; } } public static AVM2Code parse(ABC abc, Reader reader, Trait trait, MethodBody body, MethodInfo info) throws IOException, AVM2ParseException, InterruptedException { return parse(abc, reader, trait, null, body, info); } private static int checkMultinameIndex(AVM2ConstantPool constants, int index, int line) throws AVM2ParseException { if ((index < 0) || (index >= constants.getMultinameCount())) { throw new AVM2ParseException("Invalid multiname index", line); } return index; } private static void expected(int type, String expStr, Flasm3Lexer lexer) throws IOException, AVM2ParseException { ParsedSymbol s = lexer.lex(); if (s.type != type) { throw new AVM2ParseException(expStr + " expected", lexer.yyline()); } } private static void expected(ParsedSymbol s, int type, String expStr) throws IOException, AVM2ParseException { if (s.type != type) { throw new AVM2ParseException(expStr + " expected", 0); } } private static void parseTraitParams(ABC abc, Flasm3Lexer lexer, Trait t) throws IOException, AVM2ParseException { ParsedSymbol symb;// = lexer.lex(); List<Map.Entry<String, Map<String, String>>> metadata = new ArrayList<>(); int flags = 0; while (true) { symb = lexer.lex(); if (symb.type == ParsedSymbol.TYPE_KEYWORD_FLAG) { symb = lexer.lex(); switch (symb.type) { case ParsedSymbol.TYPE_KEYWORD_FINAL: flags |= Trait.ATTR_Final; break; case ParsedSymbol.TYPE_KEYWORD_OVERRIDE: flags |= Trait.ATTR_Override; break; case ParsedSymbol.TYPE_KEYWORD_METADATA: flags |= Trait.ATTR_Metadata; break; default: throw new AVM2ParseException("Invalid trait flag", lexer.yyline()); } } else if (symb.type == ParsedSymbol.TYPE_KEYWORD_METADATA_BLOCK) { symb = lexer.lex(); expected(symb, ParsedSymbol.TYPE_STRING, "string metadata"); String mkey = (String) symb.value; symb = lexer.lex(); Map<String, String> items = new HashMap<>(); while (symb.type == ParsedSymbol.TYPE_KEYWORD_ITEM) { symb = lexer.lex(); expected(symb, ParsedSymbol.TYPE_STRING, "string key"); String key = (String) symb.value; symb = lexer.lex(); expected(symb, ParsedSymbol.TYPE_STRING, "string value"); String val = (String) symb.value; items.put(key, val); symb = lexer.lex(); } expected(symb, ParsedSymbol.TYPE_KEYWORD_END, "end"); symb = lexer.lex(); if (symb.type != ParsedSymbol.TYPE_COMMENT) { lexer.pushback(symb); } metadata.add(new AbstractMap.SimpleEntry<>(mkey, items)); } else { lexer.pushback(symb); break; } } t.kindFlags = flags; if ((flags & Trait.ATTR_Metadata) > 0) { int metadataArray[] = new int[metadata.size()]; for (int i = 0; i < metadata.size(); i++) { Map.Entry<String, Map<String, String>> entry = metadata.get(i); int mkey = abc.constants.getStringId(entry.getKey(), true); Map<String, String> items = entry.getValue(); int keys[] = new int[items.size()]; int vals[] = new int[items.size()]; int pos = 0; for (String key : items.keySet()) { int ikey = abc.constants.getStringId(key, true); int ival = abc.constants.getStringId(items.get(key), true); keys[pos] = ikey; vals[pos] = ival; pos++; } MetadataInfo mi = new MetadataInfo(mkey, keys, vals); metadataArray[i] = abc.getMetadataId(mi, true); } t.metadata = metadataArray; } } public static boolean parseSlotConst(ABC abc, Reader reader, AVM2ConstantPool constants, TraitSlotConst tsc) throws IOException, AVM2ParseException { Flasm3Lexer lexer = new Flasm3Lexer(reader); expected(ParsedSymbol.TYPE_KEYWORD_TRAIT, "trait", lexer); ParsedSymbol symb = lexer.lex(); if (symb.type == ParsedSymbol.TYPE_KEYWORD_SLOT) { tsc.kindType = Trait.TRAIT_SLOT; } else if (symb.type == ParsedSymbol.TYPE_KEYWORD_CONST) { tsc.kindType = Trait.TRAIT_CONST; } else { throw new AVM2ParseException("slot or const expected", lexer.yyline()); } int name_index = parseMultiName(constants, lexer); parseTraitParams(abc, lexer, tsc); expected(ParsedSymbol.TYPE_KEYWORD_SLOTID, "slotid", lexer); symb = lexer.lex(); expected(symb, ParsedSymbol.TYPE_INTEGER, "Integer"); int slotid = (int) (long) (Long) symb.value; expected(ParsedSymbol.TYPE_KEYWORD_TYPE, "type", lexer); int type = parseMultiName(constants, lexer); expected(ParsedSymbol.TYPE_KEYWORD_VALUE, "value", lexer); ValueKind val = parseValue(constants, lexer); tsc.slot_id = slotid; tsc.type_index = type; tsc.value_kind = val.value_kind; tsc.value_index = val.value_index; tsc.name_index = name_index; return true; } private static int parseNamespaceSet(AVM2ConstantPool constants, Flasm3Lexer lexer) throws AVM2ParseException, IOException { List<Integer> namespaceList = new ArrayList<>(); ParsedSymbol s = lexer.lex(); if (s.type == ParsedSymbol.TYPE_KEYWORD_NULL) { return 0; } expected(s, ParsedSymbol.TYPE_BRACKET_OPEN, "["); s = lexer.lex(); if (s.type != ParsedSymbol.TYPE_BRACKET_CLOSE) { lexer.pushback(s); do { namespaceList.add(parseNamespace(constants, lexer)); s = lexer.lex(); } while (s.type == ParsedSymbol.TYPE_COMMA); expected(s, ParsedSymbol.TYPE_BRACKET_CLOSE, "]"); } loopn: for (int n = 1; n < constants.getNamespaceSetCount(); n++) { int[] nss = constants.getNamespaceSet(n).namespaces; if (nss.length != namespaceList.size()) { continue; } for (int i = 0; i < nss.length; i++) { if (nss[i] != namespaceList.get(i)) { continue loopn; } } return n; } int[] nss = new int[namespaceList.size()]; for (int i = 0; i < nss.length; i++) { nss[i] = namespaceList.get(i); } return constants.addNamespaceSet(new NamespaceSet(nss)); } private static int parseNamespace(AVM2ConstantPool constants, Flasm3Lexer lexer) throws AVM2ParseException, IOException { ParsedSymbol type = lexer.lex(); int kind = 0; switch (type.type) { case ParsedSymbol.TYPE_KEYWORD_NULL: return 0; case ParsedSymbol.TYPE_KEYWORD_NAMESPACE: kind = Namespace.KIND_NAMESPACE; break; case ParsedSymbol.TYPE_KEYWORD_PRIVATENAMESPACE: kind = Namespace.KIND_PRIVATE; break; case ParsedSymbol.TYPE_KEYWORD_PACKAGENAMESPACE: kind = Namespace.KIND_PACKAGE; break; case ParsedSymbol.TYPE_KEYWORD_PACKAGEINTERNALNS: kind = Namespace.KIND_PACKAGE_INTERNAL; break; case ParsedSymbol.TYPE_KEYWORD_PROTECTEDNAMESPACE: kind = Namespace.KIND_PROTECTED; break; case ParsedSymbol.TYPE_KEYWORD_EXPLICITNAMESPACE: kind = Namespace.KIND_EXPLICIT; break; case ParsedSymbol.TYPE_KEYWORD_STATICPROTECTEDNS: kind = Namespace.KIND_STATIC_PROTECTED; break; default: throw new AVM2ParseException("Namespace kind expected", lexer.yyline()); } expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); ParsedSymbol name = lexer.lex(); if (name.type == ParsedSymbol.TYPE_KEYWORD_NULL) { } else if (name.type == ParsedSymbol.TYPE_STRING) { } else { throw new AVM2ParseException("String or null expected", lexer.yyline()); } ParsedSymbol c = lexer.lex(); int index = 0; if (c.type == ParsedSymbol.TYPE_COMMA) { ParsedSymbol extra = lexer.lex(); expected(extra, ParsedSymbol.TYPE_STRING, "String"); try { index = Integer.parseInt((String) extra.value); } catch (NumberFormatException nfe) { throw new AVM2ParseException("Number expected", lexer.yyline()); } } else { lexer.pushback(c); } expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); return constants.getNamespaceId(kind, name.type == ParsedSymbol.TYPE_KEYWORD_NULL ? null : (String) name.value, index, true); } private static int parseMultiName(AVM2ConstantPool constants, Flasm3Lexer lexer) throws AVM2ParseException, IOException { ParsedSymbol s = lexer.lex(); int kind = 0; switch (s.type) { case ParsedSymbol.TYPE_KEYWORD_NULL: return 0; case ParsedSymbol.TYPE_KEYWORD_QNAME: kind = Multiname.QNAME; break; case ParsedSymbol.TYPE_KEYWORD_QNAMEA: kind = Multiname.QNAMEA; break; case ParsedSymbol.TYPE_KEYWORD_RTQNAME: kind = Multiname.RTQNAME; break; case ParsedSymbol.TYPE_KEYWORD_RTQNAMEA: kind = Multiname.RTQNAMEA; break; case ParsedSymbol.TYPE_KEYWORD_RTQNAMEL: kind = Multiname.RTQNAMEL; break; case ParsedSymbol.TYPE_KEYWORD_RTQNAMELA: kind = Multiname.RTQNAMELA; break; case ParsedSymbol.TYPE_KEYWORD_MULTINAME: kind = Multiname.MULTINAME; break; case ParsedSymbol.TYPE_KEYWORD_MULTINAMEA: kind = Multiname.MULTINAMEA; break; case ParsedSymbol.TYPE_KEYWORD_MULTINAMEL: kind = Multiname.MULTINAMEL; break; case ParsedSymbol.TYPE_KEYWORD_MULTINAMELA: kind = Multiname.MULTINAMELA; break; case ParsedSymbol.TYPE_KEYWORD_TYPENAME: kind = Multiname.TYPENAME; break; default: throw new AVM2ParseException("Name expected", lexer.yyline()); } Multiname multiname = null; switch (kind) { case Multiname.QNAME: case Multiname.QNAMEA: { expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); int namespace_index = parseNamespace(constants, lexer); expected(ParsedSymbol.TYPE_COMMA, ",", lexer); ParsedSymbol name = lexer.lex(); int name_index; if (name.type == ParsedSymbol.TYPE_KEYWORD_NULL) { name_index = 0; } else { expected(name, ParsedSymbol.TYPE_STRING, "String"); name_index = constants.getStringId((String) name.value, true); } expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); multiname = Multiname.createQName(kind == Multiname.QNAMEA, name_index, namespace_index); break; } case Multiname.RTQNAME: case Multiname.RTQNAMEA: { expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); ParsedSymbol rtqName = lexer.lex(); int name_index; if (rtqName.type == ParsedSymbol.TYPE_KEYWORD_NULL) { name_index = 0; } else { expected(rtqName, ParsedSymbol.TYPE_STRING, "String"); name_index = constants.getStringId((String) rtqName.value, true); } expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); multiname = Multiname.createRTQName(kind == Multiname.RTQNAMEA, name_index); break; } case Multiname.RTQNAMEL: case Multiname.RTQNAMELA: { expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); multiname = Multiname.createRTQNameL(kind == Multiname.RTQNAMELA); break; } case Multiname.MULTINAME: case Multiname.MULTINAMEA: { expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); ParsedSymbol mName = lexer.lex(); int name_index; if (mName.type == ParsedSymbol.TYPE_KEYWORD_NULL) { name_index = 0; } else { expected(mName, ParsedSymbol.TYPE_STRING, "String"); name_index = constants.getStringId((String) mName.value, true); } expected(ParsedSymbol.TYPE_COMMA, ",", lexer); int namespace_set_index = parseNamespaceSet(constants, lexer); expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); multiname = Multiname.createMultiname(kind == Multiname.MULTINAMEA, name_index, namespace_set_index); break; } case Multiname.MULTINAMEL: case Multiname.MULTINAMELA: { expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); int namespace_set_index = parseNamespaceSet(constants, lexer); expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); multiname = Multiname.createMultinameL(kind == Multiname.MULTINAMELA, namespace_set_index); break; } case Multiname.TYPENAME: { expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); int qname_index = parseMultiName(constants, lexer); expected(ParsedSymbol.TYPE_LOWERTHAN, "<", lexer); List<Integer> paramsList = new ArrayList<>(); paramsList.add(parseMultiName(constants, lexer)); ParsedSymbol nt = lexer.lex(); while (nt.type == ParsedSymbol.TYPE_COMMA) { paramsList.add(parseMultiName(constants, lexer)); nt = lexer.lex(); } int[] params = Helper.toIntArray(paramsList); expected(nt, ParsedSymbol.TYPE_GREATERTHAN, ">"); expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); multiname = Multiname.createTypeName(qname_index, params); break; } } return constants.getMultinameId(multiname, true); } public static ValueKind parseValue(AVM2ConstantPool constants, Flasm3Lexer lexer) throws IOException, AVM2ParseException { ParsedSymbol type = lexer.lex(); ParsedSymbol value; int value_index = 0; int value_kind = 0; switch (type.type) { case ParsedSymbol.TYPE_KEYWORD_INTEGER: value_kind = ValueKind.CONSTANT_Int; expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); value = lexer.lex(); if (value.type == ParsedSymbol.TYPE_KEYWORD_NULL) { value_index = 0; } else { expected(value, ParsedSymbol.TYPE_INTEGER, "Integer or null"); value_index = constants.getIntId((Long) value.value, true); } expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); break; case ParsedSymbol.TYPE_KEYWORD_UINTEGER: value_kind = ValueKind.CONSTANT_UInt; expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); value = lexer.lex(); if (value.type == ParsedSymbol.TYPE_KEYWORD_NULL) { value_index = 0; } else { expected(value, ParsedSymbol.TYPE_INTEGER, "UInteger"); value_index = constants.getUIntId((Long) value.value, true); } expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); break; case ParsedSymbol.TYPE_KEYWORD_DOUBLE: value_kind = ValueKind.CONSTANT_Double; expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); value = lexer.lex(); if (value.type == ParsedSymbol.TYPE_KEYWORD_NULL) { value_index = 0; } else { expected(value, ParsedSymbol.TYPE_FLOAT, "Double or null"); value_index = constants.getDoubleId((Double) value.value, true); } expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); break; /*case ParsedSymbol.TYPE_KEYWORD_DECIMAL: value_kind = ValueKind.CONSTANT_Decimal; break;*/ case ParsedSymbol.TYPE_INTEGER: value_kind = ValueKind.CONSTANT_Int; value_index = constants.getIntId((Long) type.value, true); break; case ParsedSymbol.TYPE_FLOAT: value_kind = ValueKind.CONSTANT_Double; value_index = constants.getDoubleId((Double) type.value, true); break; case ParsedSymbol.TYPE_STRING: value_kind = ValueKind.CONSTANT_Utf8; value_index = constants.getStringId((String) type.value, true); break; case ParsedSymbol.TYPE_KEYWORD_UTF8: value_kind = ValueKind.CONSTANT_Utf8; expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer); value = lexer.lex(); if (value.type == ParsedSymbol.TYPE_KEYWORD_NULL) { value_index = 0; } else { expected(value, ParsedSymbol.TYPE_STRING, "String or null"); expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer); value_index = constants.getStringId((String) value.value, true); } break; case ParsedSymbol.TYPE_KEYWORD_TRUE: value_kind = ValueKind.CONSTANT_True; break; case ParsedSymbol.TYPE_KEYWORD_FALSE: value_kind = ValueKind.CONSTANT_False; break; case ParsedSymbol.TYPE_KEYWORD_NULL: value_kind = ValueKind.CONSTANT_Null; break; case ParsedSymbol.TYPE_KEYWORD_NAMESPACE: case ParsedSymbol.TYPE_KEYWORD_PACKAGEINTERNALNS: case ParsedSymbol.TYPE_KEYWORD_PROTECTEDNAMESPACE: case ParsedSymbol.TYPE_KEYWORD_EXPLICITNAMESPACE: case ParsedSymbol.TYPE_KEYWORD_STATICPROTECTEDNS: case ParsedSymbol.TYPE_KEYWORD_PRIVATENAMESPACE: case ParsedSymbol.TYPE_KEYWORD_PACKAGENAMESPACE: switch (type.type) { case ParsedSymbol.TYPE_KEYWORD_NAMESPACE: value_kind = ValueKind.CONSTANT_Namespace; break; case ParsedSymbol.TYPE_KEYWORD_PACKAGEINTERNALNS: value_kind = ValueKind.CONSTANT_PackageInternalNs; break; case ParsedSymbol.TYPE_KEYWORD_PROTECTEDNAMESPACE: value_kind = ValueKind.CONSTANT_ProtectedNamespace; break; case ParsedSymbol.TYPE_KEYWORD_EXPLICITNAMESPACE: value_kind = ValueKind.CONSTANT_ExplicitNamespace; break; case ParsedSymbol.TYPE_KEYWORD_STATICPROTECTEDNS: value_kind = ValueKind.CONSTANT_StaticProtectedNs; break; case ParsedSymbol.TYPE_KEYWORD_PRIVATENAMESPACE: value_kind = ValueKind.CONSTANT_PrivateNs; break; case ParsedSymbol.TYPE_KEYWORD_PACKAGENAMESPACE: value_kind = ValueKind.CONSTANT_PackageNamespace; break; } lexer.pushback(type); value_index = parseNamespace(constants, lexer); break; default: if (Configuration._debugMode.get()) { throw new AVM2ParseException("Not supported valueType.", lexer.yyline()); } } return new ValueKind(value_index, value_kind); } 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(); int openedBlocks = 0; boolean autoCloseBlocks = true; //TODO? Put to false. But how about old imports? List<OffsetItem> offsetItems = new ArrayList<>(); List<LabelItem> labelItems = new ArrayList<>(); List<ABCException> exceptions = new ArrayList<>(); List<Integer> exceptionIndices = new ArrayList<>(); int offset = 0; Flasm3Lexer lexer = new Flasm3Lexer(reader); ParsedSymbol symb; AVM2Instruction lastIns = null; List<String> exceptionsFrom = new ArrayList<>(); List<String> exceptionsTo = new ArrayList<>(); List<String> exceptionsTargets = new ArrayList<>(); info.flags = 0; info.name_index = 0; List<Integer> paramTypes = new ArrayList<>(); List<Integer> paramNames = new ArrayList<>(); List<ValueKind> optional = new ArrayList<>(); do { symb = lexer.lex(); if (Arrays.asList(ParsedSymbol.TYPE_KEYWORD_BODY, ParsedSymbol.TYPE_KEYWORD_CODE, ParsedSymbol.TYPE_KEYWORD_METHOD).contains(symb.type)) { openedBlocks++; continue; } if (symb.type == ParsedSymbol.TYPE_KEYWORD_TRAIT) { openedBlocks++; 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"); 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; } continue; } if (symb.type == ParsedSymbol.TYPE_KEYWORD_NAME) { symb = lexer.lex(); if (symb.type == ParsedSymbol.TYPE_KEYWORD_NULL) { info.name_index = 0; } else { expected(symb, ParsedSymbol.TYPE_STRING, "String or null"); info.name_index = constants.getStringId((String) symb.value, true); } continue; } if (symb.type == ParsedSymbol.TYPE_KEYWORD_PARAM) { paramTypes.add(parseMultiName(constants, lexer)); continue; } if (symb.type == ParsedSymbol.TYPE_KEYWORD_PARAMNAME) { symb = lexer.lex(); if (symb.type == ParsedSymbol.TYPE_KEYWORD_NULL) { paramNames.add(0); } else { expected(symb, ParsedSymbol.TYPE_STRING, "String or null"); paramNames.add(constants.getStringId((String) symb.value, true)); } continue; } if (symb.type == ParsedSymbol.TYPE_KEYWORD_OPTIONAL) { optional.add(parseValue(constants, lexer)); continue; } if (symb.type == ParsedSymbol.TYPE_KEYWORD_MAXSTACK) { symb = lexer.lex(); expected(symb, ParsedSymbol.TYPE_INTEGER, "Integer"); body.max_stack = (int) (long) (Long) symb.value; continue; } if (symb.type == ParsedSymbol.TYPE_KEYWORD_LOCALCOUNT) { symb = lexer.lex(); expected(symb, ParsedSymbol.TYPE_INTEGER, "Integer"); body.max_regs = (int) (long) (Long) symb.value; continue; } if (symb.type == ParsedSymbol.TYPE_KEYWORD_INITSCOPEDEPTH) { symb = lexer.lex(); expected(symb, ParsedSymbol.TYPE_INTEGER, "Integer"); body.init_scope_depth = (int) (long) (Long) symb.value; continue; } if (symb.type == ParsedSymbol.TYPE_KEYWORD_MAXSCOPEDEPTH) { symb = lexer.lex(); expected(symb, ParsedSymbol.TYPE_INTEGER, "Integer"); body.max_scope_depth = (int) (long) (Long) symb.value; continue; } if (symb.type == ParsedSymbol.TYPE_KEYWORD_RETURNS) { info.ret_type = parseMultiName(constants, lexer); continue; } if (symb.type == ParsedSymbol.TYPE_KEYWORD_FLAG) { symb = lexer.lex(); switch (symb.type) { case ParsedSymbol.TYPE_KEYWORD_EXPLICIT: info.setFlagExplicit(); break; case ParsedSymbol.TYPE_KEYWORD_HAS_OPTIONAL: info.setFlagHas_optional(); break; case ParsedSymbol.TYPE_KEYWORD_HAS_PARAM_NAMES: info.setFlagHas_paramnames(); break; case ParsedSymbol.TYPE_KEYWORD_IGNORE_REST: info.setFlagIgnore_Rest(); break; case ParsedSymbol.TYPE_KEYWORD_NEED_ACTIVATION: info.setFlagNeed_activation(); break; case ParsedSymbol.TYPE_KEYWORD_NEED_ARGUMENTS: info.setFlagNeed_Arguments(); break; case ParsedSymbol.TYPE_KEYWORD_NEED_REST: info.setFlagNeed_rest(); break; case ParsedSymbol.TYPE_KEYWORD_SET_DXNS: info.setFlagSetsdxns(); break; } continue; } if (symb.type == ParsedSymbol.TYPE_KEYWORD_TRY) { expected(ParsedSymbol.TYPE_KEYWORD_FROM, "From", lexer); symb = lexer.lex(); expected(symb, ParsedSymbol.TYPE_IDENTIFIER, "Identifier"); exceptionsFrom.add((String) symb.value); expected(ParsedSymbol.TYPE_KEYWORD_TO, "To", lexer); symb = lexer.lex(); expected(symb, ParsedSymbol.TYPE_IDENTIFIER, "Identifier"); exceptionsTo.add((String) symb.value); expected(ParsedSymbol.TYPE_KEYWORD_TARGET, "Target", lexer); symb = lexer.lex(); expected(symb, ParsedSymbol.TYPE_IDENTIFIER, "Identifier"); exceptionsTargets.add((String) symb.value); expected(ParsedSymbol.TYPE_KEYWORD_TYPE, "Type", lexer); ABCException ex = new ABCException(); ex.type_index = parseMultiName(constants, lexer); expected(ParsedSymbol.TYPE_KEYWORD_NAME, "Name", lexer); ex.name_index = parseMultiName(constants, lexer); exceptions.add(ex); continue; } if (symb.type == ParsedSymbol.TYPE_EXCEPTION_START) { int exIndex = (Integer) symb.value; int listIndex = exceptionIndices.indexOf(exIndex); if (listIndex == -1) { throw new AVM2ParseException("Undefinex exception index", lexer.yyline()); } exceptions.get(listIndex).start = offset; continue; } if (symb.type == ParsedSymbol.TYPE_EXCEPTION_END) { int exIndex = (Integer) symb.value; int listIndex = exceptionIndices.indexOf(exIndex); if (listIndex == -1) { throw new AVM2ParseException("Undefinex exception index", lexer.yyline()); } exceptions.get(listIndex).end = offset; continue; } if (symb.type == ParsedSymbol.TYPE_EXCEPTION_TARGET) { int exIndex = (Integer) symb.value; int listIndex = exceptionIndices.indexOf(exIndex); if (listIndex == -1) { throw new AVM2ParseException("Undefinex exception index", lexer.yyline()); } exceptions.get(listIndex).target = offset; continue; } if (symb.type == ParsedSymbol.TYPE_EOF) { break; } if (symb.type == ParsedSymbol.TYPE_COMMENT) { if (lastIns != null) { lastIns.comment = (String) symb.value; } continue; } if (symb.type == ParsedSymbol.TYPE_KEYWORD_END) { if (openedBlocks > 0) { openedBlocks--; } else { throw new AVM2ParseException("End block encountered but there is no block opened", lexer.yyline()); } continue; } if (symb.type == ParsedSymbol.TYPE_INSTRUCTION_NAME) { if (((String) symb.value).toLowerCase(Locale.ENGLISH).equals("exception")) { ParsedSymbol exIndex = lexer.lex(); if (exIndex.type != ParsedSymbol.TYPE_INTEGER) { throw new AVM2ParseException("Index expected", lexer.yyline()); } ParsedSymbol exName = lexer.lex(); if (exName.type != ParsedSymbol.TYPE_MULTINAME) { throw new AVM2ParseException("Multiname expected", lexer.yyline()); } ParsedSymbol exType = lexer.lex(); if (exType.type != ParsedSymbol.TYPE_MULTINAME) { throw new AVM2ParseException("Multiname expected", lexer.yyline()); } ABCException ex = new ABCException(); ex.name_index = checkMultinameIndex(constants, (int) (long) (Long) exName.value, lexer.yyline()); ex.type_index = checkMultinameIndex(constants, (int) (long) (Long) exType.value, lexer.yyline()); exceptions.add(ex); exceptionIndices.add((int) (long) (Long) exIndex.value); continue; } boolean insFound = false; for (InstructionDefinition def : AVM2Code.instructionSet) { if (def != null && !(def instanceof UnknownInstruction) && def.instructionName.equals((String) symb.value)) { insFound = true; List<Integer> operandsList = new ArrayList<>(); for (int i = 0; i < def.operands.length; i++) { ParsedSymbol parsedOperand = lexer.lex(); switch (def.operands[i]) { case AVM2Code.DAT_MULTINAME_INDEX: lexer.pushback(parsedOperand); operandsList.add(parseMultiName(constants, lexer)); break; case AVM2Code.DAT_NAMESPACE_INDEX: lexer.pushback(parsedOperand); operandsList.add(parseNamespace(constants, lexer)); break; case AVM2Code.DAT_STRING_INDEX: if (parsedOperand.type == ParsedSymbol.TYPE_KEYWORD_NULL) { operandsList.add(0); } else if (parsedOperand.type == ParsedSymbol.TYPE_STRING) { int sid = constants.getStringId((String) parsedOperand.value, false); if (sid == -1) { if ((missingHandler != null) && (missingHandler.missingString((String) parsedOperand.value))) { sid = constants.addString((String) parsedOperand.value); } else { throw new AVM2ParseException("Unknown String", lexer.yyline()); } } operandsList.add(sid); } else { throw new AVM2ParseException("String or null expected", lexer.yyline()); } break; case AVM2Code.DAT_INT_INDEX: if (parsedOperand.type == ParsedSymbol.TYPE_KEYWORD_NULL) { operandsList.add(0); } else if (parsedOperand.type == ParsedSymbol.TYPE_INTEGER) { long intVal = (Long) parsedOperand.value; int iid = constants.getIntId(intVal, false); if (iid == -1) { if ((missingHandler != null) && (missingHandler.missingInt(intVal))) { iid = constants.addInt(intVal); } else { throw new AVM2ParseException("Unknown int", lexer.yyline()); } } operandsList.add(iid); } else { throw new AVM2ParseException("Integer or null expected", lexer.yyline()); } break; case AVM2Code.DAT_UINT_INDEX: if (parsedOperand.type == ParsedSymbol.TYPE_KEYWORD_NULL) { operandsList.add(0); } else if (parsedOperand.type == ParsedSymbol.TYPE_INTEGER) { long intVal = (Long) parsedOperand.value; int iid = constants.getUIntId(intVal, false); if (iid == -1) { if ((missingHandler != null) && (missingHandler.missingUInt(intVal))) { iid = constants.addUInt(intVal); } else { throw new AVM2ParseException("Unknown uint", lexer.yyline()); } } operandsList.add(iid); } else { throw new AVM2ParseException("Integer or null expected", lexer.yyline()); } break; case AVM2Code.DAT_DOUBLE_INDEX: if (parsedOperand.type == ParsedSymbol.TYPE_KEYWORD_NULL) { operandsList.add(0); } else if ((parsedOperand.type == ParsedSymbol.TYPE_INTEGER) || (parsedOperand.type == ParsedSymbol.TYPE_FLOAT)) { double doubleVal = 0; if (parsedOperand.type == ParsedSymbol.TYPE_INTEGER) { doubleVal = (Long) parsedOperand.value; } if (parsedOperand.type == ParsedSymbol.TYPE_FLOAT) { doubleVal = (Double) parsedOperand.value; } int did = constants.getDoubleId(doubleVal, false); if (did == -1) { if ((missingHandler != null) && (missingHandler.missingDouble(doubleVal))) { did = constants.addDouble(doubleVal); } else { throw new AVM2ParseException("Unknown double", lexer.yyline()); } } operandsList.add(did); } else { throw new AVM2ParseException("Double or null expected", lexer.yyline()); } break; case AVM2Code.DAT_FLOAT_INDEX: if (parsedOperand.type == ParsedSymbol.TYPE_KEYWORD_NULL) { operandsList.add(0); } else if ((parsedOperand.type == ParsedSymbol.TYPE_INTEGER) || (parsedOperand.type == ParsedSymbol.TYPE_FLOAT)) { float floatVal = 0; if (parsedOperand.type == ParsedSymbol.TYPE_INTEGER) { floatVal = (Long) parsedOperand.value; } if (parsedOperand.type == ParsedSymbol.TYPE_FLOAT) { floatVal = (float) (double) (Double) parsedOperand.value; } int fid = constants.getFloatId(floatVal, false); if (fid == -1) { if ((missingHandler != null) && (missingHandler.missingFloat(floatVal))) { fid = constants.addFloat(floatVal); } else { throw new AVM2ParseException("Unknown float", lexer.yyline()); } } operandsList.add(fid); } else { throw new AVM2ParseException("Float or null expected", lexer.yyline()); } break; case AVM2Code.DAT_FLOAT4_INDEX: if (parsedOperand.type == ParsedSymbol.TYPE_KEYWORD_NULL) { operandsList.add(0); } else { float[] float4Vals = new float[4]; for (int k = 0; k < 4; k++) { if ((parsedOperand.type == ParsedSymbol.TYPE_INTEGER) || (parsedOperand.type == ParsedSymbol.TYPE_FLOAT)) { float floatVal = 0; if (parsedOperand.type == ParsedSymbol.TYPE_INTEGER) { floatVal = (Long) parsedOperand.value; } if (parsedOperand.type == ParsedSymbol.TYPE_FLOAT) { floatVal = (float) (double) (Double) parsedOperand.value; } float4Vals[k] = floatVal; } else { throw new AVM2ParseException("4 floats or null expected", lexer.yyline()); } if (k + 1 < 4) { //not last one parsedOperand = lexer.lex(); } } Float4 float4Val = new Float4(float4Vals); int f4id = constants.getFloat4Id(float4Val, false); if (f4id == -1) { if ((missingHandler != null) && (missingHandler.missingFloat4(float4Val))) { f4id = constants.addFloat4(float4Val); } else { throw new AVM2ParseException("Unknown float4", lexer.yyline()); } } operandsList.add(f4id); } break; case AVM2Code.DAT_OFFSET: if (parsedOperand.type == ParsedSymbol.TYPE_IDENTIFIER) { offsetItems.add(new OffsetItem((String) parsedOperand.value, code.code.size(), i)); operandsList.add(0); } else { throw new AVM2ParseException("Offset expected", lexer.yyline()); } break; case AVM2Code.DAT_CASE_BASEOFFSET: if (parsedOperand.type == ParsedSymbol.TYPE_IDENTIFIER) { offsetItems.add(new CaseOffsetItem((String) parsedOperand.value, code.code.size(), i)); operandsList.add(0); } else { throw new AVM2ParseException("Offset expected", lexer.yyline()); } break; case AVM2Code.OPT_CASE_OFFSETS: if (parsedOperand.type == ParsedSymbol.TYPE_INTEGER) { int patCount = (int) (long) (Long) parsedOperand.value; operandsList.add(patCount); for (int c = 0; c <= patCount; c++) { parsedOperand = lexer.lex(); if (parsedOperand.type == ParsedSymbol.TYPE_IDENTIFIER) { offsetItems.add(new CaseOffsetItem((String) parsedOperand.value, code.code.size(), i + (c + 1))); operandsList.add(0); } else { throw new AVM2ParseException("Offset expected", lexer.yyline()); } } } else { throw new AVM2ParseException("Case count expected", lexer.yyline()); } break; case AVM2Code.OPT_S8: if (parsedOperand.type == ParsedSymbol.TYPE_INTEGER) { long val = (long) (Long) parsedOperand.value; if (val < Byte.MIN_VALUE || val > Byte.MAX_VALUE) { throw new AVM2ParseException("Byte value expected (" + Byte.MIN_VALUE + " to " + Byte.MAX_VALUE + "). Use pushshort or pushint to push larger values", lexer.yyline()); } operandsList.add((int) val); } else { throw new AVM2ParseException("Integer expected", lexer.yyline()); } break; default: if (parsedOperand.type == ParsedSymbol.TYPE_INTEGER) { long val = (long) (Long) parsedOperand.value; if (def instanceof PushShortIns) { if (val < Short.MIN_VALUE || val > Short.MAX_VALUE) { throw new AVM2ParseException("Short value expected (" + Short.MIN_VALUE + " to " + Short.MAX_VALUE + "). Use pushint to push larger values", lexer.yyline()); } } operandsList.add((int) val); } else { throw new AVM2ParseException("Integer expected", lexer.yyline()); } } } int[] operands = new int[operandsList.size()]; for (int i = 0; i < operandsList.size(); i++) { operands[i] = operandsList.get(i); } lastIns = new AVM2Instruction(offset, def, operands); code.code.add(lastIns); offset += lastIns.getBytesLength(); break; } } if (symb.value.toString().toLowerCase().equals("ffdec_deobfuscatepop")) { lastIns = new AVM2Instruction(offset, DeobfuscatePopIns.getInstance(), null); code.code.add(lastIns); offset += lastIns.getBytesLength(); insFound = true; } if (!insFound) { throw new AVM2ParseException("Invalid instruction name:" + (String) symb.value, lexer.yyline()); } } else if (symb.type == ParsedSymbol.TYPE_LABEL) { labelItems.add(new LabelItem((String) symb.value, offset)); } else { throw new AVM2ParseException("Unexpected symbol", lexer.yyline()); } } while (symb.type != ParsedSymbol.TYPE_EOF); if (!autoCloseBlocks && openedBlocks > 0) { throw new AVM2ParseException("End of the block expected: " + openedBlocks + "x", lexer.yyline()); } code.compact(); for (LabelItem li : labelItems) { int ind; ind = exceptionsFrom.indexOf(li.label); if (ind > -1) { exceptions.get(ind).start = li.offset; } ind = exceptionsTo.indexOf(li.label); if (ind > -1) { exceptions.get(ind).end = li.offset; } ind = exceptionsTargets.indexOf(li.label); if (ind > -1) { exceptions.get(ind).target = li.offset; } } for (OffsetItem oi : offsetItems) { for (LabelItem li : labelItems) { if (Thread.currentThread().isInterrupted()) { throw new InterruptedException(); } if (oi.label.equals(li.label)) { AVM2Instruction ins = code.code.get((int) oi.insPosition); int relOffset; if (oi instanceof CaseOffsetItem) { relOffset = li.offset - (int) ins.getAddress(); } else { relOffset = li.offset - ((int) ins.getAddress() + ins.getBytesLength()); } ins.operands[oi.insOperandIndex] = relOffset; } } } body.exceptions = new ABCException[exceptions.size()]; for (int e = 0; e < exceptions.size(); e++) { body.exceptions[e] = exceptions.get(e); } info.param_types = new int[paramTypes.size()]; for (int i = 0; i < paramTypes.size(); i++) { info.param_types[i] = paramTypes.get(i); } if (info.flagHas_paramnames()) { info.paramNames = new int[paramNames.size()]; for (int i = 0; i < paramNames.size(); i++) { info.paramNames[i] = paramNames.get(i); } } if (info.flagHas_optional()) { info.optional = new ValueKind[optional.size()]; for (int i = 0; i < optional.size(); i++) { info.optional[i] = optional.get(i); } } abc.refreshMultinameNamespaceSuffixes(); return code; } }