mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-06-12 14:11:54 +00:00
Display AS3 p-code docs in GUI, improvements.
This commit is contained in:
@@ -2160,7 +2160,8 @@ public class AVM2Code implements Cloneable {
|
||||
ins.operands[j] = updater.updateOperandOffset(target, ins.operands[j]);
|
||||
}
|
||||
}*/ //Faster, but not so universal
|
||||
if (ins.definition instanceof IfTypeIns) {
|
||||
{
|
||||
if (ins.definition instanceof IfTypeIns) {
|
||||
long target = ins.getTargetAddress();
|
||||
try {
|
||||
ins.operands[0] = updater.updateOperandOffset(ins.getAddress(), target, ins.operands[0]);
|
||||
@@ -2168,6 +2169,7 @@ public class AVM2Code implements Cloneable {
|
||||
throw new ConvertException("Invalid offset (" + ins + ")", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
ins.setAddress(updater.updateInstructionOffset(ins.getAddress()));
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
|
||||
public class AbsJumpIns extends InstructionDefinition {
|
||||
|
||||
public AbsJumpIns() {
|
||||
super(0xEE, "abs_jump", new int[]{}, false /*?*/, AVM2InstructionFlag.UNDOCUMENTED, AVM2InstructionFlag.UNKNOWN_OPERANDS, AVM2InstructionFlag.NO_FLASH_PLAYER);
|
||||
super(0xEE, "abs_jump", new int[]{}, false /*?*/, AVM2InstructionFlag.UNDOCUMENTED, AVM2InstructionFlag.UNKNOWN_OPERANDS, AVM2InstructionFlag.NO_FLASH_PLAYER, AVM2InstructionFlag.UNKNOWN_STACK);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -598,9 +598,10 @@ public class Configuration {
|
||||
@ConfigurationInternal
|
||||
public static final ConfigurationItem<Boolean> hwAcceleratedGraphics = null;
|
||||
|
||||
@ConfigurationDefaultBoolean(false)
|
||||
@ConfigurationDefaultDouble(0.85)
|
||||
@ConfigurationName("gui.avm2.splitPane.docs.dividerLocationPercent")
|
||||
@ConfigurationInternal
|
||||
public static final ConfigurationItem<Boolean> as3pcodeDocWindow = null;
|
||||
public static final ConfigurationItem<Double> guiAvm2DocsSplitPaneDividerLocationPercent = null;
|
||||
|
||||
private enum OSId {
|
||||
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
package com.jpexs.decompiler.flash.docs;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2InstructionFlag;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
|
||||
import com.jpexs.helpers.Cache;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* Generator for AVM2 instruction set documentation.
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class As3PCodeDocs {
|
||||
|
||||
private static ResourceBundle prop;
|
||||
private static Map<AVM2InstructionFlag, String> flagDescriptions = new HashMap<>();
|
||||
|
||||
private static Cache<String, String> docsCache = Cache.getInstance(false, true, "as3DocsCache");
|
||||
private static Map<String, InstructionDefinition> nameToDef = new HashMap<>();
|
||||
|
||||
static final String NEWLINE = "\r\n";
|
||||
|
||||
static {
|
||||
prop = ResourceBundle.getBundle("com.jpexs.decompiler.flash.locales.docs.pcode.AS3");
|
||||
for (InstructionDefinition def : AVM2Code.allInstructionSet) {
|
||||
if (def == null) {
|
||||
continue;
|
||||
}
|
||||
nameToDef.put(def.instructionName, def);
|
||||
}
|
||||
|
||||
for (AVM2InstructionFlag flg : AVM2InstructionFlag.values()) {
|
||||
String flagIdent = makeIdent(flg.toString());
|
||||
String flagDescription = getProperty("instructionFlag." + flagIdent);
|
||||
flagDescriptions.put(flg, flagDescription);
|
||||
}
|
||||
}
|
||||
|
||||
private static String makeIdent(String name) {
|
||||
StringBuilder identName = new StringBuilder();
|
||||
boolean cap = false;
|
||||
for (int i = 0; i < name.length(); i++) {
|
||||
char c = name.charAt(i);
|
||||
if (c == '_') {
|
||||
cap = true;
|
||||
continue;
|
||||
}
|
||||
if (cap) {
|
||||
identName.append(c);
|
||||
cap = false;
|
||||
} else {
|
||||
identName.append(Character.toLowerCase(c));
|
||||
}
|
||||
}
|
||||
return identName.toString();
|
||||
}
|
||||
|
||||
public static String getDocsForIns(String insName, boolean showDataSize, boolean ui) {
|
||||
if (!nameToDef.containsKey(insName)) {
|
||||
return null;
|
||||
}
|
||||
return getDocsForIns(nameToDef.get(insName), showDataSize, ui);
|
||||
}
|
||||
|
||||
private static String getProperty(String name) {
|
||||
if (prop.containsKey(name)) {
|
||||
return prop.getString(name);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getDocsForIns(InstructionDefinition def, boolean showDataSize, boolean ui) {
|
||||
final String cacheKey = def.instructionName + "|" + (showDataSize ? 1 : 0) + "|" + (ui ? 1 : 0);
|
||||
String v = docsCache.get(cacheKey);
|
||||
if (v != null) {
|
||||
return v;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String insName = def.instructionName;
|
||||
|
||||
String insShortDescription = getProperty("instruction." + insName + ".shortDescription");
|
||||
String insDescription = getProperty("instruction." + insName + ".description");
|
||||
String stackBefore = def.hasFlag(AVM2InstructionFlag.UNKNOWN_STACK) ? "" : getProperty("instruction." + insName + ".stackBefore");
|
||||
String stackAfter = def.hasFlag(AVM2InstructionFlag.UNKNOWN_STACK) ? "" : getProperty("instruction." + insName + ".stackAfter");
|
||||
if (stackBefore.trim().isEmpty()) {
|
||||
stackBefore = getProperty("ui.stack.before.empty");
|
||||
} else {
|
||||
stackBefore = getProperty("ui.stack.before") + stackBefore;
|
||||
}
|
||||
if (stackAfter.trim().isEmpty()) {
|
||||
stackAfter = getProperty("ui.stack.before.empty");
|
||||
} else {
|
||||
stackAfter = getProperty("ui.stack.before") + stackAfter;
|
||||
}
|
||||
String stack = def.hasFlag(AVM2InstructionFlag.UNKNOWN_STACK) ? getProperty("ui.unknown") : stackBefore + " => " + stackAfter;
|
||||
String operandsDoc = def.hasFlag(AVM2InstructionFlag.UNKNOWN_OPERANDS) ? getProperty("ui.unknown") : getProperty("instruction." + insName + ".operands");
|
||||
|
||||
sb.append(String.format("0x%02X", def.instructionCode)).append(" <font color=\"blue\"><b>").append(insName).append("</b></font>").append(" ");
|
||||
|
||||
if (def.hasFlag(AVM2InstructionFlag.UNKNOWN_OPERANDS)) {
|
||||
sb.append(getProperty("ui.unknown")).append(NEWLINE);
|
||||
} else {
|
||||
String[] operandsDocs = operandsDoc.split(", ?");
|
||||
boolean first = true;
|
||||
for (int i = 0; i < def.operands.length; i++) {
|
||||
int op = def.operands[i];
|
||||
String opDoc = operandsDocs[i];
|
||||
String operandTypeRaw = AVM2Code.operandTypeToString(op, false);
|
||||
String operandTypeCombined = AVM2Code.operandTypeToString(op, true);
|
||||
if (operandTypeCombined.contains(", ")) {
|
||||
String operandTypesCombined[] = operandTypeCombined.split(", ?");
|
||||
String operandTypesRaw[] = operandTypeRaw.split(", ?");
|
||||
|
||||
for (int j = 0; j < operandTypesCombined.length; j++) {
|
||||
if (!first) {
|
||||
sb.append(", ");
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
opDoc = operandsDocs[i + j];
|
||||
operandTypeCombined = operandTypesCombined[j];
|
||||
operandTypeRaw = operandTypesRaw[j];
|
||||
operandTypeRaw = getProperty("operandType." + operandTypeRaw + (ui ? ".uiName" : ".name"));
|
||||
if (opDoc.equals("...")) {
|
||||
sb.append("...");
|
||||
} else {
|
||||
sb.append(opDoc);
|
||||
sb.append(":").append(showDataSize ? operandTypeCombined : operandTypeRaw);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!first) {
|
||||
sb.append(", ");
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
operandTypeRaw = getProperty("operandType." + operandTypeRaw + (ui ? ".uiName" : ".name"));
|
||||
|
||||
if (opDoc.equals(operandTypeRaw)) {
|
||||
sb.append(showDataSize ? operandTypeCombined : operandTypeRaw);
|
||||
} else {
|
||||
sb.append(opDoc).append(":").append(showDataSize ? operandTypeCombined : operandTypeRaw);
|
||||
}
|
||||
}
|
||||
}
|
||||
sb.append(NEWLINE);
|
||||
}
|
||||
|
||||
sb.append(insShortDescription).append(NEWLINE);
|
||||
|
||||
if (!insDescription.trim().isEmpty()) {
|
||||
sb.append(insDescription).append(NEWLINE);
|
||||
}
|
||||
|
||||
sb.append("<b>").append(getProperty("ui.stack")).append("</b>").append(stack).append(NEWLINE);
|
||||
boolean flagsPrinted = false;
|
||||
|
||||
AVM2InstructionFlag flags[] = def.flags.clone();
|
||||
Arrays.sort(flags, Enum::compareTo);
|
||||
|
||||
for (AVM2InstructionFlag fl : flags) {
|
||||
if (fl != AVM2InstructionFlag.UNKNOWN_OPERANDS && fl != AVM2InstructionFlag.UNKNOWN_STACK) {
|
||||
if (!flagsPrinted) {
|
||||
flagsPrinted = true;
|
||||
sb.append("<b>").append(getProperty("ui.flags")).append("</b>").append(NEWLINE);
|
||||
}
|
||||
sb.append(getProperty("ui.flags.beginning")).append(flagDescriptions.get(fl)).append(NEWLINE);
|
||||
}
|
||||
}
|
||||
String r = sb.toString();
|
||||
docsCache.put(cacheKey, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
public static String getAllInstructionDocs() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String style = "li {list-style:none; padding:10px;border:1px solid black; border-bottom:none; border-collapse:collapse; } " + NEWLINE
|
||||
+ "ul {padding-left:0; display:table; border-bottom:1px solid black;}" + NEWLINE;
|
||||
|
||||
sb.append("<!DOCTYPE html>").append(NEWLINE).
|
||||
append("<html>").append(NEWLINE).
|
||||
append("<head>").append(NEWLINE).
|
||||
append("<style>").append(style).append("</style>").append(NEWLINE).
|
||||
append("<meta charset=\"UTF-8\">").append(NEWLINE).
|
||||
append("<title>").append(getProperty("ui.list.pageTitle")).append("</title>").append(NEWLINE).
|
||||
append("</head>").append(NEWLINE).
|
||||
append("<body>").append(NEWLINE);
|
||||
sb.append("<h1>").append(getProperty("ui.list.heading")).append("</h1>").append(NEWLINE);
|
||||
sb.append("<ul>").append(NEWLINE);
|
||||
Set<String> s = new TreeSet<>(nameToDef.keySet());
|
||||
for (String name : s) {
|
||||
InstructionDefinition def = nameToDef.get(name);
|
||||
if (def == null) {
|
||||
continue;
|
||||
}
|
||||
sb.append("<li>").append(NEWLINE);
|
||||
sb.append(getDocsForIns(def, true, false).replace(NEWLINE, "<br />" + NEWLINE));
|
||||
sb.append("</li>").append(NEWLINE);
|
||||
}
|
||||
sb.append("</ul>").append(NEWLINE);
|
||||
sb.append("</body>").append(NEWLINE);
|
||||
sb.append("</html>").append(NEWLINE);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(getAllInstructionDocs());
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,20 @@
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library.
|
||||
|
||||
#String for whole list generation
|
||||
ui.list.heading = AVM2 Instruction list
|
||||
ui.list.pageTitle = AVM2 Instruction list
|
||||
|
||||
#various strings in UI:
|
||||
ui.unknown = ???
|
||||
ui.stack = Stack:\u0020
|
||||
ui.stack.before = ...,\u0020
|
||||
ui.stack.before.empty = ...
|
||||
ui.flags = Flags:\u0020
|
||||
ui.flags.beginning = \u0020-\u0020
|
||||
|
||||
|
||||
#----------------------- Flags of the instructions
|
||||
instructionFlag.undocumented = Undocumented
|
||||
instructionFlag.unknownStack = Unknown stack
|
||||
instructionFlag.es4NumericsMinor = ES4 numerics (ABC minor 17)
|
||||
@@ -21,83 +35,133 @@ instructionFlag.unknownOperands = Unknown operands
|
||||
instructionFlag.noFlashPlayer = Not in standard Flash Player
|
||||
instructionFlag.deprecated = Deprecated
|
||||
instructionFlag.domainMemory = Domain memory operation
|
||||
instructionFlag. =
|
||||
instructionFlag. =
|
||||
|
||||
|
||||
|
||||
#----------------------- Operand types
|
||||
operandType.multinameIndex = Multiname index
|
||||
operandType.multinameIndex.description = Index into multiname constant pool
|
||||
operandType.multinameIndex.name = multinameIndex
|
||||
operandType.multinameIndex.uiName = multiname
|
||||
|
||||
operandType.argCount = Number of arguments
|
||||
operandType.argCount.description = Number of following arguments
|
||||
operandType.argCount.name = argCount
|
||||
operandType.argCount.uiName = uint
|
||||
|
||||
|
||||
operandType.methodIndex = Method index
|
||||
operandType.methodIndex.description = Index of method in the ABC
|
||||
operandType.methodIndex.name = methodIndex
|
||||
operandType.methodIndex.uiName = methodIndex
|
||||
|
||||
operandType.stringIndex = String index
|
||||
operandType.stringIndex.description = Index into string values constant pool
|
||||
operandType.stringIndex.name = stringIndex
|
||||
operandType.stringIndex.uiName = string
|
||||
|
||||
|
||||
operandType.debugType = Debug type
|
||||
operandType.debugType.description = Type of debug information. Currently only value of 1 is used.
|
||||
operandType.debugType.name = debugType
|
||||
operandType.debugType.uiName = debugType
|
||||
|
||||
|
||||
operandType.registerIndex = Register index
|
||||
operandType.registerIndex.description = Index of a local register (0-255)
|
||||
operandType.registerIndex.name = registerIndex
|
||||
operandType.registerIndex.uiName = uint
|
||||
|
||||
operandType.linenum = Line number
|
||||
operandType.linenum.description = Line number of file
|
||||
operandType.linenum.name = linenum
|
||||
operandType.linenum.uiName = linenum
|
||||
|
||||
|
||||
#similar as registerIndex, but U30 instead of U8
|
||||
operandType.localRegIndex = Register index
|
||||
operandType.localRegIndex.description = Index of a local register
|
||||
operandType.localRegIndex.name = localRegIndex
|
||||
operandType.localRegIndex.uiName = uint
|
||||
|
||||
|
||||
operandType.slotIndex = Slot index
|
||||
operandType.slotIndex.description = Index of the slot on an object
|
||||
operandType.slotIndex.name = slotIndex
|
||||
operandType.slotIndex.uiName = slotIndex
|
||||
|
||||
operandType.scopeIndex = Scope stack index
|
||||
operandType.scopeIndex.description = Index in the scope stack
|
||||
operandType.scopeIndex.name = scopeIndex
|
||||
operandType.scopeIndex.uiName = scopeIndex
|
||||
|
||||
operandType.offset = Offset
|
||||
operandType.offset.description = Offset to other location
|
||||
operandType.offset.name = offset
|
||||
operandType.offset.uiName = labelName
|
||||
|
||||
operandType.exceptionIndex = Exception index
|
||||
operandType.exceptionIndex.description = Index of exception in current method info
|
||||
operandType.exceptionIndex.name = exceptionIndex
|
||||
operandType.exceptionIndex.uiName = exceptionIndex
|
||||
|
||||
|
||||
operandType.classIndex = Class index
|
||||
operandType.classIndex.description = Index of class in ABC
|
||||
operandType.classIndex.name = classIndex
|
||||
operandType.classIndex.uiName = classIndex
|
||||
|
||||
operandType.intIndex = Int index
|
||||
operandType.intIndex.description = Index into integer values constant pool
|
||||
operandType.intIndex.name = intIndex
|
||||
operandType.intIndex.uiName = int
|
||||
|
||||
operandType.uintIndex = UInt index
|
||||
operandType.uintIndex.description = Index into unsigned integer values constant pool
|
||||
operandType.uintIndex.name = uintIndex
|
||||
operandType.uintIndex.uiName = uint
|
||||
|
||||
|
||||
operandType.doubleIndex = Double index
|
||||
operandType.doubleIndex.description = Index into double precision floating point values constant pool
|
||||
operandType.doubleIndex.name = doubleIndex
|
||||
operandType.doubleIndex.uiName = double
|
||||
|
||||
operandType.decimalIndex = Decimal index
|
||||
operandType.decimalIndex.description = Index into decimal values (128bit floating point) constant pool (EcmaScript 4 numerics - ABC minorVersion 17)
|
||||
operandType.decimalIndex.description = Index into decimal values (128bit floating point) constant pool
|
||||
operandType.decimalIndex.name = decimalIndex
|
||||
operandType.decimalIndex.uiName = decimal
|
||||
|
||||
operandType.caseBaseoffset = Base offset
|
||||
operandType.caseBaseoffset.description = Base offset of lookupswitch triggered when no value matches
|
||||
operandType.caseBaseoffset.name = offset
|
||||
operandType.caseBaseoffset.uiName = labelName
|
||||
|
||||
operandType.numberContext = Number context (ES4)
|
||||
operandType.numberContext.description = Context of calculations when using EcmaScript 4 numerics (ABC minorVersion 17).\nBits 0-2 type,3-5 rounding type, 6-12 precision.\nType: 0=number,1=decimal,2=double,3=int,4=uint\nRounding: 0=ceiling,1=up,2=half_up,3=half_even,4=half_down,5=down,6=floor\nPrecision:0-34
|
||||
|
||||
operandType.multinameIndex = Multiname index
|
||||
operandType.multinameIndex.description = Index into multiname constant pool
|
||||
operandType.numberContext.name = numberContext
|
||||
operandType.numberContext.uiName = uint
|
||||
|
||||
operandType.dispatchId = Dispatch id
|
||||
operandType.dispatchId.description = Id of the method dispatch
|
||||
operandType.dispatchId.name = dispatchId
|
||||
operandType.dispatchId.uiName = uint
|
||||
|
||||
operandType.floatIndex = Float index
|
||||
operandType.floatIndex.description = Index into float values constant pool (Only some ABC versions)
|
||||
operandType.floatIndex.description = Index into float values constant pool
|
||||
operandType.floatIndex.name = floatIndex
|
||||
operandType.floatIndex.uiName = float
|
||||
|
||||
operandType.float4Index = Float4 index
|
||||
operandType.float4Index.description = Index into float4 values constant pool (Only some ABC versions)
|
||||
operandType.float4Index.description = Index into float4 values constant pool
|
||||
operandType.float4Index.name = float4Index
|
||||
operandType.float4Index.uiName = float4
|
||||
|
||||
operandType.namespaceIndex = Namespace index
|
||||
operandType.namespaceIndex = Index into namespace constant pool
|
||||
operandType.namespaceIndex.name = namespaceIndex
|
||||
operandType.namespaceIndex.uiName = namespace
|
||||
|
||||
|
||||
#----------------------- Instructions
|
||||
|
||||
instruction.bkpt.shortDescription = Breakpoint
|
||||
instruction.bkpt.description = Breakpoint when debugging
|
||||
@@ -512,7 +576,7 @@ instruction.callproperty.shortDescription = Call property
|
||||
instruction.callproperty.description =
|
||||
instruction.callproperty.stackBefore = obj, [ns], [name], arg1, ..., argN
|
||||
instruction.callproperty.stackAfter = value
|
||||
instruction.callproperty.operands = propertyName, argCount
|
||||
instruction.callproperty.operands = property, argCount
|
||||
|
||||
instruction.returnvoid.shortDescription = Return from a method
|
||||
instruction.returnvoid.description =
|
||||
@@ -536,7 +600,7 @@ instruction.constructprop.shortDescription = Construct a property of an object
|
||||
instruction.constructprop.description =
|
||||
instruction.constructprop.stackBefore = obj, [ns], [name], arg1, ..., argN
|
||||
instruction.constructprop.stackAfter = value
|
||||
instruction.constructprop.operands = propertyName, argCount
|
||||
instruction.constructprop.operands = property, argCount
|
||||
|
||||
#Undocumented:
|
||||
instruction.callsuperid.shortDescription = Call super id
|
||||
@@ -549,7 +613,7 @@ instruction.callproplex.shortDescription = Call property with null as this
|
||||
instruction.callproplex.description =
|
||||
instruction.callproplex.stackBefore = obj, [ns], [name], arg1, ..., argN
|
||||
instruction.callproplex.stackAfter = value
|
||||
instruction.callproplex.operands = propertyName, argCount
|
||||
instruction.callproplex.operands = property, argCount
|
||||
|
||||
#Undocumented:
|
||||
instruction.callinterface.shortDescription = Call interface
|
||||
@@ -570,7 +634,7 @@ instruction.callpropvoid.shortDescription = Call property, discard return value
|
||||
instruction.callpropvoid.description =
|
||||
instruction.callpropvoid.stackBefore = obj, [ns], [name], arg1, ..., argN
|
||||
instruction.callpropvoid.stackAfter = value
|
||||
instruction.callpropvoid.operands = propertyName, argCount
|
||||
instruction.callpropvoid.operands = property, argCount
|
||||
|
||||
instruction.sxi1.shortDescription = Sign extend 1bit value to 32bits
|
||||
instruction.sxi1.description =
|
||||
@@ -687,13 +751,13 @@ instruction.getlocal.shortDescription = Get local register value
|
||||
instruction.getlocal.description =
|
||||
instruction.getlocal.stackBefore =
|
||||
instruction.getlocal.stackAfter = value
|
||||
instruction.getlocal.operands = localReg
|
||||
instruction.getlocal.operands = localRegIndex
|
||||
|
||||
instruction.setlocal.shortDescription = Set local register value
|
||||
instruction.setlocal.description =
|
||||
instruction.setlocal.stackBefore = value
|
||||
instruction.setlocal.stackAfter =
|
||||
instruction.setlocal.operands = localReg
|
||||
instruction.setlocal.operands = localRegIndex
|
||||
|
||||
instruction.getglobalscope.shortDescription = Get global scope
|
||||
instruction.getglobalscope.description =
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
# 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.
|
||||
|
||||
#String for whole list generation
|
||||
ui.list.heading = Seznam AVM2 instrukc\u00ed
|
||||
ui.list.pageTitle = Seznam AVM2 instrukc\u00ed
|
||||
|
||||
#various strings in UI:
|
||||
ui.unknown = ???
|
||||
ui.stack = Z\u00e1sobn\u00edk:\u0020
|
||||
ui.stack.before = ...,\u0020
|
||||
ui.stack.before.empty = ...
|
||||
ui.flags = P\u0159\u00edznaky:\u0020
|
||||
ui.flags.beginning = \u0020-\u0020
|
||||
|
||||
|
||||
#----------------------- Flags of the instructions
|
||||
instructionFlag.undocumented = Nedokumentovan\u00e9
|
||||
instructionFlag.unknownStack = Nezn\u00e1m\u00fd z\u00e1sobn\u00edk
|
||||
instructionFlag.es4NumericsMinor = ES4 numerika (ABC minor 17)
|
||||
instructionFlag.floatMajor = Float hodnoty (ABC major 47)
|
||||
instructionFlag.unknownOperands = Nezn\u00e1me operandy
|
||||
instructionFlag.noFlashPlayer = Nen\u00ed v standardn\u00edm Flash Playeru
|
||||
instructionFlag.deprecated = P\u0159ekonan\u00e9
|
||||
instructionFlag.domainMemory = Operace s dom\u00e9novou pam\u011bt\u00ed
|
||||
|
||||
#----------------------- Operand types
|
||||
operandType.multinameIndex = Index multiname
|
||||
operandType.multinameIndex.description = Index do seznamu multiname konstant
|
||||
operandType.multinameIndex.name = multinameIndex
|
||||
operandType.multinameIndex.uiName = multiname
|
||||
|
||||
operandType.argCount = Po\u010det argument\u016f
|
||||
operandType.argCount.description = Po\u010det argument\u016f, kter\u00e9 n\u00e1sleduj\u00ed
|
||||
operandType.argCount.name = argCount
|
||||
operandType.argCount.uiName = uint
|
||||
|
||||
|
||||
operandType.methodIndex = Index metody
|
||||
operandType.methodIndex.description = Index metody v ABC
|
||||
operandType.methodIndex.name = methodIndex
|
||||
operandType.methodIndex.uiName = methodIndex
|
||||
|
||||
operandType.stringIndex = Index \u0159et\u011bzce
|
||||
operandType.stringIndex.description = Index do seznamu \u0159et\u011bzcov\u00fdch konstant
|
||||
operandType.stringIndex.name = stringIndex
|
||||
operandType.stringIndex.uiName = string
|
||||
|
||||
|
||||
operandType.debugType = Typ lad\u011bn\u00ed
|
||||
operandType.debugType.description = Typ lad\u00edc\u00ed informace. Moment\u00e1ln\u011b je pou\u017eita pouze hodnota 1.
|
||||
operandType.debugType.name = debugType
|
||||
operandType.debugType.uiName = debugType
|
||||
|
||||
|
||||
operandType.registerIndex = Index registru
|
||||
operandType.registerIndex.description = Index lok\u00e1ln\u00edho registru (0-255)
|
||||
operandType.registerIndex.name = registerIndex
|
||||
operandType.registerIndex.uiName = uint
|
||||
|
||||
operandType.linenum = \u010c\u00edslo \u0159\u00e1dku
|
||||
operandType.linenum.description = \u010c\u00edslo \u0159\u00e1dku v souboru
|
||||
operandType.linenum.name = linenum
|
||||
operandType.linenum.uiName = linenum
|
||||
|
||||
|
||||
#similar as registerIndex, but U30 instead of U8
|
||||
operandType.localRegIndex = Index registru
|
||||
operandType.localRegIndex.description = Index lok\u00e1ln\u00edho registru
|
||||
operandType.localRegIndex.name = localRegIndex
|
||||
operandType.localRegIndex.uiName = uint
|
||||
|
||||
|
||||
operandType.slotIndex = Index slotu
|
||||
operandType.slotIndex.description = Index slotu v objektu
|
||||
operandType.slotIndex.name = slotIndex
|
||||
operandType.slotIndex.uiName = slotIndex
|
||||
|
||||
operandType.scopeIndex = Index na scope z\u00e1sobn\u00edku
|
||||
operandType.scopeIndex.description = Index na scope z\u00e1sobn\u00edku
|
||||
operandType.scopeIndex.name = scopeIndex
|
||||
operandType.scopeIndex.uiName = scopeIndex
|
||||
|
||||
operandType.offset = Ofset
|
||||
operandType.offset.description = Ofset na jinou pozici
|
||||
operandType.offset.name = ofset
|
||||
operandType.offset.uiName = n\u00e1zevLabelu
|
||||
|
||||
operandType.exceptionIndex = Index v\u00fdjimky
|
||||
operandType.exceptionIndex.description = Index v\u00fdjimky v aktu\u00e1ln\u00edm methodinfo
|
||||
operandType.exceptionIndex.name = exceptionIndex
|
||||
operandType.exceptionIndex.uiName = exceptionIndex
|
||||
|
||||
|
||||
operandType.classIndex = Index t\u0159\u00eddy
|
||||
operandType.classIndex.description = Index t\u0159\u00eddy v ABC
|
||||
operandType.classIndex.name = classIndex
|
||||
operandType.classIndex.uiName = classIndex
|
||||
|
||||
operandType.intIndex = Index int
|
||||
operandType.intIndex.description = Index do seznamu cel\u00fdch int \u010d\u00edsel
|
||||
operandType.intIndex.name = intIndex
|
||||
operandType.intIndex.uiName = int
|
||||
|
||||
operandType.uintIndex = Inde uint
|
||||
operandType.uintIndex.description = Index do seznamu int \u010d\u00edsel bez znam\u00e9nka
|
||||
operandType.uintIndex.name = uintIndex
|
||||
operandType.uintIndex.uiName = uint
|
||||
|
||||
|
||||
operandType.doubleIndex = Index double
|
||||
operandType.doubleIndex.description = Index do seznamu double \u010d\u00edsel
|
||||
operandType.doubleIndex.name = doubleIndex
|
||||
operandType.doubleIndex.uiName = double
|
||||
|
||||
operandType.decimalIndex = Index decimal
|
||||
operandType.decimalIndex.description = Index do seznamu decimal \u010d\u00edsel (128bit \u010d\u00edsla se znam\u00e9nkem)
|
||||
operandType.decimalIndex.name = decimalIndex
|
||||
operandType.decimalIndex.uiName = decimal
|
||||
|
||||
operandType.caseBaseoffset = Z\u00e1kladn\u00ed ofset
|
||||
operandType.caseBaseoffset.description = Z\u00e1kladn\u00ed ofset lookupswitche spu\u0161ten\u00fd kdy\u017e \u017e\u00e1dn\u00e1 hodnota neodpov\u00edd\u00e1
|
||||
operandType.caseBaseoffset.name = ofset
|
||||
operandType.caseBaseoffset.uiName = n\u00e1zevLabelu
|
||||
|
||||
operandType.numberContext = \u010c\u00edseln\u00fd kontext (ES4)
|
||||
operandType.numberContext.description = Kontext v\u00fdpo\u010dt\u016f p\u0159i pou\u017e\u00edv\u00e1n\u00ed EcmaScript 4 numeriky (ABC minorVersion 17).\nBity 0-2 typ,3-5 typ zaokrouhlen\u00ed, 6-12 p\u0159esnost.\nTyp: 0=number,1=decimal,2=double,3=int,4=uint\nZaokrouhlen\u00ed: 0=ceiling,1=up,2=half_up,3=half_even,4=half_down,5=down,6=floor\nP\u0159esnost:0-34
|
||||
operandType.numberContext.name = \u010d\u00edseln\u00fdKontext
|
||||
operandType.numberContext.uiName = uint
|
||||
|
||||
operandType.dispatchId = Dispatch id
|
||||
operandType.dispatchId.description = Dispatch id metody
|
||||
operandType.dispatchId.name = dispatchId
|
||||
operandType.dispatchId.uiName = uint
|
||||
|
||||
operandType.floatIndex = Index float
|
||||
operandType.floatIndex.description = Index do seznamu float hodnot
|
||||
operandType.floatIndex.name = floatIndex
|
||||
operandType.floatIndex.uiName = float
|
||||
|
||||
operandType.float4Index = Index float4
|
||||
operandType.float4Index.description = Index do seznamu float4 hodnot
|
||||
operandType.float4Index.name = float4Index
|
||||
operandType.float4Index.uiName = float4
|
||||
|
||||
operandType.namespaceIndex = Index namespace
|
||||
operandType.namespaceIndex = Index do seznamu namespace
|
||||
operandType.namespaceIndex.name = namespaceIndex
|
||||
operandType.namespaceIndex.uiName = namespace
|
||||
|
||||
|
||||
#----------------------- Instructions
|
||||
#TODO... maybe(?)
|
||||
@@ -1,171 +0,0 @@
|
||||
package com.jpexs.decompiler.flash.locales.docs.pcode;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2InstructionFlag;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
|
||||
import com.jpexs.helpers.Cache;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Generator for AVM2 instruction set documentation. TODO: use this somehow in
|
||||
* GUI
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class As3Docs {
|
||||
|
||||
private static Properties prop;
|
||||
private static Map<AVM2InstructionFlag, String> flagDescriptions = new HashMap<>();
|
||||
|
||||
private static Cache<String, String> docsCache = Cache.getInstance(false, true, "as3DocsCache");
|
||||
private static Map<String, InstructionDefinition> nameToDef = new HashMap<>();
|
||||
|
||||
static {
|
||||
prop = new Properties();
|
||||
try {
|
||||
prop.load(As3Docs.class.getClassLoader().getResourceAsStream("com/jpexs/decompiler/flash/locales/docs/pcode/AS3.properties"));
|
||||
} catch (IOException e) {
|
||||
//ignore
|
||||
}
|
||||
|
||||
for (InstructionDefinition def : AVM2Code.allInstructionSet) {
|
||||
if (def == null) {
|
||||
continue;
|
||||
}
|
||||
nameToDef.put(def.instructionName, def);
|
||||
}
|
||||
|
||||
for (AVM2InstructionFlag flg : AVM2InstructionFlag.values()) {
|
||||
String flagIdent = makeIdent(flg.toString());
|
||||
String flagDescription = prop.getProperty("instructionFlag." + flagIdent);
|
||||
flagDescriptions.put(flg, flagDescription);
|
||||
}
|
||||
}
|
||||
|
||||
private static String makeIdent(String name) {
|
||||
StringBuilder identName = new StringBuilder();
|
||||
boolean cap = false;
|
||||
for (int i = 0; i < name.length(); i++) {
|
||||
char c = name.charAt(i);
|
||||
if (c == '_') {
|
||||
cap = true;
|
||||
continue;
|
||||
}
|
||||
if (cap) {
|
||||
identName.append(c);
|
||||
cap = false;
|
||||
} else {
|
||||
identName.append(Character.toLowerCase(c));
|
||||
}
|
||||
}
|
||||
return identName.toString();
|
||||
}
|
||||
|
||||
public static String getDocsForIns(String insName) {
|
||||
if (!nameToDef.containsKey(insName)) {
|
||||
return null;
|
||||
}
|
||||
return getDocsForIns(nameToDef.get(insName));
|
||||
}
|
||||
|
||||
public static String getDocsForIns(InstructionDefinition def) {
|
||||
String v = docsCache.get(def.instructionName);
|
||||
if (v != null) {
|
||||
return v;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String insName = def.instructionName;
|
||||
final String NEWLINE = "\r\n";
|
||||
|
||||
String insShortDescription = prop.getProperty("instruction." + insName + ".shortDescription");
|
||||
String insDescription = prop.getProperty("instruction." + insName + ".description");
|
||||
String stackBefore = def.hasFlag(AVM2InstructionFlag.UNKNOWN_STACK) ? "???" : prop.getProperty("instruction." + insName + ".stackBefore");
|
||||
String stackAfter = def.hasFlag(AVM2InstructionFlag.UNKNOWN_STACK) ? "???" : prop.getProperty("instruction." + insName + ".stackAfter");
|
||||
String operandsDoc = def.hasFlag(AVM2InstructionFlag.UNKNOWN_OPERANDS) ? "???" : prop.getProperty("instruction." + insName + ".operands");
|
||||
|
||||
sb.append(String.format("0x%02X", def.instructionCode)).append(" <font color=\"blue\"><b>").append(insName).append("</b></font>: ").append(insShortDescription).append(NEWLINE);
|
||||
|
||||
if (!insDescription.trim().isEmpty()) {
|
||||
sb.append("<b>Description:</b> ").append(insDescription).append(NEWLINE);
|
||||
}
|
||||
sb.append("<b>Stack before:</b> ").append(stackBefore).append(NEWLINE);
|
||||
sb.append("<b>Stack after:</b> ").append(stackAfter).append(NEWLINE);
|
||||
boolean flagsPrinted = false;
|
||||
|
||||
sb.append("<b>Operands:</b> ");
|
||||
|
||||
if (def.hasFlag(AVM2InstructionFlag.UNKNOWN_OPERANDS)) {
|
||||
sb.append("???").append(NEWLINE);
|
||||
} else {
|
||||
String[] operandsDocs = operandsDoc.split(", ?");
|
||||
boolean first = true;
|
||||
for (int i = 0; i < def.operands.length; i++) {
|
||||
int op = def.operands[i];
|
||||
String opDoc = operandsDocs[i];
|
||||
String operandTypeRaw = AVM2Code.operandTypeToString(op, false);
|
||||
String operandTypeCombined = AVM2Code.operandTypeToString(op, true);
|
||||
if (operandTypeCombined.contains(", ")) {
|
||||
String operandTypesCombined[] = operandTypeCombined.split(", ?");
|
||||
for (int j = 0; j < operandTypesCombined.length; j++) {
|
||||
if (!first) {
|
||||
sb.append(", ");
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
opDoc = operandsDocs[i + j];
|
||||
operandTypeCombined = operandTypesCombined[j];
|
||||
if (opDoc.equals("...")) {
|
||||
sb.append("...");
|
||||
} else {
|
||||
sb.append(opDoc).append(":").append(operandTypeCombined);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!first) {
|
||||
sb.append(", ");
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
if (opDoc.equals(operandTypeRaw)) {
|
||||
sb.append(operandTypeCombined);
|
||||
} else {
|
||||
sb.append(opDoc).append(":").append(operandTypeCombined);
|
||||
}
|
||||
}
|
||||
}
|
||||
sb.append(NEWLINE);
|
||||
}
|
||||
|
||||
AVM2InstructionFlag flags[] = def.flags.clone();
|
||||
Arrays.sort(flags, Enum::compareTo);
|
||||
|
||||
for (AVM2InstructionFlag fl : flags) {
|
||||
if (fl != AVM2InstructionFlag.UNKNOWN_OPERANDS && fl != AVM2InstructionFlag.UNKNOWN_STACK) {
|
||||
if (!flagsPrinted) {
|
||||
flagsPrinted = true;
|
||||
sb.append("Flags:").append(NEWLINE);
|
||||
}
|
||||
sb.append(" - ").append(flagDescriptions.get(fl)).append(NEWLINE);
|
||||
}
|
||||
}
|
||||
String r = sb.toString();
|
||||
docsCache.put(def.instructionName, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
|
||||
for (InstructionDefinition def : AVM2Code.allInstructionSet) {
|
||||
if (def == null) {
|
||||
continue;
|
||||
}
|
||||
System.out.println("=========================");
|
||||
System.out.print(getDocsForIns(def));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user