/* * 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.methodinfo_parser; import com.jpexs.decompiler.flash.abc.ABC; import com.jpexs.decompiler.flash.abc.types.MethodInfo; import com.jpexs.decompiler.flash.abc.types.ValueKind; import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst; import com.jpexs.decompiler.flash.configuration.Configuration; import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * * @author JPEXS */ public class MethodInfoParser { public static boolean parseSlotConst(String text, TraitSlotConst trait, ABC abc) throws MethodInfoParseException { MethodInfoLexer lexer = new MethodInfoLexer(new java.io.InputStreamReader(new ByteArrayInputStream(text.getBytes()))); ParsedSymbol symb; int type_index = -1; ValueKind value = new ValueKind(0, 0); try { ParsedSymbol symbType = lexer.yylex(); if (symbType.type == ParsedSymbol.TYPE_STAR) { type_index = 0; } else if (symbType.type == ParsedSymbol.TYPE_MULTINAME) { type_index = (int) (long) (Long) symbType.value; } else { throw new MethodInfoParseException("Multiname or * expected", lexer.yyline()); } ParsedSymbol symbEqual = lexer.yylex(); if (symbEqual.type == ParsedSymbol.TYPE_ASSIGN) { ParsedSymbol symbValue; String nstype = ""; do { symbValue = lexer.yylex(); if (symbValue.type >= 8 && symbValue.type <= 13) { nstype = nstype + symbValue.type + ":"; } } while (symbValue.type >= 8 && symbValue.type <= 13); if ((!nstype.isEmpty()) && (symbValue.type != ParsedSymbol.TYPE_NAMESPACE)) { throw new MethodInfoParseException("Namespace expected", lexer.yyline()); } int id = 0; switch (symbValue.type) { case ParsedSymbol.TYPE_INTEGER: value = new ValueKind(abc.constants.getIntId((Long) symbValue.value, true), ValueKind.CONSTANT_Int); break; case ParsedSymbol.TYPE_FLOAT: value = new ValueKind(abc.constants.getDoubleId((Double) symbValue.value, true), ValueKind.CONSTANT_Double); break; case ParsedSymbol.TYPE_STRING: value = new ValueKind(abc.constants.getStringId((String) symbValue.value, true), ValueKind.CONSTANT_Utf8); break; case ParsedSymbol.TYPE_TRUE: value = new ValueKind(0, ValueKind.CONSTANT_True); break; case ParsedSymbol.TYPE_FALSE: value = new ValueKind(0, ValueKind.CONSTANT_False); break; case ParsedSymbol.TYPE_NULL: value = new ValueKind(0, ValueKind.CONSTANT_Null); break; case ParsedSymbol.TYPE_UNDEFINED: value = new ValueKind(0, ValueKind.CONSTANT_Undefined); break; case ParsedSymbol.TYPE_NAMESPACE: if (nstype.equals("9:")) { value = new ValueKind((int) (long) (Long) symbValue.value, ValueKind.CONSTANT_PackageNamespace); } else if (nstype.equals("9:10:")) { value = new ValueKind((int) (long) (Long) symbValue.value, ValueKind.CONSTANT_PackageInternalNs); } else if (nstype.equals("13:")) { value = new ValueKind((int) (long) (Long) symbValue.value, ValueKind.CONSTANT_ProtectedNamespace); } else if (nstype.equals("12:")) { value = new ValueKind((int) (long) (Long) symbValue.value, ValueKind.CONSTANT_ExplicitNamespace); } else if (nstype.equals("11:13:")) { value = new ValueKind((int) (long) (Long) symbValue.value, ValueKind.CONSTANT_StaticProtectedNs); } else if (nstype.equals("8:")) { value = new ValueKind((int) (long) (Long) symbValue.value, ValueKind.CONSTANT_PrivateNs); } else if (nstype.isEmpty()) { value = new ValueKind((int) (long) (Long) symbValue.value, ValueKind.CONSTANT_Namespace); } else { throw new MethodInfoParseException("Invalid type of namespace", lexer.yyline()); } break; default: throw new MethodInfoParseException("Unexpected symbol", lexer.yyline()); } symb = lexer.yylex(); if (symb.type != ParsedSymbol.TYPE_EOF) { throw new MethodInfoParseException("Unexpected symbol", lexer.yyline()); } } else if (symbEqual.type == ParsedSymbol.TYPE_EOF) { } else { throw new MethodInfoParseException("Unexpected symbol", lexer.yyline()); } } catch (IOException ex) { return false; } trait.type_index = type_index; trait.value_kind = value.value_kind; trait.value_index = value.value_index; return true; } public static boolean parseReturnType(String text, MethodInfo update) throws MethodInfoParseException { MethodInfoLexer lexer = new MethodInfoLexer(new java.io.InputStreamReader(new ByteArrayInputStream(text.getBytes()))); ParsedSymbol symb; int type = -1; try { symb = lexer.yylex(); if (symb.type == ParsedSymbol.TYPE_STAR) { type = 0; } else if (symb.type == ParsedSymbol.TYPE_MULTINAME) { type = (int) (long) (Long) symb.value; } else { throw new MethodInfoParseException("Multiname or * expected", lexer.yyline()); } symb = lexer.yylex(); if (symb.type != ParsedSymbol.TYPE_EOF) { throw new MethodInfoParseException("Only one return type allowed", lexer.yyline()); } update.ret_type = type; return true; } catch (IOException ex) { } return false; } public static boolean parseParams(String text, MethodInfo update, ABC abc) throws MethodInfoParseException { MethodInfoLexer lexer = new MethodInfoLexer(new java.io.InputStreamReader(new ByteArrayInputStream(text.getBytes()))); List<String> paramNames = new ArrayList<>(); List<Long> paramTypes = new ArrayList<>(); List<ValueKind> optionalValues = new ArrayList<>(); boolean hasOptional = false; boolean needsRest = false; try { ParsedSymbol symb; symb = lexer.yylex(); while (symb.type != ParsedSymbol.TYPE_EOF) { if (symb.type == ParsedSymbol.TYPE_DOTS) { needsRest = true; symb = lexer.yylex(); if (symb.type != ParsedSymbol.TYPE_IDENTIFIER) { throw new MethodInfoParseException("Identifier expected", lexer.yyline()); } symb = lexer.yylex(); if (symb.type != ParsedSymbol.TYPE_EOF) { throw new MethodInfoParseException("End expected after rest params", lexer.yyline()); } break; } if (symb.type != ParsedSymbol.TYPE_IDENTIFIER) { throw new MethodInfoParseException("Identifier expected", lexer.yyline()); } paramNames.add((String) symb.value); symb = lexer.yylex(); if (symb.type == ParsedSymbol.TYPE_COLON) { ParsedSymbol symbType = lexer.yylex(); if (symbType.type == ParsedSymbol.TYPE_STAR) { paramTypes.add(new Long(0)); } else if (symbType.type == ParsedSymbol.TYPE_MULTINAME) { paramTypes.add((Long) symbType.value); } else { throw new MethodInfoParseException("Multiname or * expected", lexer.yyline()); } ParsedSymbol symbEqual = lexer.yylex(); if (symbEqual.type == ParsedSymbol.TYPE_ASSIGN) { hasOptional = true; ParsedSymbol symbValue; String nstype = ""; do { symbValue = lexer.yylex(); if (symbValue.type >= 8 && symbValue.type <= 13) { nstype = nstype + symbValue.type + ":"; } } while (symbValue.type >= 8 && symbValue.type <= 13); if ((!nstype.isEmpty()) && (symbValue.type != ParsedSymbol.TYPE_NAMESPACE)) { throw new MethodInfoParseException("Namespace expected", lexer.yyline()); } int id = 0; switch (symbValue.type) { case ParsedSymbol.TYPE_INTEGER: optionalValues.add(new ValueKind(abc.constants.getIntId((Long) symbValue.value, true), ValueKind.CONSTANT_Int)); break; case ParsedSymbol.TYPE_FLOAT: optionalValues.add(new ValueKind(abc.constants.getDoubleId((Double) symbValue.value, true), ValueKind.CONSTANT_Double)); break; case ParsedSymbol.TYPE_STRING: optionalValues.add(new ValueKind(abc.constants.getStringId((String) symbValue.value, true), ValueKind.CONSTANT_Utf8)); break; case ParsedSymbol.TYPE_TRUE: optionalValues.add(new ValueKind(0, ValueKind.CONSTANT_True)); break; case ParsedSymbol.TYPE_FALSE: optionalValues.add(new ValueKind(0, ValueKind.CONSTANT_False)); break; case ParsedSymbol.TYPE_NULL: optionalValues.add(new ValueKind(0, ValueKind.CONSTANT_Null)); break; case ParsedSymbol.TYPE_UNDEFINED: optionalValues.add(new ValueKind(0, ValueKind.CONSTANT_Undefined)); break; case ParsedSymbol.TYPE_NAMESPACE: if (nstype.equals("9:")) { optionalValues.add(new ValueKind((int) (long) (Long) symbValue.value, ValueKind.CONSTANT_PackageNamespace)); } else if (nstype.equals("9:10:")) { optionalValues.add(new ValueKind((int) (long) (Long) symbValue.value, ValueKind.CONSTANT_PackageInternalNs)); } else if (nstype.equals("13:")) { optionalValues.add(new ValueKind((int) (long) (Long) symbValue.value, ValueKind.CONSTANT_ProtectedNamespace)); } else if (nstype.equals("12:")) { optionalValues.add(new ValueKind((int) (long) (Long) symbValue.value, ValueKind.CONSTANT_ExplicitNamespace)); } else if (nstype.equals("11:13:")) { optionalValues.add(new ValueKind((int) (long) (Long) symbValue.value, ValueKind.CONSTANT_StaticProtectedNs)); } else if (nstype.equals("8:")) { optionalValues.add(new ValueKind((int) (long) (Long) symbValue.value, ValueKind.CONSTANT_PrivateNs)); } else if (nstype.isEmpty()) { optionalValues.add(new ValueKind((int) (long) (Long) symbValue.value, ValueKind.CONSTANT_Namespace)); } else { throw new MethodInfoParseException("Invalid type of namespace", lexer.yyline()); } break; default: throw new MethodInfoParseException("Unexpected symbol", lexer.yyline()); } symb = lexer.yylex(); if (symb.type == ParsedSymbol.TYPE_COMMA) { } else if (symb.type == ParsedSymbol.TYPE_EOF) { break; } } else if (symbEqual.type == ParsedSymbol.TYPE_COMMA) { if (hasOptional) { throw new MethodInfoParseException("Parameter must have default value", lexer.yyline()); } } else if (symbEqual.type == ParsedSymbol.TYPE_EOF) { if (hasOptional) { throw new MethodInfoParseException("Parameter must have default value", lexer.yyline()); } break; } else { throw new MethodInfoParseException("Unexpected symbol", lexer.yyline()); } } else if (symb.type == ParsedSymbol.TYPE_COMMA) { } else if (symb.type == ParsedSymbol.TYPE_EOF) { break; } else { throw new MethodInfoParseException("Unexpected symbol", lexer.yyline()); } symb = lexer.yylex(); } } catch (IOException iex) { return false; } if (needsRest && (!optionalValues.isEmpty())) { throw new MethodInfoParseException("Rest parameter canot be combined with default values", lexer.yyline()); } update.param_types = new int[paramTypes.size()]; for (int p = 0; p < paramTypes.size(); p++) { update.param_types[p] = (int) (long) paramTypes.get(p); } update.optional = (ValueKind[]) optionalValues.toArray(new ValueKind[optionalValues.size()]); update.unsetFlagHas_optional(); if (!optionalValues.isEmpty()) { update.setFlagHas_optional(); } update.unsetFlagNeed_rest(); if (needsRest) { update.setFlagNeed_rest(); } update.unsetFlagHas_paramnames(); update.paramNames = new int[]{}; boolean useParamNames = false; for (int p = 0; p < paramNames.size(); p++) { if (!paramNames.get(p).equals("param" + (p + 1))) { useParamNames = true; } } if (!Configuration.paramNamesEnable.get()) { useParamNames = false; } if (useParamNames) { update.setFlagHas_paramnames(); update.paramNames = new int[paramNames.size()]; for (int p = 0; p < paramNames.size(); p++) { update.paramNames[p] = abc.constants.getStringId(paramNames.get(p), true); } } return true; } }