From ab7c3344a21575af379d66b9b35ff0e6a06f4e07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sun, 27 Mar 2016 14:51:39 +0200 Subject: [PATCH] Display AS3 p-code docs in GUI, improvements. --- .../decompiler/flash/abc/avm2/AVM2Code.java | 4 +- .../avm2/instructions/other2/AbsJumpIns.java | 2 +- .../flash/configuration/Configuration.java | 5 +- .../decompiler/flash/docs/As3PCodeDocs.java | 220 ++++++++++++++++++ .../flash/locales/docs/pcode/AS3.properties | 96 ++++++-- .../locales/docs/pcode/AS3_cs.properties | 165 +++++++++++++ .../flash/locales/docs/pcode/As3Docs.java | 171 -------------- .../gui/{DocsWindow.java => DocsPanel.java} | 35 +-- .../flash/gui/abc/ASMSourceEditorPane.java | 15 +- .../flash/gui/abc/MethodCodePanel.java | 15 +- 10 files changed, 496 insertions(+), 232 deletions(-) create mode 100644 libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/docs/As3PCodeDocs.java create mode 100644 libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/docs/pcode/AS3_cs.properties delete mode 100644 libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/docs/pcode/As3Docs.java rename src/com/jpexs/decompiler/flash/gui/{DocsWindow.java => DocsPanel.java} (62%) diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java index b1b6b7fa7..41b3c7a01 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java @@ -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())); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other2/AbsJumpIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other2/AbsJumpIns.java index 0ba4d0901..b575ae6af 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other2/AbsJumpIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other2/AbsJumpIns.java @@ -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 diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java index 380b92ba7..3c684c7eb 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java @@ -598,9 +598,10 @@ public class Configuration { @ConfigurationInternal public static final ConfigurationItem hwAcceleratedGraphics = null; - @ConfigurationDefaultBoolean(false) + @ConfigurationDefaultDouble(0.85) + @ConfigurationName("gui.avm2.splitPane.docs.dividerLocationPercent") @ConfigurationInternal - public static final ConfigurationItem as3pcodeDocWindow = null; + public static final ConfigurationItem guiAvm2DocsSplitPaneDividerLocationPercent = null; private enum OSId { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/docs/As3PCodeDocs.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/docs/As3PCodeDocs.java new file mode 100644 index 000000000..1ca24126b --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/docs/As3PCodeDocs.java @@ -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 flagDescriptions = new HashMap<>(); + + private static Cache docsCache = Cache.getInstance(false, true, "as3DocsCache"); + private static Map 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(" ").append(insName).append("").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("").append(getProperty("ui.stack")).append("").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("").append(getProperty("ui.flags")).append("").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("").append(NEWLINE). + append("").append(NEWLINE). + append("").append(NEWLINE). + append("").append(NEWLINE). + append("").append(NEWLINE). + append("").append(getProperty("ui.list.pageTitle")).append("").append(NEWLINE). + append("").append(NEWLINE). + append("").append(NEWLINE); + sb.append("

").append(getProperty("ui.list.heading")).append("

").append(NEWLINE); + sb.append("
    ").append(NEWLINE); + Set s = new TreeSet<>(nameToDef.keySet()); + for (String name : s) { + InstructionDefinition def = nameToDef.get(name); + if (def == null) { + continue; + } + sb.append("
  • ").append(NEWLINE); + sb.append(getDocsForIns(def, true, false).replace(NEWLINE, "
    " + NEWLINE)); + sb.append("
  • ").append(NEWLINE); + } + sb.append("
").append(NEWLINE); + sb.append("").append(NEWLINE); + sb.append("").append(NEWLINE); + return sb.toString(); + } + + public static void main(String[] args) { + System.out.println(getAllInstructionDocs()); + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/docs/pcode/AS3.properties b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/docs/pcode/AS3.properties index f69f292b0..f3720c41a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/docs/pcode/AS3.properties +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/docs/pcode/AS3.properties @@ -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 = diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/docs/pcode/AS3_cs.properties b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/docs/pcode/AS3_cs.properties new file mode 100644 index 000000000..e8aa78156 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/docs/pcode/AS3_cs.properties @@ -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(?) \ No newline at end of file diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/docs/pcode/As3Docs.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/docs/pcode/As3Docs.java deleted file mode 100644 index 16c766e74..000000000 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/docs/pcode/As3Docs.java +++ /dev/null @@ -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 flagDescriptions = new HashMap<>(); - - private static Cache docsCache = Cache.getInstance(false, true, "as3DocsCache"); - private static Map 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(" ").append(insName).append(": ").append(insShortDescription).append(NEWLINE); - - if (!insDescription.trim().isEmpty()) { - sb.append("Description: ").append(insDescription).append(NEWLINE); - } - sb.append("Stack before: ").append(stackBefore).append(NEWLINE); - sb.append("Stack after: ").append(stackAfter).append(NEWLINE); - boolean flagsPrinted = false; - - sb.append("Operands: "); - - 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)); - } - } -} diff --git a/src/com/jpexs/decompiler/flash/gui/DocsWindow.java b/src/com/jpexs/decompiler/flash/gui/DocsPanel.java similarity index 62% rename from src/com/jpexs/decompiler/flash/gui/DocsWindow.java rename to src/com/jpexs/decompiler/flash/gui/DocsPanel.java index b9f24c4d7..5d3cd1905 100644 --- a/src/com/jpexs/decompiler/flash/gui/DocsWindow.java +++ b/src/com/jpexs/decompiler/flash/gui/DocsPanel.java @@ -25,6 +25,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JEditorPane; import javax.swing.JFrame; +import javax.swing.JPanel; import javax.swing.JRootPane; import javax.swing.JScrollPane; @@ -32,47 +33,27 @@ import javax.swing.JScrollPane; * * @author JPEXS */ -public class DocsWindow extends JFrame implements DocsListener { +public class DocsPanel extends JPanel implements DocsListener { private JEditorPane textDisplay = new JEditorPane(); + //TODO: Make this use skin somehow (?) + public static final Color HINT_COLOR = new Color(245, 245, 181); - public DocsWindow() { - setAlwaysOnTop(true); - setSize(500, 250); - setTitle("-"); - getContentPane().setLayout(new BorderLayout()); - getContentPane().add(new JScrollPane(textDisplay), BorderLayout.CENTER); + public DocsPanel() { + setLayout(new BorderLayout()); + add(new JScrollPane(textDisplay), BorderLayout.CENTER); textDisplay.setContentType("text/html"); - setAutoRequestFocus(false); textDisplay.setFocusable(false); - View.setWindowIcon(this); - this.getRootPane().setWindowDecorationStyle(JRootPane.PLAIN_DIALOG); - textDisplay.setBackground(Color.white); + textDisplay.setBackground(HINT_COLOR); } @Override public void docs(String identifier, String docs, Point screenLocation) { - setTitle(identifier); textDisplay.setText(docs.replace("\r\n", "
")); - if (screenLocation != null) { - setLocation(screenLocation); - } - - setFocusableWindowState(false); - setVisible(true); - View.execInEventDispatchLater(new Runnable() { - @Override - public void run() { - setFocusableWindowState(true); - } - }); - } @Override public void noDocs() { - setVisible(false); - setTitle("-"); textDisplay.setText(""); } diff --git a/src/com/jpexs/decompiler/flash/gui/abc/ASMSourceEditorPane.java b/src/com/jpexs/decompiler/flash/gui/abc/ASMSourceEditorPane.java index d79622b58..f12baec3f 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/ASMSourceEditorPane.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/ASMSourceEditorPane.java @@ -38,7 +38,7 @@ import com.jpexs.decompiler.flash.helpers.HighlightedText; import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter; import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType; import com.jpexs.decompiler.flash.helpers.hilight.Highlighting; -import com.jpexs.decompiler.flash.locales.docs.pcode.As3Docs; +import com.jpexs.decompiler.flash.docs.As3PCodeDocs; import com.jpexs.decompiler.flash.tags.ABCContainerTag; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.graph.ScopeStack; @@ -158,7 +158,7 @@ public class ASMSourceEditorPane extends DebuggableEditorPane implements CaretLi public ASMSourceEditorPane(DecompiledEditorPane decompiledEditor) { this.decompiledEditor = decompiledEditor; addCaretListener(this); - for (InstructionDefinition def : AVM2Code.instructionSet) { + for (InstructionDefinition def : AVM2Code.allInstructionSet) { if (def != null) { insNameToDef.put(def.instructionName, def); } @@ -419,7 +419,7 @@ public class ASMSourceEditorPane extends DebuggableEditorPane implements CaretLi } } - public void caretUpdateEdit(CaretEvent e) { + public void updateDocs() { String curLine = getCurrentLineText(); if (curLine == null) { @@ -444,7 +444,7 @@ public class ASMSourceEditorPane extends DebuggableEditorPane implements CaretLi if (loc != null) { SwingUtilities.convertPointToScreen(loc, this); } - fireDocs(insName, As3Docs.getDocsForIns(insName), loc); + fireDocs(insName, As3PCodeDocs.getDocsForIns(insName, false, true), loc); } else { fireNoDocs(); } @@ -452,11 +452,12 @@ public class ASMSourceEditorPane extends DebuggableEditorPane implements CaretLi @Override public void caretUpdate(CaretEvent e) { - if (isEditable()) { - caretUpdateEdit(e); + updateDocs(); + + if (ignoreCarret) { return; } - if (ignoreCarret) { + if (isEditable()) { return; } getCaret().setVisible(true); diff --git a/src/com/jpexs/decompiler/flash/gui/abc/MethodCodePanel.java b/src/com/jpexs/decompiler/flash/gui/abc/MethodCodePanel.java index 84188b925..da7b0ca57 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/MethodCodePanel.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/MethodCodePanel.java @@ -21,9 +21,10 @@ import com.jpexs.decompiler.flash.abc.types.traits.Trait; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; import com.jpexs.decompiler.flash.gui.AppStrings; -import com.jpexs.decompiler.flash.gui.DocsWindow; +import com.jpexs.decompiler.flash.gui.DocsPanel; import com.jpexs.decompiler.flash.gui.Main; import com.jpexs.decompiler.flash.gui.View; +import com.jpexs.decompiler.flash.gui.controls.JPersistentSplitPane; import com.jpexs.decompiler.flash.gui.controls.NoneSelectedButtonGroup; import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType; import java.awt.BorderLayout; @@ -36,6 +37,7 @@ import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JPanel; import javax.swing.JScrollPane; +import javax.swing.JSplitPane; import javax.swing.JToggleButton; /** @@ -51,7 +53,7 @@ public class MethodCodePanel extends JPanel { private final JToggleButton hexButton; private final JToggleButton hexOnlyButton; - private final DocsWindow docsWindow; + private final DocsPanel docsPanel; public void refreshMarkers() { sourceTextArea.refreshMarkers(); @@ -113,7 +115,10 @@ public class MethodCodePanel extends JPanel { sourceTextArea = new ASMSourceEditorPane(decompiledEditor); setLayout(new BorderLayout()); - add(new JScrollPane(sourceTextArea), BorderLayout.CENTER); + + docsPanel = new DocsPanel(); + sourceTextArea.addDocsListener(docsPanel); + add(new JPersistentSplitPane(JSplitPane.VERTICAL_SPLIT, new JScrollPane(sourceTextArea), new JScrollPane(docsPanel), Configuration.guiAvm2DocsSplitPaneDividerLocationPercent)); sourceTextArea.changeContentType("text/flasm3"); sourceTextArea.setFont(new Font("Monospaced", Font.PLAIN, sourceTextArea.getFont().getSize())); @@ -146,11 +151,7 @@ public class MethodCodePanel extends JPanel { buttonsPanel.add(new JPanel()); add(buttonsPanel, BorderLayout.NORTH); - docsWindow = new DocsWindow(); - if (Configuration.as3pcodeDocWindow.get()) { - sourceTextArea.addDocsListener(docsWindow); - } } private void graphButtonActionPerformed(ActionEvent evt) {