diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3SimpleParser.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3SimpleParser.java index fb93beb21..1d63497e6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3SimpleParser.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/ActionScript3SimpleParser.java @@ -23,6 +23,7 @@ import com.jpexs.decompiler.flash.simpleparser.ClassScope; import com.jpexs.decompiler.flash.simpleparser.ClassTrait; import com.jpexs.decompiler.flash.simpleparser.FunctionScope; import com.jpexs.decompiler.flash.simpleparser.Import; +import com.jpexs.decompiler.flash.simpleparser.LinkHandler; import com.jpexs.decompiler.flash.simpleparser.MethodScope; import com.jpexs.decompiler.flash.simpleparser.Namespace; import com.jpexs.decompiler.flash.simpleparser.SimpleParseException; @@ -2273,7 +2274,10 @@ public class ActionScript3SimpleParser implements SimpleParser { List errors, List externalTypes, Map referenceToExternalTypeIndex, - Map> externalTypeIndexToReference + Map> externalTypeIndexToReference, + LinkHandler linkHandler, + Map referenceToExternalTraitKey, + Map> externalTraitKeyToReference ) throws SimpleParseException, IOException, InterruptedException { List> allOpenedNamespaces = new ArrayList<>(); Reference sinitNeedsActivation = new Reference<>(false); @@ -2293,7 +2297,7 @@ public class ActionScript3SimpleParser implements SimpleParser { //Logger.getLogger(ActionScript3SimpleParser.class.getName()).log(Level.SEVERE, null, ex); throw new SimpleParseException(str, ex.line); } - SimpleParser.parseVariablesList(new ArrayList<>(), vars, definitionPosToReferences, referenceToDefinition, errors, true, externalTypes, referenceToExternalTypeIndex, externalTypeIndexToReference); + SimpleParser.parseVariablesList(new ArrayList<>(), vars, definitionPosToReferences, referenceToDefinition, errors, true, externalTypes, referenceToExternalTypeIndex, externalTypeIndexToReference, linkHandler, referenceToExternalTraitKey, externalTraitKeyToReference); } /** diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionScript2SimpleParser.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionScript2SimpleParser.java index ac0236f27..064cf2ec8 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionScript2SimpleParser.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionScript2SimpleParser.java @@ -21,6 +21,7 @@ import com.jpexs.decompiler.flash.action.parser.ActionParseException; import com.jpexs.decompiler.flash.simpleparser.CatchScope; import com.jpexs.decompiler.flash.simpleparser.ClassScope; import com.jpexs.decompiler.flash.simpleparser.FunctionScope; +import com.jpexs.decompiler.flash.simpleparser.LinkHandler; import com.jpexs.decompiler.flash.simpleparser.MethodScope; import com.jpexs.decompiler.flash.simpleparser.SimpleParseException; import com.jpexs.decompiler.flash.simpleparser.SimpleParser; @@ -1576,7 +1577,10 @@ public class ActionScript2SimpleParser implements SimpleParser { List errors, List externalTypes, Map referenceToExternalTypeIndex, - Map> externalTypeIndexToReference + Map> externalTypeIndexToReference, + LinkHandler linkHandler, + Map referenceToExternalTraitKey, + Map> externalTraitKeyToReference ) throws SimpleParseException, IOException, InterruptedException { List vars = new ArrayList<>(); @@ -1667,7 +1671,7 @@ public class ActionScript2SimpleParser implements SimpleParser { } catch (ActionParseException ex) { errors.add(new SimpleParseException(ex.getMessage(), ex.line, ex.position)); } - SimpleParser.parseVariablesList(new ArrayList<>(), vars, definitionPosToReferences, referenceToDefinition, errors, false, externalTypes, referenceToExternalTypeIndex, externalTypeIndexToReference); + SimpleParser.parseVariablesList(new ArrayList<>(), vars, definitionPosToReferences, referenceToDefinition, errors, false, externalTypes, referenceToExternalTypeIndex, externalTypeIndexToReference, linkHandler, referenceToExternalTraitKey, externalTraitKeyToReference); } private void versionRequired(List errors, ParsedSymbol s, int min) throws SimpleParseException { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/LinkHandler.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/LinkHandler.java new file mode 100644 index 000000000..5d1755a05 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/LinkHandler.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2010-2025 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.simpleparser; + +/** + * @author JPEXS + */ +public interface LinkHandler { + + public LinkType getClassLinkType(String className); + + public boolean traitExists(String className, String traitName); + + public String getTraitType(String className, String traitName); + + public String getTraitSubType(String className, String traitName, int level); + + public String getTraitCallType(String className, String traitName); + + public String getTraitCallSubType(String className, String traitName, int level); + + public void handleClassLink(String className); + + public void handleTraitLink(String className, String traitName); + +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/LinkType.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/LinkType.java new file mode 100644 index 000000000..fe29f99fb --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/LinkType.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2010-2025 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.simpleparser; + +/** + * + * @author JPEXS + */ +public enum LinkType { + NO_LINK, + LINK_THIS_SCRIPT, + LINK_OTHER_SCRIPT, + LINK_OTHER_FILE; +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/SimpleParser.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/SimpleParser.java index 9b340f2ac..99bbf0570 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/SimpleParser.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/simpleparser/SimpleParser.java @@ -48,7 +48,10 @@ public interface SimpleParser { List errors, List externalTypes, Map referenceToExternalTypeIndex, - Map> externalTypeIndexToReference + Map> externalTypeIndexToReference, + LinkHandler linkHandler, + Map referenceToExternalTraitKey, + Map> externalTraitKeyToReference ) throws SimpleParseException, IOException, InterruptedException; public static void parseVariablesList( @@ -60,11 +63,17 @@ public interface SimpleParser { boolean innerFunctionCanUseTraits, List externalTypes, Map referenceToExternalTypeIndex, - Map> externalTypeIndexToReference + Map> externalTypeIndexToReference, + LinkHandler linkHandler, + Map referenceToExternalTraitKey, + Map> externalTraitKeyToReference ) { List externalSimpleTypes = new ArrayList<>(); + Map simpleExternalClassNameToFullClassName = new LinkedHashMap<>(); for (String type : externalTypes) { - externalSimpleTypes.add(type.contains(".") ? type.substring(type.lastIndexOf(".") + 1) : type); + String simpleName = type.contains(".") ? type.substring(type.lastIndexOf(".") + 1) : type; + externalSimpleTypes.add(simpleName); + simpleExternalClassNameToFullClassName.put(simpleName, type); } Map definitionToType = new LinkedHashMap<>(); @@ -77,7 +86,7 @@ public interface SimpleParser { findClassTraits(privateVariables, traitFullNameToDefinition, definitionPosToReferences, positionToStatic, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType); findClassTraits(sharedVariables, traitFullNameToDefinition, definitionPosToReferences, positionToStatic, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType); - parseVariablesList(privateVariables, sharedVariables, definitionPosToReferences, referenceToDefinition, new LinkedHashMap<>(), new LinkedHashMap<>(), positionToStatic, true, errors, null, innerFunctionCanUseTraits, externalSimpleTypes, referenceToExternalTypeIndex, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition); + parseVariablesList(privateVariables, sharedVariables, definitionPosToReferences, referenceToDefinition, new LinkedHashMap<>(), new LinkedHashMap<>(), positionToStatic, true, errors, null, innerFunctionCanUseTraits, externalSimpleTypes, referenceToExternalTypeIndex, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition, linkHandler, simpleExternalClassNameToFullClassName, referenceToExternalTraitKey, externalTraitKeyToReference); for (Map.Entry entry : referenceToExternalTypeIndex.entrySet()) { if (!externalTypeIndexToReference.containsKey(entry.getValue())) { externalTypeIndexToReference.put(entry.getValue(), new ArrayList<>()); @@ -104,7 +113,11 @@ public interface SimpleParser { Map definitionToCallType, Map definitionToSubType, Map definitionToCallSubType, - Map traitFullNameToDefinition + Map traitFullNameToDefinition, + LinkHandler linkHandler, + Map simpleExternalClassNameToFullClassName, + Map referenceToExternalTraitKey, + Map> externalTraitKeyToReference ) { Map privateVarNameToDefinitionPosition = new LinkedHashMap<>(); privateVarNameToDefinitionPosition.putAll(parentVarNameToDefinitionPosition); @@ -135,7 +148,7 @@ public interface SimpleParser { if (externalSimpleTypes.contains(v.name)) { referenceToExternalTypeIndex.put(v.position, externalSimpleTypes.indexOf(v.name)); } else { - boolean traitFound = searchTrait(v, privateVarFullNameToDefinitionPosition, privateVarNameToDefinitionPosition, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition, definitionPosToReferences, referenceToDefinition); + boolean traitFound = searchTrait(v, privateVarFullNameToDefinitionPosition, privateVarNameToDefinitionPosition, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition, definitionPosToReferences, referenceToDefinition, linkHandler, simpleExternalClassNameToFullClassName, referenceToExternalTraitKey, externalTraitKeyToReference); if (!traitFound) { parentVarFullNameToDefinitionPosition.put(v.name, -v.position - 1); parentVarNameToDefinitionPosition.put(v.getLastName(), -v.position - 1); @@ -199,7 +212,7 @@ public interface SimpleParser { } } - parseVariablesList(vs.getPrivateItems(), vs.getSharedItems(), definitionPosToReferences, referenceToDefinition, subPrivateVarFullNameToDefinitionPosition, subPrivateVarNameToDefinitionPosition, positionToStatic, subStatic, errors, vs, innerFunctionCanUseTraits, externalSimpleTypes, referenceToExternalTypeIndex, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition); + parseVariablesList(vs.getPrivateItems(), vs.getSharedItems(), definitionPosToReferences, referenceToDefinition, subPrivateVarFullNameToDefinitionPosition, subPrivateVarNameToDefinitionPosition, positionToStatic, subStatic, errors, vs, innerFunctionCanUseTraits, externalSimpleTypes, referenceToExternalTypeIndex, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition, linkHandler, simpleExternalClassNameToFullClassName, referenceToExternalTraitKey, externalTraitKeyToReference); } } for (VariableOrScope vt : sharedVariables) { @@ -227,7 +240,7 @@ public interface SimpleParser { if (externalSimpleTypes.contains(v.name)) { referenceToExternalTypeIndex.put(v.position, externalSimpleTypes.indexOf(v.name)); } else { - boolean traitFound = searchTrait(v, privateVarFullNameToDefinitionPosition, privateVarNameToDefinitionPosition, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition, definitionPosToReferences, referenceToDefinition); + boolean traitFound = searchTrait(v, privateVarFullNameToDefinitionPosition, privateVarNameToDefinitionPosition, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition, definitionPosToReferences, referenceToDefinition, linkHandler, simpleExternalClassNameToFullClassName, referenceToExternalTraitKey, externalTraitKeyToReference); if (!traitFound) { parentVarFullNameToDefinitionPosition.put(v.name, -v.position - 1); parentVarNameToDefinitionPosition.put(v.getFirstName(), -v.position - 1); @@ -291,7 +304,7 @@ public interface SimpleParser { } } - parseVariablesList(vs.getPrivateItems(), vs.getSharedItems(), definitionPosToReferences, referenceToDefinition, privateVarFullNameToDefinitionPosition, privateVarNameToDefinitionPosition, positionToStatic, subStatic, errors, vs, innerFunctionCanUseTraits, externalSimpleTypes, referenceToExternalTypeIndex, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition); + parseVariablesList(vs.getPrivateItems(), vs.getSharedItems(), definitionPosToReferences, referenceToDefinition, privateVarFullNameToDefinitionPosition, privateVarNameToDefinitionPosition, positionToStatic, subStatic, errors, vs, innerFunctionCanUseTraits, externalSimpleTypes, referenceToExternalTypeIndex, definitionToType, definitionToCallType, definitionToSubType, definitionToCallSubType, traitFullNameToDefinition, linkHandler, simpleExternalClassNameToFullClassName, referenceToExternalTraitKey, externalTraitKeyToReference); } } } @@ -343,12 +356,16 @@ public interface SimpleParser { Map definitionToCallSubType, Map traitFullNameToDefinition, Map> definitionPosToReferences, - Map referenceToDefinition + Map referenceToDefinition, + LinkHandler linkHandler, + Map simpleExternalClassNameToFullClassName, + Map referenceToExternalTraitKey, + Map> externalTraitKeyToReference ) { boolean traitFound = false; if (v.hasParent()) { List parts = v.getParts(); - + Integer definitionPos = null; String firstName = parts.get(0); if (privateVarFullNameToDefinitionPosition.containsKey(firstName)) { @@ -361,34 +378,88 @@ public interface SimpleParser { String type = definitionToType.get(definitionPos); traitFound = true; Variable lastSubType = null; + String traitKey = null; + String externalCallType = null; + List externalSubTypes = new ArrayList<>(); + List externalCallSubTypes = new ArrayList<>(); + String part = null; for (int p = 1; p < parts.size(); p++) { - String part = parts.get(p); + part = parts.get(p); if (part.equals("()")) { if (parts.get(p - 1).equals("[]")) { traitFound = false; break; } - type = definitionToCallType.get(definitionPos); + if (definitionPos == null) { + type = externalCallType; + externalSubTypes.clear(); + externalSubTypes.addAll(externalCallSubTypes); + } else { + type = definitionToCallType.get(definitionPos); + } lastSubType = null; } else if (part.equals("[]")) { - if (lastSubType != null) { - lastSubType = lastSubType.subType; - } else if (parts.get(p - 1).equals("()")) { - lastSubType = definitionToCallSubType.get(definitionPos); - } else { - lastSubType = definitionToSubType.get(definitionPos); + if (definitionPos != null) { + if (lastSubType != null) { + lastSubType = lastSubType.subType; + } else if (parts.get(p - 1).equals("()")) { + lastSubType = definitionToCallSubType.get(definitionPos); + } else { + lastSubType = definitionToSubType.get(definitionPos); + } + if (lastSubType == null) { + traitFound = false; + break; + } + type = lastSubType.name; + } else { + if (externalSubTypes.isEmpty()) { + traitFound = false; + break; + } + type = externalSubTypes.remove(0); } - if (lastSubType == null) { - traitFound = false; - break; - } - type = lastSubType.name; } else { - String traitKey = type + "/" + part; + traitKey = type + "/" + part; if (!traitFullNameToDefinition.containsKey(traitKey)) { - traitFound = false; - break; + if (simpleExternalClassNameToFullClassName.containsKey(type)) { + type = simpleExternalClassNameToFullClassName.get(type); + } + traitKey = type + "/" + part; + String newType = linkHandler.getTraitType(type, part); + if (newType == null) { + traitFound = false; + break; + } + externalSubTypes.clear(); + int i = 1; + while (true) { + String st = linkHandler.getTraitSubType(type, part, i); + if (st == null) { + break; + } + externalSubTypes.add(st); + i++; + } + externalCallType = linkHandler.getTraitCallType(type, part); + externalCallSubTypes.clear(); + i = 1; + while (true) { + String st = linkHandler.getTraitCallSubType(type, part, i); + if (st == null) { + break; + } + externalCallSubTypes.add(st); + i++; + } + type = newType; + definitionPos = null; + lastSubType = null; + continue; } + externalCallSubTypes.clear(); + externalSubTypes.clear(); + externalCallType = null; definitionPos = traitFullNameToDefinition.get(traitKey); type = definitionToType.get(definitionPos); lastSubType = null; @@ -396,8 +467,16 @@ public interface SimpleParser { } if (traitFound) { - definitionPosToReferences.get(definitionPos).add(v.position); - referenceToDefinition.put(v.position, definitionPos); + if (definitionPos != null) { + definitionPosToReferences.get(definitionPos).add(v.position); + referenceToDefinition.put(v.position, definitionPos); + } else if (part != null) { + if (!externalTraitKeyToReference.containsKey(traitKey)) { + externalTraitKeyToReference.put(traitKey, new ArrayList<>()); + } + externalTraitKeyToReference.get(traitKey).add(v.position); + referenceToExternalTraitKey.put(v.position, traitKey); + } } } } diff --git a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java index 1574248dc..172422e9d 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java @@ -20,7 +20,6 @@ import com.jpexs.debugger.flash.Variable; import com.jpexs.debugger.flash.VariableFlags; import com.jpexs.debugger.flash.VariableType; import com.jpexs.debugger.flash.messages.in.InGetVariable; -import com.jpexs.decompiler.flash.SWC; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.abc.ABC; import com.jpexs.decompiler.flash.abc.ClassPath; @@ -28,6 +27,7 @@ import com.jpexs.decompiler.flash.abc.ScriptPack; import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; 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.model.ApplyTypeAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.parser.script.AbcIndexing; import com.jpexs.decompiler.flash.abc.avm2.parser.script.ActionScript3SimpleParser; import com.jpexs.decompiler.flash.abc.types.ABCException; @@ -61,7 +61,6 @@ import com.jpexs.decompiler.flash.gui.HeaderLabel; import com.jpexs.decompiler.flash.gui.Main; import com.jpexs.decompiler.flash.gui.MainPanel; import com.jpexs.decompiler.flash.gui.OpenableListLoaded; -import com.jpexs.decompiler.flash.gui.OpenableOpened; import com.jpexs.decompiler.flash.gui.PopupButton; import com.jpexs.decompiler.flash.gui.SearchListener; import com.jpexs.decompiler.flash.gui.SearchPanel; @@ -69,13 +68,10 @@ import com.jpexs.decompiler.flash.gui.TagEditorPanel; import com.jpexs.decompiler.flash.gui.View; import com.jpexs.decompiler.flash.gui.ViewMessages; import com.jpexs.decompiler.flash.gui.controls.JPersistentSplitPane; -import com.jpexs.decompiler.flash.gui.editor.LinkHandler; -import com.jpexs.decompiler.flash.gui.editor.LinkType; import com.jpexs.decompiler.flash.gui.editor.VariableMarker; import com.jpexs.decompiler.flash.gui.tagtree.AbstractTagTree; import com.jpexs.decompiler.flash.gui.tagtree.AbstractTagTreeModel; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; -import com.jpexs.decompiler.flash.helpers.hilight.Highlighting; import com.jpexs.decompiler.flash.importers.As3ScriptReplaceException; import com.jpexs.decompiler.flash.importers.As3ScriptReplaceExceptionItem; import com.jpexs.decompiler.flash.importers.As3ScriptReplacerInterface; @@ -84,6 +80,8 @@ import com.jpexs.decompiler.flash.search.ABCSearchResult; import com.jpexs.decompiler.flash.search.ActionScriptSearch; import com.jpexs.decompiler.flash.search.ScriptSearchListener; import com.jpexs.decompiler.flash.search.ScriptSearchResult; +import com.jpexs.decompiler.flash.simpleparser.LinkHandler; +import com.jpexs.decompiler.flash.simpleparser.LinkType; import com.jpexs.decompiler.flash.tags.ABCContainerTag; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.timeline.AS3Package; @@ -92,6 +90,7 @@ import com.jpexs.decompiler.flash.treeitems.Openable; import com.jpexs.decompiler.flash.treeitems.OpenableList; import com.jpexs.decompiler.flash.treeitems.TreeItem; import com.jpexs.decompiler.graph.DottedChain; +import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.TypeItem; import com.jpexs.helpers.CancellableWorker; import com.jpexs.helpers.Helper; @@ -122,6 +121,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Timer; +import java.util.TimerTask; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.AbstractAction; @@ -148,7 +149,6 @@ import javax.swing.event.EventListenerList; import javax.swing.event.TableModelListener; import javax.swing.event.TreeModelEvent; import javax.swing.event.TreeModelListener; -import javax.swing.text.Highlighter; import javax.swing.tree.TreePath; import jsyntaxpane.DefaultSyntaxKit; import jsyntaxpane.Token; @@ -903,6 +903,46 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener -1) { + scriptName = newAbc.instance_info.get(classIndex).getName(newAbc.constants).getNameWithNamespace(newAbc.constants, true).toPrintableString(true); + } else if (scriptIndex > -1) { + scriptName = newAbc.script_info.get(classIndex).getSimplePackName(newAbc).toPrintableString(true); + } else { + scriptName = ""; + } + hilightScript(newAbc.getOpenable(), scriptName); + } + } + public ABCPanel(MainPanel mainPanel) { this.mainPanel = mainPanel; @@ -913,22 +953,7 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener foundStatic = new Reference<>(null); + AbcIndexing.TraitIndex ti = abc.getSwf().getAbcIndex().findProperty(new AbcIndexing.PropertyDef(traitName, new TypeItem(className), abc, -1), + true, + true, + true, + foundStatic); + return ti != null; + } + + @Override + public void handleClassLink(String scriptName) { Reference swfRef = new Reference<>(null); AbcIndexing.ClassIndex ci = abc.getSwf().getAbcIndex().findClass(new TypeItem(scriptName), abc, decompiledTextArea.getScriptIndex()); if (ci == null) { @@ -978,9 +1014,122 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener foundStatic = new Reference<>(null); + AbcIndexing.TraitIndex ti = abc.getSwf().getAbcIndex().findProperty(new AbcIndexing.PropertyDef(traitName, new TypeItem(className), abc, -1), + true, + true, + true, + foundStatic); + if (ti.objType instanceof TypeItem) { + AbcIndexing.ClassIndex ci = abc.getSwf().getAbcIndex().findClass(ti.objType, abc, decompiledTextArea.getScriptIndex()); + int i = 0; + Integer traitIndex = null; + for (Trait t : ci.abc.class_info.get(ci.index).static_traits.traits) { + if (t == ti.trait) { + traitIndex = i; + break; + } + i++; + } + if (traitIndex == null) { + for (Trait t : ci.abc.instance_info.get(ci.index).instance_traits.traits) { + if (t == ti.trait) { + traitIndex = i; + break; + } + i++; + } + } + if (traitIndex != null) { + hilightScriptClassTrait(ti.abc, ti.scriptIndex, ci.index, traitIndex); + } + } + } + + @Override + public String getTraitType(String className, String traitName) { + Reference foundStatic = new Reference<>(null); + AbcIndexing.TraitIndex ti = abc.getSwf().getAbcIndex().findProperty(new AbcIndexing.PropertyDef(traitName, new TypeItem(className), abc, -1), + true, + true, + true, + foundStatic); + if (ti == null) { + return null; + } + if (ti.returnType instanceof ApplyTypeAVM2Item) { + ApplyTypeAVM2Item at = (ApplyTypeAVM2Item) ti.returnType; + return at.object.toString(); + } + return ti.returnType.toString(); + } + + @Override + public String getTraitSubType(String className, String traitName, int level) { + Reference foundStatic = new Reference<>(null); + AbcIndexing.TraitIndex ti = abc.getSwf().getAbcIndex().findProperty(new AbcIndexing.PropertyDef(traitName, new TypeItem(className), abc, -1), + true, + true, + true, + foundStatic); + if (ti == null) { + return null; + } + GraphTargetItem it = ti.returnType; + for (int i = 0; i < level; i++) { + if (!(it instanceof ApplyTypeAVM2Item)) { + return null; + } + it = ((ApplyTypeAVM2Item) it).params.get(0); + } + + return it.toString(); + } + + @Override + public String getTraitCallType(String className, String traitName) { + Reference foundStatic = new Reference<>(null); + AbcIndexing.TraitIndex ti = abc.getSwf().getAbcIndex().findProperty(new AbcIndexing.PropertyDef(traitName, new TypeItem(className), abc, -1), + true, + true, + true, + foundStatic); + if (ti == null) { + return null; + } + if (ti.callReturnType instanceof ApplyTypeAVM2Item) { + ApplyTypeAVM2Item at = (ApplyTypeAVM2Item) ti.callReturnType; + return at.object.toString(); + } + return ti.callReturnType.toString(); + } + + @Override + public String getTraitCallSubType(String className, String traitName, int level) { + Reference foundStatic = new Reference<>(null); + AbcIndexing.TraitIndex ti = abc.getSwf().getAbcIndex().findProperty(new AbcIndexing.PropertyDef(traitName, new TypeItem(className), abc, -1), + true, + true, + true, + foundStatic); + if (ti == null) { + return null; + } + GraphTargetItem it = ti.callReturnType; + for (int i = 0; i < level; i++) { + if (!(it instanceof ApplyTypeAVM2Item)) { + return null; + } + it = ((ApplyTypeAVM2Item) it).params.get(0); + } + + return it.toString(); + } + }); decompiledTextArea.addScriptListener(new Runnable() { @Override @@ -1575,9 +1724,9 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener { @@ -384,21 +412,6 @@ public class LineMarkedEditorPane extends UndoFixedEditorPane implements LinkHan return linkHandler; } - @Override - public HighlightPainter linkPainter() { - return null; - } - - @Override - public LinkType getLinkType(Token token) { - return LinkType.NO_LINK; - } - - @Override - public void handleLink(Token token) { - - } - @Override public void setText(String t) { this.lineMarkers = new HashMap<>(); diff --git a/src/com/jpexs/decompiler/flash/gui/editor/LinkHandler.java b/src/com/jpexs/decompiler/flash/gui/editor/LinkHandler.java deleted file mode 100644 index 72d78c3f6..000000000 --- a/src/com/jpexs/decompiler/flash/gui/editor/LinkHandler.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2010-2025 JPEXS - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.jpexs.decompiler.flash.gui.editor; - -import javax.swing.text.Highlighter; -import jsyntaxpane.Token; - -/** - * @author JPEXS - */ -public interface LinkHandler { - - public LinkType getLinkType(Token token); - - public LinkType getExternalTypeLinkType(String className); - - public void handleLink(Token token); - - public void handleExternalTypeLink(String className); - - public Highlighter.HighlightPainter linkPainter(); -} diff --git a/src/com/jpexs/decompiler/flash/gui/editor/LinkType.java b/src/com/jpexs/decompiler/flash/gui/editor/LinkType.java deleted file mode 100644 index 57b791a9c..000000000 --- a/src/com/jpexs/decompiler/flash/gui/editor/LinkType.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2025 JPEXS - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.jpexs.decompiler.flash.gui.editor; - -/** - * - * @author JPEXS - */ -public enum LinkType { - NO_LINK, - LINK_THIS_SCRIPT, - LINK_OTHER_SCRIPT, - LINK_OTHER_FILE; -} diff --git a/src/com/jpexs/decompiler/flash/gui/editor/VariableMarker.java b/src/com/jpexs/decompiler/flash/gui/editor/VariableMarker.java index 7ca659659..694655ad3 100644 --- a/src/com/jpexs/decompiler/flash/gui/editor/VariableMarker.java +++ b/src/com/jpexs/decompiler/flash/gui/editor/VariableMarker.java @@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.gui.AppStrings; import com.jpexs.decompiler.flash.gui.Main; import com.jpexs.decompiler.flash.gui.View; import com.jpexs.decompiler.flash.gui.ViewMessages; +import com.jpexs.decompiler.flash.simpleparser.LinkType; import com.jpexs.decompiler.flash.simpleparser.SimpleParseException; import com.jpexs.decompiler.flash.simpleparser.SimpleParser; import java.awt.BorderLayout; @@ -108,6 +109,9 @@ public class VariableMarker implements SyntaxComponent, CaretListener, PropertyC private List externalTypes = new ArrayList<>(); private Map referenceToExternalTypeIndex = new LinkedHashMap<>(); private Map> externalTypeIndexToReference = new LinkedHashMap<>(); + private Map simpleExternalClassNameToFullClassName = new LinkedHashMap<>(); + private Map referenceToExternalTraitKey = new LinkedHashMap<>(); + private Map> externalTraitKeyToReference = new LinkedHashMap<>(); private MouseMotionAdapter mouseMotionAdapter; @@ -283,6 +287,27 @@ public class VariableMarker implements SyntaxComponent, CaretListener, PropertyC } sDoc.readUnlock(); return; + } else { + if (referenceToExternalTraitKey.containsKey(tok.start)) { + String traitKey = referenceToExternalTraitKey.get(tok.start); + for (int i : externalTraitKeyToReference.get(traitKey)) { + Token referenceToken = getIdentifierTokenAt(sDoc, i); + if (referenceToken != null) { + Markers.SimpleMarker markerKind = marker; + if (lastUnderlined == referenceToken) { + if (lastUnderlinedLinkType == LinkType.LINK_OTHER_SCRIPT) { + markerKind = underLineOtherScriptMarkOccurencesPainter; + } else if (lastUnderlinedLinkType == LinkType.LINK_OTHER_FILE) { + markerKind = underLineOtherFileMarkOccurencesPainter; + } else { + markerKind = underLineMarkOccurencesPainter; + } + } + Markers.markToken(pane, referenceToken, markerKind); + occurencesPositions.add(referenceToken.start); + } + } + } } } Token definitionToken = getIdentifierTokenAt(sDoc, definitionPos < 0 ? -(definitionPos + 1) : definitionPos); @@ -546,12 +571,32 @@ public class VariableMarker implements SyntaxComponent, CaretListener, PropertyC private void editorMouseMoved(MouseEvent e) { if (pane instanceof LineMarkedEditorPane) { Token token = ((LineMarkedEditorPane) pane).tokenAtPos(e.getPoint()); - if (token != null) { - String err = errors.get(token.start); - pane.setToolTipText(err); - } else { + if (token == null) { pane.setToolTipText(null); + return; } + String err = errors.get(token.start); + if (err != null) { + pane.setToolTipText(err); + return; + } + + /* + String traitKey = referenceToExternalTraitKey.get(token.start); + if (traitKey != null) { + pane.setToolTipText(traitKey); + return; + } + + if (referenceToExternalTypeIndex.containsKey(token.start)) { + String externalType = externalTypes.get(referenceToExternalTypeIndex.get(token.start)); + if (externalType != null) { + pane.setToolTipText(externalType); + return; + } + } + */ + pane.setToolTipText(null); } } @@ -627,12 +672,34 @@ public class VariableMarker implements SyntaxComponent, CaretListener, PropertyC List newExternalTypes = new ArrayList<>(); Map newReferenceToExternalTypeIndex = new LinkedHashMap<>(); Map> newExternalTypeIndexToReference = new LinkedHashMap<>(); - parser.parse(fullText, newDefinitionPosToReferences, newReferenceToDefinition, newErrors, newExternalTypes, newReferenceToExternalTypeIndex, newExternalTypeIndexToReference); + Map newReferenceToExternalTraitKey = new LinkedHashMap<>(); + Map> newExternalTraitKeyToReference = new LinkedHashMap<>(); + parser.parse( + fullText, + newDefinitionPosToReferences, + newReferenceToDefinition, + newErrors, + newExternalTypes, + newReferenceToExternalTypeIndex, + newExternalTypeIndexToReference, + ((LineMarkedEditorPane) pane).getLinkHandler(), + newReferenceToExternalTraitKey, newExternalTraitKeyToReference + ); + + Map newSimpleExternalClassNameToFullClassName = new LinkedHashMap<>(); + for (int i = 0; i < newExternalTypes.size(); i++) { + String type = newExternalTypes.get(i); + String simpleName = type.contains(".") ? type.substring(type.lastIndexOf(".") + 1) : type; + newSimpleExternalClassNameToFullClassName.put(simpleName, type); + } definitionPosToReferences = newDefinitionPosToReferences; referenceToDefinition = newReferenceToDefinition; externalTypes = newExternalTypes; referenceToExternalTypeIndex = newReferenceToExternalTypeIndex; externalTypeIndexToReference = newExternalTypeIndexToReference; + simpleExternalClassNameToFullClassName = newSimpleExternalClassNameToFullClassName; + referenceToExternalTraitKey = newReferenceToExternalTraitKey; + externalTraitKeyToReference = newExternalTraitKeyToReference; for (SimpleParseException ex : newErrors) { errors.put((int) ex.position, ex.getMessage()); } @@ -691,9 +758,19 @@ public class VariableMarker implements SyntaxComponent, CaretListener, PropertyC } if (referenceToExternalTypeIndex.containsKey(token.start)) { String externalType = externalTypes.get(referenceToExternalTypeIndex.get(token.start)); - return ((LineMarkedEditorPane) pane).getLinkHandler().getExternalTypeLinkType(externalType); + return ((LineMarkedEditorPane) pane).getLinkHandler().getClassLinkType(externalType); } - return ((LineMarkedEditorPane) pane).getLinkHandler().getLinkType(token); + if (referenceToExternalTraitKey.containsKey(token.start)) { + String traitKey = referenceToExternalTraitKey.get(token.start); + //String traitName = traitKey.substring(traitKey.lastIndexOf("/") + 1); + String className = traitKey.substring(0, traitKey.lastIndexOf("/")); + if (simpleExternalClassNameToFullClassName.containsKey(className)) { + className = simpleExternalClassNameToFullClassName.get(className); + } + return ((LineMarkedEditorPane) pane).getLinkHandler().getClassLinkType(className); + } + + return LinkType.NO_LINK; } private class UnderlinedLabel extends JLabel { @@ -732,7 +809,8 @@ public class VariableMarker implements SyntaxComponent, CaretListener, PropertyC && com.jpexs.decompiler.flash.configuration.Configuration.warningLinkTypes.get()) { String externalType = externalTypes.get(referenceToExternalTypeIndex.get(token.start)); - LinkType lt = ((LineMarkedEditorPane) pane).getLinkHandler().getExternalTypeLinkType(externalType); + + LinkType lt = ((LineMarkedEditorPane) pane).getLinkHandler().getClassLinkType(externalType); if (lt == LinkType.LINK_OTHER_FILE) { JPanel msgPanel = new JPanel(); @@ -811,11 +889,19 @@ public class VariableMarker implements SyntaxComponent, CaretListener, PropertyC goingOut = true; pane.setCursor(Cursor.getDefaultCursor()); String externalType = externalTypes.get(referenceToExternalTypeIndex.get(token.start)); - ((LineMarkedEditorPane) pane).getLinkHandler().handleExternalTypeLink(externalType); + ((LineMarkedEditorPane) pane).getLinkHandler().handleClassLink(externalType); return; } + if (referenceToExternalTraitKey.containsKey(token.start)) { + String traitKey = referenceToExternalTraitKey.get(token.start); + String traitName = traitKey.substring(traitKey.lastIndexOf("/") + 1); + String className = traitKey.substring(0, traitKey.lastIndexOf("/")); - ((LineMarkedEditorPane) pane).getLinkHandler().handleLink(token); + if (simpleExternalClassNameToFullClassName.containsKey(className)) { + className = simpleExternalClassNameToFullClassName.get(className); + } + ((LineMarkedEditorPane) pane).getLinkHandler().handleTraitLink(className, traitName); + } } }