/*
* 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.types;
import com.jpexs.decompiler.flash.IdentifiersDeobfuscation;
import com.jpexs.decompiler.flash.abc.ABC;
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.construction.NewFunctionIns;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.flash.helpers.hilight.HighlightData;
import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType;
import com.jpexs.decompiler.flash.types.annotations.Internal;
import com.jpexs.decompiler.graph.DottedChain;
import com.jpexs.helpers.Helper;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*
* @author JPEXS
*/
public class MethodInfo {
@Internal
public boolean deleted;
public void delete(ABC abc, boolean d) {
this.deleted = true;
MethodBody body = abc.findBody(this);
if (body != null) {
for (AVM2Instruction ins : body.getCode().code) {
if (ins.definition instanceof NewFunctionIns) {
if (ins.operands[0] < abc.method_info.size() && !abc.method_info.get(ins.operands[0]).deleted) {
abc.method_info.get(ins.operands[0]).delete(abc, d);
}
}
}
}
}
public int[] param_types = new int[]{};
public int ret_type;
public int name_index; //0=no name
// 1=need_arguments, 2=need_activation, 4=need_rest 8=has_optional 16=ignore_rest, 32=explicit, 64=setsdxns, 128=has_paramnames
public static int FLAG_NEED_ARGUMENTS = 1;
public static int FLAG_NEED_ACTIVATION = 2;
public static int FLAG_NEED_REST = 4;
public static int FLAG_HAS_OPTIONAL = 8;
public static int FLAG_IGNORE_REST = 16;
public static int FLAG_EXPLICIT = 32;
public static int FLAG_SETSDXNS = 64;
public static int FLAG_HAS_PARAMNAMES = 128;
public int flags;
public ValueKind[] optional = new ValueKind[0];
public int[] paramNames = new int[0];
public void setFlagIgnore_Rest() {
flags |= FLAG_IGNORE_REST;
}
public void setFlagExplicit() {
flags |= FLAG_EXPLICIT;
}
public void setFlagNeed_Arguments() {
flags |= FLAG_NEED_ARGUMENTS;
}
public void setFlagSetsdxns() {
flags |= FLAG_SETSDXNS;
}
public void setFlagSetsdxns(boolean val) {
if (val) {
setFlagSetsdxns();
} else {
unsetFlagSetsdxns();
}
}
public void unsetFlagSetsdxns() {
if (flagSetsdxns()) {
flags -= FLAG_SETSDXNS;
}
}
public void setFlagNeed_activation() {
flags |= FLAG_NEED_ACTIVATION;
}
public void setFlagNeed_activation(boolean val) {
if (val) {
setFlagNeed_activation();
} else {
unsetFlagNeed_activation();
}
}
public void unsetFlagNeed_activation() {
if (flagNeed_activation()) {
flags -= FLAG_NEED_ACTIVATION;
}
}
public void setFlagNeed_rest() {
flags |= FLAG_NEED_REST;
}
public void unsetFlagNeed_rest() {
if (flagNeed_rest()) {
flags -= FLAG_NEED_REST;
}
}
public void setFlagNeed_rest(boolean val) {
if (val) {
setFlagNeed_rest();
} else {
unsetFlagNeed_rest();
}
}
public void setFlagHas_optional() {
flags |= FLAG_HAS_OPTIONAL;
}
public void unsetFlagHas_optional() {
if (flagHas_optional()) {
flags -= FLAG_HAS_OPTIONAL;
}
}
public void setFlagHas_optional(boolean val) {
if (val) {
setFlagHas_optional();
} else {
unsetFlagHas_optional();
}
}
public void setFlagHas_paramnames() {
flags |= FLAG_HAS_PARAMNAMES;
}
public void unsetFlagHas_paramnames() {
if (flagHas_paramnames()) {
flags -= FLAG_HAS_PARAMNAMES;
}
}
public void setFlagHas_paramnames(boolean val) {
if (val) {
setFlagHas_paramnames();
} else {
unsetFlagHas_paramnames();
}
}
public boolean flagNeed_arguments() {
return (flags & FLAG_NEED_ARGUMENTS) == FLAG_NEED_ARGUMENTS;
}
public boolean flagNeed_activation() {
return (flags & FLAG_NEED_ACTIVATION) == FLAG_NEED_ACTIVATION;
}
public boolean flagNeed_rest() {
return (flags & FLAG_NEED_REST) == FLAG_NEED_REST;
}
public boolean flagHas_optional() {
return (flags & FLAG_HAS_OPTIONAL) == FLAG_HAS_OPTIONAL;
}
public boolean flagIgnore_rest() {
return (flags & FLAG_IGNORE_REST) == FLAG_IGNORE_REST;
}
public boolean flagExplicit() {
return (flags & FLAG_EXPLICIT) == FLAG_EXPLICIT;
}
public boolean flagSetsdxns() {
return (flags & FLAG_SETSDXNS) == FLAG_SETSDXNS;
}
public boolean flagHas_paramnames() {
return (flags & FLAG_HAS_PARAMNAMES) == FLAG_HAS_PARAMNAMES;
}
public MethodInfo() {
}
public MethodInfo(int[] param_types, int ret_type, int name_index, int flags, ValueKind[] optional, int[] paramNames) {
this.param_types = param_types;
this.ret_type = ret_type;
this.name_index = name_index;
this.flags = flags;
this.optional = optional;
this.paramNames = paramNames;
}
@Override
public String toString() {
StringBuilder ret = new StringBuilder();
ret.append("MethodInfo: param_types=");
Helper.intArrToStringBuilder(param_types, ret);
ret.append(" ret_type=").append(ret_type)
.append(" name_index=").append(name_index)
.append(" flags=").append(flags)
.append(" optional=[");
if (optional != null) {
for (int i = 0; i < optional.length; i++) {
if (i > 0) {
ret.append(",");
}
ret.append(optional[i].toString());
}
}
ret.append("]");
ret.append(" paramNames=");
Helper.intArrToStringBuilder(paramNames, ret);
return ret.toString();
}
public String toString(AVM2ConstantPool constants, List<DottedChain> fullyQualifiedNames) {
StringBuilder optionalStr = new StringBuilder();
optionalStr.append("[");
if (optional != null) {
for (int i = 0; i < optional.length; i++) {
if (i > 0) {
optionalStr.append(",");
}
optionalStr.append(optional[i].toString(constants));
}
}
optionalStr.append("]");
StringBuilder param_typesStr = new StringBuilder();
for (int i = 0; i < param_types.length; i++) {
if (i > 0) {
param_typesStr.append(",");
}
if (param_types[i] == 0) {
param_typesStr.append("*");
} else {
param_typesStr.append(constants.getMultiname(param_types[i]).toString(constants, fullyQualifiedNames));
}
}
StringBuilder paramNamesStr = new StringBuilder();
for (int i = 0; i < paramNames.length; i++) {
if (i > 0) {
paramNamesStr.append(",");
}
paramNamesStr.append(constants.getString(paramNames[i]));
}
String ret_typeStr;
if (ret_type == 0) {
ret_typeStr = "*";
} else {
ret_typeStr = constants.getMultiname(ret_type).toString(constants, fullyQualifiedNames);
}
return "param_types=" + param_typesStr + " ret_type=" + ret_typeStr + " name=\"" + constants.getString(name_index) + "\" flags=" + flags + " optional=" + optionalStr + " paramNames=" + paramNamesStr;
}
public String getName(AVM2ConstantPool constants) {
if (name_index == 0) {
return "UNKNOWN";
}
return constants.getString(name_index);
}
public int getMaxReservedReg() {
return param_types.length + (flagNeed_rest() ? 1 : 0) + (flagNeed_arguments() ? 1 : 0);
}
public GraphTextWriter getParamStr(GraphTextWriter writer, AVM2ConstantPool constants, MethodBody body, ABC abc, List<DottedChain> fullyQualifiedNames) {
Map<Integer, String> localRegNames = new HashMap<>();
if (body != null && Configuration.getLocalNamesFromDebugInfo.get()) {
localRegNames = body.getCode().getLocalRegNamesFromDebug(abc);
}
for (int i = 0; i < param_types.length; i++) {
if (i > 0) {
writer.appendNoHilight(", ");
}
DottedChain ptype = DottedChain.ALL;
if (param_types[i] > 0) {
ptype = constants.getMultiname(param_types[i]).getNameWithNamespace(constants, true);
}
HighlightData pdata = new HighlightData();
pdata.declaration = true;
pdata.declaredType = ptype;
pdata.regIndex = i + 1;
if (!localRegNames.isEmpty()) {
pdata.localName = localRegNames.get(i + 1); //assuming it is a slot
writer.hilightSpecial(IdentifiersDeobfuscation.printIdentifier(true, localRegNames.get(i + 1)), HighlightSpecialType.PARAM_NAME, i, pdata);
} else if ((paramNames.length > i) && (paramNames[i] != 0) && Configuration.paramNamesEnable.get()) {
pdata.localName = constants.getString(paramNames[i]);
writer.hilightSpecial(IdentifiersDeobfuscation.printIdentifier(true, constants.getString(paramNames[i])), HighlightSpecialType.PARAM_NAME, i, pdata);
} else {
pdata.localName = "param" + (i + 1);
writer.hilightSpecial(pdata.localName, HighlightSpecialType.PARAM_NAME, i, pdata);
}
writer.appendNoHilight(":");
if (param_types[i] == 0) {
writer.hilightSpecial("*", HighlightSpecialType.PARAM, i);
} else {
writer.hilightSpecial(constants.getMultiname(param_types[i]).getName(constants, fullyQualifiedNames, false, true), HighlightSpecialType.PARAM, i);
}
if (optional != null) {
if (i >= param_types.length - optional.length) {
int optionalIndex = i - (param_types.length - optional.length);
writer.appendNoHilight(" = ");
writer.hilightSpecial(optional[optionalIndex].toString(constants), HighlightSpecialType.OPTIONAL, optionalIndex);
}
}
}
if (flagNeed_rest()) {
String restAdd = "";
if ((param_types != null) && (param_types.length > 0)) {
restAdd = ", ";
}
restAdd += "... ";
String restName;
if (!localRegNames.isEmpty()) {
restName = localRegNames.get(param_types.length + 1);
} else {
restName = "rest";
}
HighlightData pdata = new HighlightData();
pdata.declaration = true;
pdata.declaredType = DottedChain.ALL;
pdata.regIndex = param_types.length + 1;
pdata.localName = restName;
writer.append(restAdd);
writer.hilightSpecial(restName, HighlightSpecialType.FLAG_NEED_REST, 0, pdata);
}
return writer;
}
public GraphTextWriter getReturnTypeStr(GraphTextWriter writer, AVM2ConstantPool constants, List<DottedChain> fullyQualifiedNames) {
String rname = "*";
if (ret_type > 0) {
Multiname multiname = constants.getMultiname(ret_type);
if (multiname.kind != Multiname.TYPENAME && multiname.name_index > 0 && constants.getString(multiname.name_index).equals("void")) {
rname = "void";
} else {
rname = multiname.getName(constants, fullyQualifiedNames, false, true);
}
}
return writer.hilightSpecial(rname, HighlightSpecialType.RETURNS);
}
public String getReturnTypeRaw(AVM2ConstantPool constants, List<DottedChain> fullyQualifiedNames) {
String rname = "*";
if (ret_type > 0) {
Multiname multiname = constants.getMultiname(ret_type);
if (multiname.kind != Multiname.TYPENAME && multiname.name_index > 0 && constants.getString(multiname.name_index).equals("void")) {
rname = "void";
} else {
rname = multiname.getName(constants, fullyQualifiedNames, false, true);
}
}
return rname;
}
}