Better float support.

Removed methodinfo parser.
This commit is contained in:
Jindra Petřík
2024-08-11 09:37:46 +02:00
parent 9f661ec84c
commit e685022fd7
28 changed files with 3369 additions and 4699 deletions

View File

@@ -17,6 +17,7 @@
package com.jpexs.decompiler.flash.abc.avm2.instructions.other.floatsupport;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.AVM2LocalData;
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
import com.jpexs.decompiler.flash.abc.avm2.AVM2Runtime;
import com.jpexs.decompiler.flash.abc.avm2.LocalDataArea;
@@ -24,13 +25,21 @@ import com.jpexs.decompiler.flash.abc.avm2.exceptions.AVM2VerifyErrorException;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2InstructionFlag;
import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
import com.jpexs.decompiler.flash.abc.avm2.instructions.types.CoerceOrConvertTypeIns;
import com.jpexs.decompiler.flash.abc.avm2.model.ConvertAVM2Item;
import com.jpexs.decompiler.flash.abc.types.Float4;
import com.jpexs.decompiler.flash.ecma.EcmaScript;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateStack;
import com.jpexs.decompiler.graph.TypeItem;
import java.util.List;
/**
* convert_f4 - Convert a value to a float4.
*
* @author JPEXS
*/
public class ConvertF4Ins extends InstructionDefinition {
public class ConvertF4Ins extends InstructionDefinition implements CoerceOrConvertTypeIns{
/**
* Constructor
@@ -48,6 +57,15 @@ public class ConvertF4Ins extends InstructionDefinition {
super.verify(lda, constants, ins);
}
@Override
public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) {
Object value = lda.operandStack.pop();
double d = EcmaScript.toNumber(value);
float f = (float) d;
lda.operandStack.push(new Float4(f, f, f, f));
return true;
}
@Override
public int getStackPopCount(AVM2Instruction ins, ABC abc) {
return 1;
@@ -57,4 +75,14 @@ public class ConvertF4Ins extends InstructionDefinition {
public int getStackPushCount(AVM2Instruction ins, ABC abc) {
return 1;
}
@Override
public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List<GraphTargetItem> output, String path) {
stack.push(new ConvertAVM2Item(ins, localData.lineStartInstruction, stack.pop(), getTargetType(localData.getConstants(), ins)));
}
@Override
public GraphTargetItem getTargetType(AVM2ConstantPool constants, AVM2Instruction ins) {
return new TypeItem("float4");
}
}

View File

@@ -17,6 +17,7 @@
package com.jpexs.decompiler.flash.abc.avm2.instructions.other.floatsupport;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.AVM2LocalData;
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
import com.jpexs.decompiler.flash.abc.avm2.AVM2Runtime;
import com.jpexs.decompiler.flash.abc.avm2.LocalDataArea;
@@ -24,13 +25,20 @@ import com.jpexs.decompiler.flash.abc.avm2.exceptions.AVM2VerifyErrorException;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2InstructionFlag;
import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
import com.jpexs.decompiler.flash.abc.avm2.instructions.types.CoerceOrConvertTypeIns;
import com.jpexs.decompiler.flash.abc.avm2.model.ConvertAVM2Item;
import com.jpexs.decompiler.flash.ecma.EcmaScript;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateStack;
import com.jpexs.decompiler.graph.TypeItem;
import java.util.List;
/**
* convert_f - Convert a value to a float.
*
* @author JPEXS
*/
public class ConvertFIns extends InstructionDefinition {
public class ConvertFIns extends InstructionDefinition implements CoerceOrConvertTypeIns {
/**
* Constructor
@@ -47,6 +55,15 @@ public class ConvertFIns extends InstructionDefinition {
super.verify(lda, constants, ins);
}
@Override
public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) {
Object value = lda.operandStack.pop();
double d = EcmaScript.toNumber(value);
float f = (float) d;
lda.operandStack.push(f);
return true;
}
@Override
public int getStackPopCount(AVM2Instruction ins, ABC abc) {
@@ -57,4 +74,14 @@ public class ConvertFIns extends InstructionDefinition {
public int getStackPushCount(AVM2Instruction ins, ABC abc) {
return 1;
}
@Override
public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List<GraphTargetItem> output, String path) {
stack.push(new ConvertAVM2Item(ins, localData.lineStartInstruction, stack.pop(), getTargetType(localData.getConstants(), ins)));
}
@Override
public GraphTargetItem getTargetType(AVM2ConstantPool constants, AVM2Instruction ins) {
return new TypeItem("float");
}
}

View File

@@ -17,6 +17,7 @@
package com.jpexs.decompiler.flash.abc.avm2.instructions.other.floatsupport;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.AVM2LocalData;
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
import com.jpexs.decompiler.flash.abc.avm2.AVM2Runtime;
@@ -25,6 +26,10 @@ import com.jpexs.decompiler.flash.abc.avm2.exceptions.AVM2VerifyErrorException;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2InstructionFlag;
import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
import com.jpexs.decompiler.flash.abc.avm2.model.Float4ValueAVM2Item;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateStack;
import java.util.List;
/**
* pushfloat4 - Push a float4 constant onto the stack.
@@ -49,6 +54,12 @@ public class PushFloat4Ins extends InstructionDefinition {
super.verify(lda, constants, ins);
}
@Override
public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) {
lda.operandStack.push(constants.getFloat4(ins.operands[0]));
return true;
}
@Override
public int getStackPopCount(AVM2Instruction ins, ABC abc) {
return 0;
@@ -59,4 +70,8 @@ public class PushFloat4Ins extends InstructionDefinition {
return 1;
}
@Override
public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List<GraphTargetItem> output, String path) {
stack.push(new Float4ValueAVM2Item(ins, localData.lineStartInstruction, localData.getConstants().getFloat4(ins.operands[0])));
}
}

View File

@@ -17,6 +17,7 @@
package com.jpexs.decompiler.flash.abc.avm2.instructions.other.floatsupport;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.AVM2LocalData;
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
import com.jpexs.decompiler.flash.abc.avm2.AVM2Runtime;
@@ -25,6 +26,10 @@ import com.jpexs.decompiler.flash.abc.avm2.exceptions.AVM2VerifyErrorException;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2InstructionFlag;
import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
import com.jpexs.decompiler.flash.abc.avm2.model.FloatValueAVM2Item;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateStack;
import java.util.List;
/**
* pushfloat - Push a float constant onto the stack.
@@ -48,6 +53,12 @@ public class PushFloatIns extends InstructionDefinition {
super.verify(lda, constants, ins);
}
@Override
public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) {
lda.operandStack.push(constants.getFloat(ins.operands[0]));
return true;
}
@Override
public int getStackPopCount(AVM2Instruction ins, ABC abc) {
@@ -58,4 +69,9 @@ public class PushFloatIns extends InstructionDefinition {
public int getStackPushCount(AVM2Instruction ins, ABC abc) {
return 1;
}
@Override
public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List<GraphTargetItem> output, String path) {
stack.push(new FloatValueAVM2Item(ins, localData.lineStartInstruction, localData.getConstants().getFloat(ins.operands[0])));
}
}

View File

@@ -0,0 +1,140 @@
/*
* Copyright (C) 2010-2024 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.model;
import com.jpexs.decompiler.flash.SourceGeneratorLocalData;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instructions;
import com.jpexs.decompiler.flash.abc.avm2.parser.script.AVM2SourceGenerator;
import com.jpexs.decompiler.flash.abc.types.Float4;
import com.jpexs.decompiler.flash.ecma.EcmaScript;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.graph.CompilationException;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.SourceGenerator;
import com.jpexs.decompiler.graph.TypeItem;
import com.jpexs.decompiler.graph.model.LocalData;
import java.util.List;
import java.util.Objects;
import java.util.Set;
/**
* Float4 value.
*
* @author JPEXS
*/
public class Float4ValueAVM2Item extends NumberValueAVM2Item {
/**
* Value
*/
public Float4 value;
/**
* Constructor.
*
* @param instruction Instruction
* @param lineStartIns Line start instruction
* @param value Value
*/
public Float4ValueAVM2Item(GraphSourceItem instruction, GraphSourceItem lineStartIns, Float4 value) {
super(instruction, lineStartIns);
this.value = value;
}
@Override
public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) {
writer.append("float4");
writer.spaceBeforeCallParenthesies(precedence);
writer.append("(");
writer.append(EcmaScript.toString(value.values[0]));
if (Float.isFinite(value.values[0])) {
writer.append("f");
}
writer.append(",");
writer.append(EcmaScript.toString(value.values[1]));
if (Float.isFinite(value.values[1])) {
writer.append("f");
}
writer.append(",");
writer.append(EcmaScript.toString(value.values[2]));
if (Float.isFinite(value.values[2])) {
writer.append("f");
}
writer.append(",");
writer.append(EcmaScript.toString(value.values[3]));
if (Float.isFinite(value.values[3])) {
writer.append("f");
}
writer.append(")");
return writer;
}
@Override
public Object getResult() {
return value;
}
@Override
public boolean isCompileTime(Set<GraphTargetItem> dependencies) {
return true;
}
@Override
public List<GraphSourceItem> toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException {
return toSourceMerge(localData, generator,
new AVM2Instruction(0, AVM2Instructions.PushFloat4, new int[]{((AVM2SourceGenerator) generator).abcIndex.getSelectedAbc().constants.getFloat4Id(value, true)})
);
}
@Override
public GraphTargetItem returnType() {
return TypeItem.NUMBER;
}
@Override
public boolean hasReturnValue() {
return true;
}
@Override
public int hashCode() {
int hash = 7;
hash = 53 * hash + Objects.hashCode(this.value);
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Float4ValueAVM2Item other = (Float4ValueAVM2Item) obj;
if (!Objects.equals(this.value, other.value)) {
return false;
}
return true;
}
}

View File

@@ -58,7 +58,11 @@ public class FloatValueAVM2Item extends NumberValueAVM2Item {
@Override
public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) {
return writer.append(EcmaScript.toString(value)).append("f");
writer.append(EcmaScript.toString(value));
if (Float.isFinite(value)) {
writer.append("f");
}
return writer;
}
@Override

View File

@@ -0,0 +1,63 @@
/*
* Copyright (C) 2010-2024 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.model.operations;
import com.jpexs.decompiler.flash.SourceGeneratorLocalData;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instructions;
import com.jpexs.decompiler.graph.CompilationException;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.SourceGenerator;
import com.jpexs.decompiler.graph.TypeItem;
import com.jpexs.decompiler.graph.model.UnaryOpItem;
import java.util.List;
/**
* Unary plus.
*
* @author JPEXS
*/
public class UnPlusAVM2Item extends UnaryOpItem {
/**
* Constructor.
* @param instruction Instruction
* @param lineStartIns Line start instruction
* @param value Value
*/
public UnPlusAVM2Item(GraphSourceItem instruction, GraphSourceItem lineStartIns, GraphTargetItem value) {
super(instruction, lineStartIns, PRECEDENCE_UNARY, value, "+", "Number");
}
@Override
public Object getResult() {
return value.getResultAsNumber();
}
@Override
public List<GraphSourceItem> toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException {
return toSourceMerge(localData, generator, value,
new AVM2Instruction(0, AVM2Instructions.UnPlus, null)
);
}
@Override
public GraphTargetItem returnType() {
return TypeItem.NUMBER;
}
}

View File

@@ -241,7 +241,7 @@ public class ASM3Parser {
nval = nval.substring(0, nval.length() - 1);
}
return Double.parseDouble(nval);
}
}
private static void expected(ParsedSymbol s, int type, String expStr, int line) throws IOException, AVM2ParseException {
if (s.type != type) {
@@ -830,11 +830,44 @@ public class ASM3Parser {
value = lexer.lex();
if (value.type == ParsedSymbol.TYPE_KEYWORD_NULL) {
value_index = 0;
} else if (value.type == ParsedSymbol.TYPE_NUMBER) {
} else {
value_index = constants.getDoubleId(getDouble(value, lexer.yyline(), true), true);
}
expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer);
break;
break;
case ParsedSymbol.TYPE_KEYWORD_FLOAT:
value_kind = ValueKind.CONSTANT_DecimalOrFloat;
expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer);
value = lexer.lex();
if (value.type == ParsedSymbol.TYPE_KEYWORD_NULL) {
value_index = 0;
} else {
value_index = constants.getFloatId(getFloat(value, lexer.yyline(), true), true);
}
expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer);
break;
case ParsedSymbol.TYPE_KEYWORD_FLOAT4:
value_kind = ValueKind.CONSTANT_Float4;
expected(ParsedSymbol.TYPE_PARENT_OPEN, "(", lexer);
value = lexer.lex();
if (value.type == ParsedSymbol.TYPE_KEYWORD_NULL) {
value_index = 0;
} else {
float f1 = getFloat(value, lexer.yyline(), true);
expected(ParsedSymbol.TYPE_COMMA, ",", lexer);
value = lexer.lex();
float f2 = getFloat(value, lexer.yyline(), true);
expected(ParsedSymbol.TYPE_COMMA, ",", lexer);
value = lexer.lex();
float f3 = getFloat(value, lexer.yyline(), true);
expected(ParsedSymbol.TYPE_COMMA, ",", lexer);
value = lexer.lex();
float f4 = getFloat(value, lexer.yyline(), true);
Float4 fval = new Float4(f1, f2, f3, f4);
value_index = constants.getFloat4Id(fval, true);
}
expected(ParsedSymbol.TYPE_PARENT_CLOSE, ")", lexer);
break;
case ParsedSymbol.TYPE_NUMBER:
String nval = (String) type.value;
if (nval.endsWith("m")) {

View File

@@ -574,6 +574,16 @@ public class ParsedSymbol {
*/
public static final int TYPE_KEYWORD_FLOOR = 108;
/**
* Type: Keyword Float
*/
public static final int TYPE_KEYWORD_FLOAT = 109;
/**
* Type: Keyword Float4
*/
public static final int TYPE_KEYWORD_FLOAT4 = 110;
/**
* Constructor.
* @param pos Position

View File

@@ -34,6 +34,7 @@ import com.jpexs.decompiler.flash.abc.avm2.model.ApplyTypeAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.BooleanAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.DecimalValueAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.DoubleValueAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.Float4ValueAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.FloatValueAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.GetDescendantsAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.IntegerValueAVM2Item;
@@ -1564,6 +1565,9 @@ public class AVM2SourceGenerator implements SourceGenerator {
if (val instanceof FloatValueAVM2Item) {
return new ValueKind(abcIndex.getSelectedAbc().constants.getFloatId(((FloatValueAVM2Item) val).value, true), ValueKind.CONSTANT_DecimalOrFloat);
}
if (val instanceof Float4ValueAVM2Item) {
return new ValueKind(abcIndex.getSelectedAbc().constants.getFloat4Id(((Float4ValueAVM2Item) val).value, true), ValueKind.CONSTANT_Float4);
}
if (val instanceof NanAVM2Item) {
return new ValueKind(abcIndex.getSelectedAbc().constants.getDoubleId(Double.NaN, true), ValueKind.CONSTANT_Double);
}

View File

@@ -29,6 +29,7 @@ import com.jpexs.decompiler.flash.abc.avm2.model.DefaultXMLNamespace;
import com.jpexs.decompiler.flash.abc.avm2.model.EscapeXAttrAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.EscapeXElemAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.DoubleValueAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.Float4ValueAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.FloatValueAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.GetDescendantsAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.GetPropertyAVM2Item;
@@ -86,6 +87,7 @@ import com.jpexs.decompiler.flash.abc.avm2.model.operations.SubtractAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.operations.TypeOfAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.operations.URShiftAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.parser.AVM2ParseException;
import com.jpexs.decompiler.flash.abc.types.Float4;
import com.jpexs.decompiler.flash.abc.types.Namespace;
import com.jpexs.decompiler.flash.abc.types.ScriptInfo;
import com.jpexs.decompiler.flash.action.swf4.ActionIf;
@@ -2461,7 +2463,7 @@ public class ActionScript3Parser {
case DOUBLE:
ret = new DoubleValueAVM2Item(null, null, (Double) s.value);
allowMemberOrCall = true; // 5.2.toString();
break;
break;
case DECIMAL:
ret = new DecimalValueAVM2Item(null, null, (Decimal128) s.value);
allowMemberOrCall = true;
@@ -2470,6 +2472,10 @@ public class ActionScript3Parser {
ret = new FloatValueAVM2Item(null, null, (Float) s.value);
allowMemberOrCall = true;
break;
case FLOAT4:
ret = new Float4ValueAVM2Item(null, null, (Float4) s.value);
allowMemberOrCall = true;
break;
case DELETE:
GraphTargetItem varDel = expressionPrimary(allOpenedNamespaces, thisType, pkg, needsActivation, importedClasses, openedNamespaces, false, registerVars, inFunction, inMethod, true, variables);
if (!isNameOrProp(varDel)) {

View File

@@ -63,6 +63,10 @@ public enum SymbolGroup {
* Float
*/
FLOAT,
/**
* Float 4
*/
FLOAT4,
/**
* Type name
*/

View File

@@ -475,6 +475,10 @@ public enum SymbolType {
* Other: Float
*/
FLOAT(GraphTargetItem.PRECEDENCE_PRIMARY, false),
/**
* Other: Float 4
*/
FLOAT4(GraphTargetItem.PRECEDENCE_PRIMARY, false),
/**
* Other: Type name
*/

View File

@@ -1,31 +0,0 @@
/*
* Copyright (C) 2010-2024 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.methodinfoparser;
import com.jpexs.decompiler.flash.ParseException;
/**
* Method info parse exception.
*
* @author JPEXS
*/
public class MethodInfoParseException extends ParseException {
public MethodInfoParseException(String text, long line) {
super(text, line);
}
}

View File

@@ -1,362 +0,0 @@
/*
* Copyright (C) 2010-2024 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.methodinfoparser;
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;
import macromedia.asc.util.Decimal128;
/**
* ABC Method info P-code parser.
*
* @author JPEXS
*/
public class MethodInfoParser {
private static ValueKind numberToValueKind(ABC abc, String nval) {
if (nval.endsWith("m")) {
nval = nval.substring(0, nval.length() - 1);
return new ValueKind(abc.constants.getDecimalId(new Decimal128(nval), true), ValueKind.CONSTANT_DecimalOrFloat);
}
if (nval.endsWith("f")) {
nval = nval.substring(0, nval.length() - 1);
return new ValueKind(abc.constants.getFloatId(Float.parseFloat(nval), true), ValueKind.CONSTANT_DecimalOrFloat);
}
if (nval.endsWith("d") || nval.contains("e") || nval.contains("E") | nval.contains(".")) {
if (nval.endsWith("d")) {
nval = nval.substring(0, nval.length() - 1);
}
return new ValueKind(abc.constants.getDoubleId(Double.parseDouble(nval), true), ValueKind.CONSTANT_Double);
}
if (nval.endsWith("i") || nval.endsWith("u")) {
nval = nval.substring(0, nval.length() - 1);
}
return new ValueKind(abc.constants.getIntId(Integer.parseInt(nval), true), ValueKind.CONSTANT_Int);
}
/**
* Parses slot const.
*
* @param text Text to parse
* @param trait Trait to update
* @param abc ABC file
* @return True if successful
* @throws MethodInfoParseException On parse error
*/
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_NUMBER:
value = numberToValueKind(abc, (String) symbValue.value);
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(ValueKind.CONSTANT_True, ValueKind.CONSTANT_True);
break;
case ParsedSymbol.TYPE_FALSE:
value = new ValueKind(ValueKind.CONSTANT_False, ValueKind.CONSTANT_False);
break;
case ParsedSymbol.TYPE_NULL:
value = new ValueKind(ValueKind.CONSTANT_Null, ValueKind.CONSTANT_Null);
break;
case ParsedSymbol.TYPE_UNDEFINED:
value = new ValueKind(ValueKind.CONSTANT_Undefined, 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) {
//empty
} 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;
}
/**
* Parses return type.
*
* @param text Text to parse
* @param update Method info to update
* @return True if successful
* @throws MethodInfoParseException On parse error
*/
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) {
//ignore
}
return false;
}
/**
* Parses parameters.
*
* @param text Text to parse
* @param update Method info to update
* @param abc ABC file
* @return True if successful
* @throws MethodInfoParseException On parse error
*/
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((Long) 0L);
} 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_NUMBER:
optionalValues.add(numberToValueKind(abc, (String) symbValue.value));
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(ValueKind.CONSTANT_True, ValueKind.CONSTANT_True));
break;
case ParsedSymbol.TYPE_FALSE:
optionalValues.add(new ValueKind(ValueKind.CONSTANT_False, ValueKind.CONSTANT_False));
break;
case ParsedSymbol.TYPE_NULL:
optionalValues.add(new ValueKind(ValueKind.CONSTANT_Null, ValueKind.CONSTANT_Null));
break;
case ParsedSymbol.TYPE_UNDEFINED:
optionalValues.add(new ValueKind(ValueKind.CONSTANT_Undefined, 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) {
//empty
} 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) {
//empty
} 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;
}
}

View File

@@ -1,160 +0,0 @@
/*
* Copyright (C) 2010-2024 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.methodinfoparser;
/**
* ABC method info P-code parser symbol.
*
* @author JPEXS
*/
public class ParsedSymbol {
/**
* Type
*/
public int type;
/**
* Value
*/
public Object value;
/**
* Type: Number
*/
public static final int TYPE_NUMBER = 1;
/**
* Type: True
*/
public static final int TYPE_TRUE = 3;
/**
* Type: False
*/
public static final int TYPE_FALSE = 4;
/**
* Type: Null
*/
public static final int TYPE_NULL = 5;
/**
* Type: Undefined
*/
public static final int TYPE_UNDEFINED = 6;
/**
* Type: String
*/
public static final int TYPE_STRING = 7;
//8-12 namespace prefix
/**
* Type: Private
*/
public static final int TYPE_PRIVATE = 8;
/**
* Type: Package
*/
public static final int TYPE_PACKAGE = 9;
/**
* Type: Internal
*/
public static final int TYPE_INTERNAL = 10;
/**
* Type: Static
*/
public static final int TYPE_STATIC = 11;
/**
* Type: Explicit
*/
public static final int TYPE_EXPLICIT = 12;
/**
* Type: Protected
*/
public static final int TYPE_PROTECTED = 13;
/**
* Type: Namespace
*/
public static final int TYPE_NAMESPACE = 14;
/**
* Type: Colon
*/
public static final int TYPE_COLON = 15;
/**
* Type: Comma
*/
public static final int TYPE_COMMA = 16;
/**
* Type: Dots
*/
public static final int TYPE_DOTS = 17;
/**
* Type: Multiname
*/
public static final int TYPE_MULTINAME = 18;
/**
* Type: Identifier
*/
public static final int TYPE_IDENTIFIER = 19;
/**
* Type: End of file
*/
public static final int TYPE_EOF = 20;
/**
* Type: Star
*/
public static final int TYPE_STAR = 21;
/**
* Type: Assign
*/
public static final int TYPE_ASSIGN = 22;
/**
* Constructor.
* @param type Type
* @param value Value
*/
public ParsedSymbol(int type, Object value) {
this.type = type;
this.value = value;
}
/**
* Constructor.
* @param type Type
*/
public ParsedSymbol(int type) {
this.type = type;
}
}

View File

@@ -1,4 +0,0 @@
/**
* Parsing method info P-code.
*/
package com.jpexs.decompiler.flash.abc.methodinfoparser;

View File

@@ -237,17 +237,38 @@ public class ValueKind {
break;
case CONSTANT_DecimalOrFloat:
if (abc.hasDecimalSupport()) {
ret = "" + abc.constants.getDecimal(value_index);
ret = abc.constants.getDecimal(value_index).toActionScriptString();
} else {
ret = "" + EcmaScript.toString(abc.constants.getFloat(value_index));
float fval = abc.constants.getFloat(value_index);
ret = EcmaScript.toString(fval) + (Float.isFinite(fval) ? "f" : "");
}
break;
case CONSTANT_Float4:
Float4 f4 = abc.constants.getFloat4(value_index);
ret = "[" + EcmaScript.toString(f4.values[0]) + ", "
+ EcmaScript.toString(f4.values[1]) + ", "
+ EcmaScript.toString(f4.values[2]) + ", "
+ EcmaScript.toString(f4.values[3]) + "]";
StringBuilder fsb = new StringBuilder();
fsb.append("float4");
fsb.append("(");
fsb.append(EcmaScript.toString(f4.values[0]));
if (Float.isFinite(f4.values[0])) {
fsb.append("f");
}
fsb.append(",");
fsb.append(EcmaScript.toString(f4.values[1]));
if (Float.isFinite(f4.values[1])) {
fsb.append("f");
}
fsb.append(",");
fsb.append(EcmaScript.toString(f4.values[2]));
if (Float.isFinite(f4.values[2])) {
fsb.append("f");
}
fsb.append(",");
fsb.append(EcmaScript.toString(f4.values[3]));
if (Float.isFinite(f4.values[3])) {
fsb.append("f");
}
fsb.append(")");
ret = fsb.toString();
break;
case CONSTANT_Utf8:
ret = "\"" + Helper.escapeActionScriptString(abc.constants.getString(value_index)) + "\"";

View File

@@ -16,6 +16,7 @@
*/
package com.jpexs.decompiler.flash.ecma;
import com.jpexs.decompiler.flash.abc.types.Float4;
import com.jpexs.decompiler.flash.action.swf4.ConstantIndex;
import com.jpexs.helpers.utf8.Utf8Helper;
import java.io.ByteArrayOutputStream;
@@ -52,6 +53,9 @@ public class EcmaScript {
if (o instanceof Float) {
o = (double) (float) (Float) o;
}
if (o instanceof Float4) {
return Double.NaN;
}
if (o instanceof Double) {
return (Double) o;
}
@@ -69,7 +73,7 @@ public class EcmaScript {
}
try {
return Double.parseDouble(str);
return Double.valueOf(str);
} catch (NumberFormatException nfe) {
return Double.NaN;
}
@@ -204,6 +208,12 @@ public class EcmaScript {
if (o.getClass() == Undefined.class) {
return EcmaType.UNDEFINED;
}
if (o.getClass() == Float.class) {
return EcmaType.FLOAT;
}
if (o.getClass() == Float4.class) {
return EcmaType.FLOAT4;
}
return EcmaType.OBJECT;
}
@@ -225,6 +235,12 @@ public class EcmaScript {
case NUMBER:
typeStr = "number";
break;
case FLOAT:
typeStr = "float";
break;
case FLOAT4:
typeStr = "float4";
break;
case OBJECT:
typeStr = "object";
break;
@@ -236,7 +252,7 @@ public class EcmaScript {
typeStr = "object";
break;
default:
// todo: function,movieclip
// todo: function,movieclip,xml
typeStr = "object";
break;
}

View File

@@ -46,8 +46,16 @@ public enum EcmaType {
/**
* Boolean
*/
BOOLEAN("Boolean");
BOOLEAN("Boolean"),
/**
* Float
*/
FLOAT("float"),
/**
* Float 4
*/
FLOAT4("float4");
private final String clsName;
private EcmaType(String clsName) {