Files
jpexs-decompiler/src/com/jpexs/decompiler/flash/gui/abc/ABCExplorerDialog.java
2023-10-01 18:21:38 +02:00

2198 lines
104 KiB
Java

/*
* Copyright (C) 2023 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 <http://www.gnu.org/licenses/>.
*/
package com.jpexs.decompiler.flash.gui.abc;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.NewFunctionIns;
import com.jpexs.decompiler.flash.abc.types.ABCException;
import com.jpexs.decompiler.flash.abc.types.ClassInfo;
import com.jpexs.decompiler.flash.abc.types.Float4;
import com.jpexs.decompiler.flash.abc.types.InstanceInfo;
import com.jpexs.decompiler.flash.abc.types.MetadataInfo;
import com.jpexs.decompiler.flash.abc.types.MethodBody;
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
import com.jpexs.decompiler.flash.abc.types.Multiname;
import com.jpexs.decompiler.flash.abc.types.Namespace;
import com.jpexs.decompiler.flash.abc.types.NamespaceSet;
import com.jpexs.decompiler.flash.abc.types.ScriptInfo;
import com.jpexs.decompiler.flash.abc.types.ValueKind;
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
import com.jpexs.decompiler.flash.abc.types.traits.TraitClass;
import com.jpexs.decompiler.flash.abc.types.traits.TraitFunction;
import com.jpexs.decompiler.flash.abc.types.traits.TraitMethodGetterSetter;
import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst;
import com.jpexs.decompiler.flash.abc.types.traits.Traits;
import com.jpexs.decompiler.flash.ecma.EcmaScript;
import com.jpexs.decompiler.flash.gui.AppDialog;
import com.jpexs.decompiler.flash.gui.FasterScrollPane;
import com.jpexs.decompiler.flash.gui.MainPanel;
import com.jpexs.decompiler.flash.gui.View;
import com.jpexs.decompiler.flash.helpers.CodeFormatting;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.flash.helpers.StringBuilderTextWriter;
import com.jpexs.decompiler.flash.tags.ABCContainerTag;
import com.jpexs.decompiler.flash.tags.DoABC2Tag;
import com.jpexs.decompiler.flash.tags.ShowFrameTag;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.treeitems.Openable;
import com.jpexs.decompiler.graph.DottedChain;
import com.jpexs.helpers.Helper;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JTabbedPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.event.TreeModelListener;
import javax.swing.plaf.basic.BasicLabelUI;
import javax.swing.plaf.basic.BasicTreeUI;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
/**
*
* @author JPEXS
*/
public class ABCExplorerDialog extends AppDialog {
private final List<ABC> abcs = new ArrayList<>();
private JComboBox<String> abcComboBox = null;
private final JLabel tagInfoLabel;
private final List<Integer> abcFrames = new ArrayList<>();
private final JTabbedPane mainTabbedPane;
private final JTabbedPane cpTabbedPane;
private MainPanel mainPanel;
public ABCExplorerDialog(Window owner, MainPanel mainPanel, Openable openable, ABC abc) {
super(owner);
this.mainPanel = mainPanel;
Container cnt = getContentPane();
cnt.setLayout(new BorderLayout());
JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
topPanel.add(new JLabel(translate("abc")));
int selectedIndex = 0;
int frame = 1;
if (openable instanceof SWF) {
SWF swf = (SWF) openable;
List<ABCContainerTag> abcContainers = new ArrayList<>();
for (Tag t : swf.getTags()) {
if (t instanceof ShowFrameTag) {
frame++;
}
if (t instanceof ABCContainerTag) {
ABCContainerTag abcCnt = (ABCContainerTag) t;
if (abcCnt.getABC() == abc) {
selectedIndex = abcs.size();
}
abcContainers.add(abcCnt);
abcs.add(abcCnt.getABC());
abcFrames.add(frame);
}
}
String[] abcComboBoxData = new String[abcs.size()];
for (int i = 0; i < abcContainers.size(); i++) {
abcComboBoxData[i] = "tag" + (i + 1);
if (abcContainers.get(i) instanceof DoABC2Tag) {
DoABC2Tag doa2 = (DoABC2Tag) abcContainers.get(i);
if (doa2.name != null && !doa2.name.isEmpty()) {
abcComboBoxData[i] += " (\"" + Helper.escapePCodeString(doa2.name) + "\")";
}
}
}
abcComboBox = new JComboBox<>(abcComboBoxData);
Dimension abcComboBoxSize = new Dimension(500, abcComboBox.getPreferredSize().height);
abcComboBox.setMinimumSize(abcComboBoxSize);
abcComboBox.setPreferredSize(abcComboBoxSize);
topPanel.add(abcComboBox);
abcComboBox.addActionListener(this::abcComboBoxActionPerformed);
} else if (openable instanceof ABC) {
abcs.add((ABC) openable);
abcFrames.add(-1);
}
tagInfoLabel = new JLabel();
topPanel.add(tagInfoLabel);
mainTabbedPane = new JTabbedPane();
cpTabbedPane = new JTabbedPane();
cnt.add(topPanel, BorderLayout.NORTH);
cnt.add(mainTabbedPane, BorderLayout.CENTER);
if (!abcs.isEmpty()) {
if (abcComboBox != null) {
abcComboBox.setSelectedIndex(selectedIndex);
} else {
abcComboBoxActionPerformed(null);
}
}
setSize(800, 600);
setTitle(translate("title") + " - " + openable.getTitleOrShortFileName());
List<Image> images = new ArrayList<>();
images.add(View.loadImage("abcexplorer16"));
images.add(View.loadImage("abcexplorer32"));
setIconImages(images);
View.centerScreen(this);
}
public void selectAbc(ABC abc) {
if (abcComboBox == null) {
return;
}
if (abc == null && !abcs.isEmpty()) {
abcComboBox.setSelectedIndex(0);
return;
}
for (int i = 0; i < abcs.size(); i++) {
if (abcs.get(i) == abc) {
abcComboBox.setSelectedIndex(i);
break;
}
}
}
private ABC getSelectedAbc() {
if (abcs.isEmpty()) {
return null;
}
if (abcComboBox == null) {
return abcs.get(0);
}
return abcs.get(abcComboBox.getSelectedIndex());
}
private void abcComboBoxActionPerformed(ActionEvent e) {
int index = abcComboBox == null ? 0 : abcComboBox.getSelectedIndex();
if (index == -1) {
return;
}
if (abcs.isEmpty()) {
return;
}
ABC abc = abcs.get(index);
if (abcComboBox == null) {
tagInfoLabel.setText(translate("abc.info.standalone")
.replace("%major%", "" + abc.version.major)
.replace("%minor%", "" + abc.version.minor)
.replace("%size%", Helper.formatFileSize(abc.getDataSize()))
);
} else {
tagInfoLabel.setText(
translate("abc.info")
.replace("%index%", "" + (index + 1))
.replace("%count%", "" + abcComboBox.getItemCount())
.replace("%major%", "" + abc.version.major)
.replace("%minor%", "" + abc.version.minor)
.replace("%size%", Helper.formatFileSize(abc.getDataSize()))
.replace("%frame%", "" + abcFrames.get(index))
);
}
cpTabbedPane.removeAll();
cpTabbedPane.addTab("int (" + Math.max(0, abc.constants.getIntCount() - 1) + ")", View.getIcon(TreeType.CONSTANT_INT.getIcon().getFile()), makeTreePanel(abc, TreeType.CONSTANT_INT));
cpTabbedPane.addTab("uint (" + Math.max(0, abc.constants.getUIntCount() - 1) + ")", View.getIcon(TreeType.CONSTANT_UINT.getIcon().getFile()), makeTreePanel(abc, TreeType.CONSTANT_UINT));
cpTabbedPane.addTab("dbl (" + Math.max(0, abc.constants.getDoubleCount() - 1) + ")", View.getIcon(TreeType.CONSTANT_DOUBLE.getIcon().getFile()), makeTreePanel(abc, TreeType.CONSTANT_DOUBLE));
if (abc.hasDecimalSupport()) {
cpTabbedPane.addTab("dc (" + Math.max(0, abc.constants.getDecimalCount() - 1) + ")", View.getIcon(TreeType.CONSTANT_DECIMAL.getIcon().getFile()), makeTreePanel(abc, TreeType.CONSTANT_DECIMAL));
}
if (abc.hasFloatSupport()) {
cpTabbedPane.addTab("fl (" + Math.max(0, abc.constants.getFloatCount() - 1) + ")", View.getIcon(TreeType.CONSTANT_FLOAT.getIcon().getFile()), makeTreePanel(abc, TreeType.CONSTANT_FLOAT));
cpTabbedPane.addTab("fl4 (" + Math.max(0, abc.constants.getFloat4Count() - 1) + ")", View.getIcon(TreeType.CONSTANT_FLOAT_4.getIcon().getFile()), makeTreePanel(abc, TreeType.CONSTANT_FLOAT_4));
}
cpTabbedPane.addTab("str (" + Math.max(0, abc.constants.getStringCount() - 1) + ")", View.getIcon(TreeType.CONSTANT_STRING.getIcon().getFile()), makeTreePanel(abc, TreeType.CONSTANT_STRING));
cpTabbedPane.addTab("ns (" + Math.max(0, abc.constants.getNamespaceCount() - 1) + ")", View.getIcon(TreeType.CONSTANT_NAMESPACE.getIcon().getFile()), makeTreePanel(abc, TreeType.CONSTANT_NAMESPACE));
cpTabbedPane.addTab("nss (" + Math.max(0, abc.constants.getNamespaceSetCount() - 1) + ")", View.getIcon(TreeType.CONSTANT_NAMESPACE_SET.getIcon().getFile()), makeTreePanel(abc, TreeType.CONSTANT_NAMESPACE_SET));
cpTabbedPane.addTab("mn (" + Math.max(0, abc.constants.getMultinameCount() - 1) + ")", View.getIcon(TreeType.CONSTANT_MULTINAME.getIcon().getFile()), makeTreePanel(abc, TreeType.CONSTANT_MULTINAME));
mainTabbedPane.removeAll();
JPanel cpPanel = new JPanel(new BorderLayout());
cpPanel.add(cpTabbedPane, BorderLayout.CENTER);
int cpCount = Math.max(0, abc.constants.getIntCount() - 1)
+ Math.max(0, abc.constants.getUIntCount() - 1)
+ Math.max(0, abc.constants.getDoubleCount() - 1)
+ Math.max(0, abc.constants.getStringCount() - 1)
+ Math.max(0, abc.constants.getNamespaceCount() - 1)
+ Math.max(0, abc.constants.getNamespaceSetCount() - 1)
+ Math.max(0, abc.constants.getMultinameCount() - 1)
+ (abc.hasDecimalSupport() ? Math.max(0, abc.constants.getDecimalCount() - 1) : 0)
+ (abc.hasFloatSupport() ? (Math.max(0, abc.constants.getFloatCount() - 1) + Math.max(0, abc.constants.getFloat4Count() - 1)) : 0);
mainTabbedPane.addTab("cp (" + cpCount + ")", View.getIcon("abcconstantpool16"), cpPanel);
mainTabbedPane.addTab("mi (" + abc.method_info.size() + ")", View.getIcon(TreeType.METHOD_INFO.getIcon().getFile()), makeTreePanel(abc, TreeType.METHOD_INFO));
mainTabbedPane.addTab("md (" + abc.metadata_info.size() + ")", View.getIcon(TreeType.METADATA_INFO.getIcon().getFile()), makeTreePanel(abc, TreeType.METADATA_INFO));
mainTabbedPane.addTab("ii (" + abc.instance_info.size() + ")", View.getIcon(TreeType.INSTANCE_INFO.getIcon().getFile()), makeTreePanel(abc, TreeType.INSTANCE_INFO));
mainTabbedPane.addTab("ci (" + abc.class_info.size() + ")", View.getIcon(TreeType.CLASS_INFO.getIcon().getFile()), makeTreePanel(abc, TreeType.CLASS_INFO));
mainTabbedPane.addTab("si (" + abc.script_info.size() + ")", View.getIcon(TreeType.SCRIPT_INFO.getIcon().getFile()), makeTreePanel(abc, TreeType.SCRIPT_INFO));
mainTabbedPane.addTab("mb (" + abc.bodies.size() + ")", View.getIcon(TreeType.METHOD_BODY.getIcon().getFile()), makeTreePanel(abc, TreeType.METHOD_BODY));
}
private JTree getCurrentTree() {
JPanel pan;
if (mainTabbedPane.getSelectedIndex() == 0) { //cp
pan = (JPanel) cpTabbedPane.getSelectedComponent();
} else {
pan = (JPanel) mainTabbedPane.getSelectedComponent();
}
FasterScrollPane fasterScrollPane = (FasterScrollPane) pan.getComponent(0);
JTree tree = (JTree) fasterScrollPane.getViewport().getView();
return tree;
}
public void selectTrait(int scriptIndex, int classIndex, int traitIndex, int traitType) {
selectScriptInfo(scriptIndex);
JTree tree = getCurrentTree();
Object selection = tree.getLastSelectedPathComponent();
if (selection == null) {
return;
}
int classTraitIndexInScript = -1;
if (classIndex != -1) {
classTraitIndexInScript = findClassTraitIndexInScript(scriptIndex, classIndex);
if (classTraitIndexInScript == -1) {
return;
}
}
if (traitIndex == GraphTextWriter.TRAIT_SCRIPT_INITIALIZER) {
selectPath(tree, "si"+scriptIndex+"/init");
} else if (traitIndex == GraphTextWriter.TRAIT_CLASS_INITIALIZER) {
selectPath(tree, "si"+scriptIndex+"/traits/t"+classTraitIndexInScript+"/class_info/cinit");
} else if (traitIndex == GraphTextWriter.TRAIT_INSTANCE_INITIALIZER) {
selectPath(tree, "si"+scriptIndex+"/traits/t"+classTraitIndexInScript+"/instance_info/iinit");
} else if (traitType == GraphTextWriter.TRAIT_SCRIPT_INITIALIZER) {
selectPath(tree, "si"+scriptIndex+"/traits/t"+traitIndex);
} else if (traitType == GraphTextWriter.TRAIT_CLASS_INITIALIZER) {
selectPath(tree, "si"+scriptIndex+"/traits/t"+classTraitIndexInScript+"/class_info/traits/t"+traitIndex);
} else if (traitType == GraphTextWriter.TRAIT_INSTANCE_INITIALIZER) {
selectPath(tree, "si"+scriptIndex+"/traits/t"+classTraitIndexInScript+"/instance_info/traits/t"+traitIndex);
}
}
private int findClassTraitIndexInScript(int scriptIndex, int classIndex) {
ABC abc = getSelectedAbc();
for (int i = 0; i < abc.script_info.get(scriptIndex).traits.traits.size(); i++) {
Trait t = abc.script_info.get(scriptIndex).traits.traits.get(i);
if (t instanceof TraitClass) {
TraitClass tc = (TraitClass) t;
if (tc.class_info == classIndex) {
return i;
}
}
}
return -1;
}
private void selectPath(JTree tree, String path) {
String parts[] = path.split("/");
TreeModel model = tree.getModel();
Object root = model.getRoot();
Object parent = root;
Object treePath[] = new Object[parts.length + 1];
treePath[0] = root;
loopp:for (int p = 0; p < parts.length; p++) {
String part = parts[p];
for (int i = 0; i < model.getChildCount(parent); i++) {
Object child = model.getChild(parent, i);
String key = "";
if (child instanceof ValueWithIndex) {
ValueWithIndex vwi = (ValueWithIndex) child;
if (!vwi.getTitle().isEmpty()) {
key = vwi.getTitle();
} else {
key = vwi.getType().getAbbreviation() + vwi.getIndex();
}
} else if (child instanceof SubValue) {
SubValue sv = (SubValue) child;
key = sv.getTitle();
} else if (child instanceof SimpleValue) {
SimpleValue sv = (SimpleValue) child;
key = sv.getTitle();
}
if (key.equals(part)) {
treePath[1 + p] = child;
parent = child;
continue loopp;
}
}
return;
}
tree.setSelectionPath(new TreePath(treePath));
}
public void selectScriptInfo(int scriptIndex) {
if (mainTabbedPane.getTabCount() > 0) {
mainTabbedPane.setSelectedIndex(5);
JPanel pan = (JPanel) mainTabbedPane.getComponentAt(5);
FasterScrollPane fasterScrollPane = (FasterScrollPane) pan.getComponent(0);
JTree tree = (JTree) fasterScrollPane.getViewport().getView();
TreeModel model = tree.getModel();
if (scriptIndex >= model.getChildCount(model.getRoot())) {
return;
}
Object scriptInfoNode = model.getChild(model.getRoot(), scriptIndex);
TreePath path = new TreePath(new Object[]{
model.getRoot(),
scriptInfoNode
});
tree.setSelectionPath(path);
tree.scrollPathToVisible(path);
}
}
private JPanel makeTreePanel(ABC abc, TreeType type) {
JTree tree = new JTree(new ExplorerTreeModel(abc, type));
if (View.isOceanic()) {
tree.setBackground(Color.white);
}
tree.setCellRenderer(new ExplorerTreeCellRenderer());
tree.setUI(new BasicTreeUI() {
{
if (View.isOceanic()) {
setHashColor(Color.gray);
}
}
});
tree.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e)) {
int row = tree.getClosestRowForLocation(e.getX(), e.getY());
tree.setSelectionRow(row);
JPopupMenu popupMenu = createTreePopup(tree);
if (popupMenu == null) {
return;
}
popupMenu.show(e.getComponent(), e.getX(), e.getY());
}
}
});
JPanel treePanel = new JPanel(new BorderLayout());
treePanel.add(new FasterScrollPane(tree), BorderLayout.CENTER);
return treePanel;
}
private JPopupMenu createTreePopup(JTree tree) {
JPopupMenu menu = new JPopupMenu();
if (tree.getSelectionCount() != 1) {
return null;
}
Object selection = tree.getLastSelectedPathComponent();
if (selection instanceof ValueWithIndex) {
ValueWithIndex vwi = (ValueWithIndex) selection;
if (vwi.getType() == TreeType.SCRIPT_INFO) {
JMenuItem showInMainWindowMenuItem = new JMenuItem(translate("show.script"), View.getIcon("show16"));
showInMainWindowMenuItem.addActionListener(this::showInMainWindowActionPerformed);
menu.add(showInMainWindowMenuItem);
}
if (vwi.getType() == TreeType.METHOD_INFO || vwi.getType() == TreeType.METHOD_BODY) {
JMenuItem showInMainWindowMenuItem = new JMenuItem(translate("show.method"), View.getIcon("show16"));
showInMainWindowMenuItem.addActionListener(this::showInMainWindowActionPerformed);
menu.add(showInMainWindowMenuItem);
}
if (vwi.getType() == TreeType.INSTANCE_INFO || vwi.getType() == TreeType.CLASS_INFO) {
JMenuItem showInMainWindowMenuItem = new JMenuItem(translate("show.class"), View.getIcon("show16"));
showInMainWindowMenuItem.addActionListener(this::showInMainWindowActionPerformed);
menu.add(showInMainWindowMenuItem);
}
}
if (selection instanceof SubValue) {
SubValue sv = (SubValue) selection;
switch (sv.getIcon()) {
case TRAIT_CLASS:
case TRAIT_CONST:
case TRAIT_FUNCTION:
case TRAIT_GETTER:
case TRAIT_METHOD:
case TRAIT_SETTER:
case TRAIT_SLOT:
if (!(sv.parentValue instanceof MethodBody)) {
JMenuItem showInMainWindowMenuItem = new JMenuItem(translate("show.trait"), View.getIcon("show16"));
showInMainWindowMenuItem.addActionListener(this::showInMainWindowActionPerformed);
menu.add(showInMainWindowMenuItem);
}
break;
}
}
if (selection != null) {
JMenuItem copyRowMenuItem = new JMenuItem(translate("copy.row"), View.getIcon("copy16"));
copyRowMenuItem.addActionListener(this::copyRowActionPerformed);
menu.add(copyRowMenuItem);
}
if (selection instanceof ValueWithIndex) {
ValueWithIndex vwi = (ValueWithIndex) selection;
if (!vwi.getTitle().isEmpty()) {
JMenuItem copyTitleMenuItem = new JMenuItem(translate("copy.title"), View.getIcon("copy16"));
copyTitleMenuItem.addActionListener(this::copyTitleActionPerformed);
menu.add(copyTitleMenuItem);
}
JMenuItem copyTypeIdMenuItem = new JMenuItem(translate("copy.typeid"), View.getIcon("copy16"));
copyTypeIdMenuItem.addActionListener(this::copyTypeIdActionPerformed);
menu.add(copyTypeIdMenuItem);
if (!vwi.getDescription().isEmpty()) {
JMenuItem copyValueMenuItem = new JMenuItem(translate("copy.value"), View.getIcon("copy16"));
copyValueMenuItem.addActionListener(this::copyValueActionPerformed);
menu.add(copyValueMenuItem);
}
if (vwi.getType() == TreeType.CONSTANT_STRING && vwi.getIndex() > 0) {
JMenuItem copyRawStringValueMenuItem = new JMenuItem(translate("copy.rawstring"), View.getIcon("copy16"));
copyRawStringValueMenuItem.addActionListener(this::copyRawStringValueActionPerformed);
menu.add(copyRawStringValueMenuItem);
}
} else if (selection instanceof SubValue) {
SubValue sv = (SubValue) selection;
JMenuItem copyTitleMenuItem = new JMenuItem(translate("copy.title"), View.getIcon("copy16"));
copyTitleMenuItem.addActionListener(this::copyTitleActionPerformed);
menu.add(copyTitleMenuItem);
if (!sv.getDescription().isEmpty()) {
JMenuItem copyValueMenuItem = new JMenuItem(translate("copy.value"), View.getIcon("copy16"));
copyValueMenuItem.addActionListener(this::copyValueActionPerformed);
menu.add(copyValueMenuItem);
}
} else if (selection instanceof SimpleValue) {
SimpleValue sv = (SimpleValue) selection;
JMenuItem copyTitleMenuItem = new JMenuItem(translate("copy.title"), View.getIcon("copy16"));
copyTitleMenuItem.addActionListener(this::copyTitleActionPerformed);
menu.add(copyTitleMenuItem);
if (!sv.getValue().isEmpty()) {
JMenuItem copyValueMenuItem = new JMenuItem(translate("copy.value"), View.getIcon("copy16"));
copyValueMenuItem.addActionListener(this::copyValueActionPerformed);
menu.add(copyValueMenuItem);
}
} else {
return null;
}
return menu;
}
private void copyRowActionPerformed(ActionEvent e) {
Object selection = getCurrentTree().getLastSelectedPathComponent();
if (selection != null) {
copyToClipboard(selection.toString());
}
}
private boolean showMethodInfo(int round, ABC abc, int methodInfo, int searchMethodInfo, int scriptIndex, int classIndex, int globalTraitIndex) {
boolean found = false;
if (methodInfo == searchMethodInfo) {
found = true;
} else if (round == 2) {
MethodBody body = abc.findBody(methodInfo);
if (body != null) {
for (AVM2Instruction ins : body.getCode().code) {
if (ins.definition instanceof NewFunctionIns) {
if (ins.operands[0] == methodInfo) {
found = true;
break;
}
}
}
}
}
if (found) {
DottedChain scriptNameDc = abc.script_info.get(scriptIndex).getSimplePackName(abc);
String scriptName = (scriptNameDc == null ? "script_" + scriptIndex : scriptNameDc.toRawString());
mainPanel.gotoScriptTrait(abc.getSwf(), scriptName, classIndex, globalTraitIndex);
}
return found;
}
private boolean showMethodInfoTraits(int round, int scriptIndex, int classIndex, int methodInfo, ABC abc, Traits traits, int traitsType) {
for (int j = 0; j < traits.traits.size(); j++) {
Trait t = (Trait) traits.traits.get(j);
int globalTraitIndex = j;
if (traitsType == GraphTextWriter.TRAIT_INSTANCE_INITIALIZER) {
globalTraitIndex += abc.class_info.get(classIndex).static_traits.traits.size();
}
if (t instanceof TraitClass) {
TraitClass tc = (TraitClass) t;
if (showMethodInfo(round, abc, abc.class_info.get(tc.class_info).cinit_index, methodInfo, scriptIndex, tc.class_info, GraphTextWriter.TRAIT_CLASS_INITIALIZER)) {
return true;
}
if (showMethodInfo(round, abc, abc.instance_info.get(tc.class_info).iinit_index, methodInfo, scriptIndex, tc.class_info, GraphTextWriter.TRAIT_INSTANCE_INITIALIZER)) {
return true;
}
if (showMethodInfoTraits(round, scriptIndex, tc.class_info, methodInfo, abc, abc.class_info.get(tc.class_info).static_traits, GraphTextWriter.TRAIT_CLASS_INITIALIZER)) {
return true;
}
if (showMethodInfoTraits(round, scriptIndex, tc.class_info, methodInfo, abc, abc.instance_info.get(tc.class_info).instance_traits, GraphTextWriter.TRAIT_INSTANCE_INITIALIZER)) {
return true;
}
}
if (t instanceof TraitMethodGetterSetter) {
TraitMethodGetterSetter tmgs = (TraitMethodGetterSetter) t;
if (showMethodInfo(round, abc, tmgs.method_info, methodInfo, scriptIndex, classIndex, globalTraitIndex)) {
return true;
}
}
if (t instanceof TraitFunction) {
TraitFunction tf = (TraitFunction) t;
if (showMethodInfo(round, abc, tf.method_info, methodInfo, scriptIndex, classIndex, globalTraitIndex)) {
return true;
}
}
}
return false;
}
private void showMethodInfo(int methodInfo) {
ABC abc = getSelectedAbc();
for (int round = 1; round <= 2; round++) {
for (int i = 0; i < abc.script_info.size(); i++) {
if (showMethodInfo(round, abc, abc.script_info.get(i).init_index, methodInfo, i, -1, GraphTextWriter.TRAIT_SCRIPT_INITIALIZER)) {
return;
}
if (showMethodInfoTraits(round, i, -1, methodInfo, abc, abc.script_info.get(i).traits, GraphTextWriter.TRAIT_SCRIPT_INITIALIZER)) {
return;
}
}
}
}
private void showInMainWindowActionPerformed(ActionEvent e) {
Object selection = getCurrentTree().getLastSelectedPathComponent();
ABC abc = getSelectedAbc();
if (selection instanceof ValueWithIndex) {
ValueWithIndex vwi = (ValueWithIndex) selection;
int scriptIndex = -1;
switch (vwi.type) {
case SCRIPT_INFO:
scriptIndex = vwi.getIndex();
DottedChain scriptNameDc = abc.script_info.get(scriptIndex).getSimplePackName(abc);
String scriptName = (scriptNameDc == null ? "script_" + scriptIndex : scriptNameDc.toRawString());
mainPanel.gotoScriptName(abc.getSwf(), scriptName);
break;
case METHOD_BODY:
MethodBody body = (MethodBody) vwi.getRawValue();
if (body != null) {
showMethodInfo(body.method_info);
}
break;
case METHOD_INFO:
showMethodInfo(vwi.getIndex());
break;
case INSTANCE_INFO:
case CLASS_INFO:
int classIndex = vwi.getIndex();
loopc:
for (int i = 0; i < abc.script_info.size(); i++) {
for (int j = 0; j < abc.script_info.get(i).traits.traits.size(); j++) {
Trait t = (Trait) abc.script_info.get(i).traits.traits.get(j);
if (t instanceof TraitClass) {
TraitClass tc = (TraitClass) t;
if (tc.class_info == classIndex) {
scriptIndex = i;
break loopc;
}
}
}
}
if (scriptIndex != -1) {
DottedChain scriptNameDc2 = abc.script_info.get(scriptIndex).getSimplePackName(abc);
String scriptName2 = (scriptNameDc2 == null ? "script_" + scriptIndex : scriptNameDc2.toRawString());
mainPanel.gotoScriptTrait(abc.getSwf(), scriptName2, classIndex, GraphTextWriter.TRAIT_CLASS_INITIALIZER);
}
break;
}
}
if (selection instanceof SubValue) {
SubValue sv = (SubValue) selection;
switch (sv.getIcon()) {
case TRAIT_CLASS:
case TRAIT_CONST:
case TRAIT_FUNCTION:
case TRAIT_GETTER:
case TRAIT_METHOD:
case TRAIT_SETTER:
case TRAIT_SLOT:
int traitIndex = sv.getIndex();
int globalTraitIndex = traitIndex;
SubValue sv1 = (SubValue) sv.getParent();
ValueWithIndex wvi = (ValueWithIndex) sv1.getParent();
int scriptIndex = -1;
int classIndex = -1;
if (sv.getParentValue() instanceof ScriptInfo) {
scriptIndex = wvi.getIndex();
} else {
classIndex = wvi.getIndex();
if (sv.getParentValue() instanceof InstanceInfo) {
globalTraitIndex += abc.class_info.get(classIndex).static_traits.traits.size();
}
loopi:
for (int i = 0; i < abc.script_info.size(); i++) {
for (int j = 0; j < abc.script_info.get(i).traits.traits.size(); j++) {
Trait t = (Trait) abc.script_info.get(i).traits.traits.get(j);
if (t instanceof TraitClass) {
TraitClass tc = (TraitClass) t;
if (tc.class_info == classIndex) {
scriptIndex = i;
break loopi;
}
}
}
}
}
if (scriptIndex != -1) {
DottedChain scriptNameDc = abc.script_info.get(scriptIndex).getSimplePackName(abc);
String scriptName = (scriptNameDc == null ? "script_" + scriptIndex : scriptNameDc.toRawString());
mainPanel.gotoScriptTrait(abc.getSwf(), scriptName, classIndex, globalTraitIndex);
}
break;
}
}
}
private void copyTitleActionPerformed(ActionEvent e) {
Object selection = getCurrentTree().getLastSelectedPathComponent();
if (selection instanceof SimpleValue) {
SimpleValue sv = (SimpleValue) selection;
copyToClipboard(sv.getTitle());
}
if (selection instanceof ValueWithIndex) {
ValueWithIndex vwi = (ValueWithIndex) selection;
copyToClipboard(vwi.getTitle());
}
if (selection instanceof SubValue) {
SubValue sv = (SubValue) selection;
copyToClipboard(sv.getTitle());
}
}
private void copyValueActionPerformed(ActionEvent e) {
Object selection = getCurrentTree().getLastSelectedPathComponent();
if (selection instanceof SimpleValue) {
SimpleValue sv = (SimpleValue) selection;
copyToClipboard(sv.getValue());
}
if (selection instanceof ValueWithIndex) {
ValueWithIndex vwi = (ValueWithIndex) selection;
copyToClipboard(vwi.getDescription());
}
if (selection instanceof SubValue) {
SubValue sv = (SubValue) selection;
copyToClipboard(sv.getDescription());
}
}
private void copyRawStringValueActionPerformed(ActionEvent e) {
Object selection = getCurrentTree().getLastSelectedPathComponent();
if (selection instanceof ValueWithIndex) {
ValueWithIndex vwi = (ValueWithIndex) selection;
copyToClipboard((String) vwi.getRawValue());
}
}
private void copyTypeIdActionPerformed(ActionEvent e) {
Object selection = getCurrentTree().getLastSelectedPathComponent();
if (selection instanceof ValueWithIndex) {
ValueWithIndex vwi = (ValueWithIndex) selection;
copyToClipboard(vwi.getType().getAbbreviation() + vwi.getIndex());
}
}
private void copyToClipboard(String text) {
StringSelection stringSelection = new StringSelection(text);
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.setContents(stringSelection, null);
}
private enum TreeIcon {
CONSTANT_INT("abcint16"),
CONSTANT_UINT("abcuint16"),
CONSTANT_DOUBLE("abcdouble16"),
CONSTANT_DECIMAL("abcdecimal16"), //needs ABC decimal support
CONSTANT_FLOAT("abcfloat16"), //needs ABC float support
CONSTANT_FLOAT_4("abcfloat416"), //needs ABC float support
CONSTANT_STRING("abcstring16"),
CONSTANT_NAMESPACE("abcnamespace16"),
CONSTANT_NAMESPACE_SET("abcnamespaceset16"),
CONSTANT_MULTINAME("abcmultiname16"),
METHOD_INFO("abcmethodinfo16"),
METADATA_INFO("abcmetadata16"),
INSTANCE_INFO("abcinstanceinfo16"),
CLASS_INFO("abcclassinfo16"),
SCRIPT_INFO("abcscriptinfo16"),
METHOD_BODY("abcmethodbody16"),
TRAIT_METADATA("folder16"),
METADATA_PAIRS("folder16"),
METADATA_PAIRS_SUB(""),
TRAITS("abctraits16"),
TRAITS_SUB(""),
TRAIT_SLOT("variable"),
TRAIT_CONST("constant"),
TRAIT_CLASS("asclass16"),
TRAIT_METHOD("function"),
TRAIT_GETTER("function"),
TRAIT_SETTER("function"),
TRAIT_FUNCTION("function"),
PARAM_TYPES(""),
OPTIONAL("folder16"),
OPTIONAL_SUB(""),
PARAM_NAMES("folder16"),
EXCEPTIONS("folder16"),
EXCEPTIONS_SUB("abcexception16"),
INTERFACES("asinterface16"),
KIND("abcbulletblue16"),
FLAGS("abcflags16"),
SLOT_ID(""),
VALUE_INDEX(""),
VALUE_KIND(""),
DISP_ID(""),
MAX_STACK(""),
MAX_REGS(""),
INIT_SCOPE_DEPTH(""),
MAX_SCOPE_DEPTH(""),
CODE("abccode16"),
EXCEPTION_START(""),
EXCEPTION_END(""),
EXCEPTION_TARGET("");
private final String DEFAULT_FILE = "abcbulletgray16";
private String file;
private TreeIcon(String file) {
this.file = file;
}
public String getFile() {
if (file.isEmpty()) {
return DEFAULT_FILE;
}
return file;
}
}
private enum TreeType {
CONSTANT_INT("Integers", "int", TreeIcon.CONSTANT_INT),
CONSTANT_UINT("UnsignedIntegers", "uint", TreeIcon.CONSTANT_UINT),
CONSTANT_DOUBLE("Doubles", "dbl", TreeIcon.CONSTANT_DOUBLE),
CONSTANT_DECIMAL("Decimals", "dc", TreeIcon.CONSTANT_DECIMAL), //needs ABC decimal support
CONSTANT_FLOAT("Floats", "fl", TreeIcon.CONSTANT_FLOAT), //needs ABC float support
CONSTANT_FLOAT_4("Floats4", "fl4", TreeIcon.CONSTANT_FLOAT_4), //needs ABC float support
CONSTANT_STRING("Strings", "str", TreeIcon.CONSTANT_STRING),
CONSTANT_NAMESPACE("Namespaces", "ns", TreeIcon.CONSTANT_NAMESPACE),
CONSTANT_NAMESPACE_SET("NamespaceSets", "nss", TreeIcon.CONSTANT_NAMESPACE_SET),
CONSTANT_MULTINAME("Multinames", "mn", TreeIcon.CONSTANT_MULTINAME),
METHOD_INFO("MethodInfos", "mi", TreeIcon.METHOD_INFO),
METADATA_INFO("MetadataInfos", "md", TreeIcon.METADATA_INFO),
INSTANCE_INFO("InstanceInfos", "ii", TreeIcon.INSTANCE_INFO),
CLASS_INFO("ClassInfos", "ci", TreeIcon.CLASS_INFO),
SCRIPT_INFO("ScriptInfos", "si", TreeIcon.SCRIPT_INFO),
METHOD_BODY("MethodBodys", "mb", TreeIcon.METHOD_BODY);
private final String name;
private final String abbreviation;
private final TreeIcon icon;
TreeType(String name, String abbreviation, TreeIcon icon) {
this.name = name;
this.abbreviation = abbreviation;
this.icon = icon;
}
public String getName() {
return name;
}
public String getAbbreviation() {
return abbreviation;
}
public TreeIcon getIcon() {
return icon;
}
@Override
public String toString() {
return name;
}
}
private class SimpleValue implements HasIcon {
private final int currentLevelIndex;
private final Object parent;
private final String title;
private final TreeIcon icon;
private final String value;
public SimpleValue(Object parent, int currentLevelIndex, String title, String value, TreeIcon icon) {
this.currentLevelIndex = currentLevelIndex;
this.parent = parent;
this.title = title;
this.icon = icon;
this.value = value;
}
public String getTitle() {
return title;
}
public String getValue() {
return value;
}
@Override
public TreeIcon getIcon() {
return icon;
}
public int getCurrentLevelIndex() {
return currentLevelIndex;
}
public Object getParent() {
return parent;
}
@Override
public String toString() {
return title + (!value.isEmpty() ? ": " + value : "");
}
@Override
public int hashCode() {
int hash = 7;
hash = 47 * hash + this.currentLevelIndex;
hash = 47 * hash + Objects.hashCode(this.parent);
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final SimpleValue other = (SimpleValue) obj;
if (this.currentLevelIndex != other.currentLevelIndex) {
return false;
}
return Objects.equals(this.parent, other.parent);
}
}
private interface HasIcon {
public TreeIcon getIcon();
}
private class SubValue implements HasIcon {
private final int currentLevelIndex;
private final Object parent;
private final Object parentValue;
private final String property;
private final String title;
private final int index;
private final TreeIcon icon;
private final String description;
public SubValue(Object parent, int currentLevelIndex, Object parentValue, String property, String title, String description, TreeIcon icon) {
this.currentLevelIndex = currentLevelIndex;
this.parent = parent;
this.parentValue = parentValue;
this.property = property;
this.title = title;
this.index = -1;
this.icon = icon;
this.description = description;
}
public SubValue(Object parent, int currentLevelIndex, int index, Object parentValue, String property, String title, String description, TreeIcon icon) {
this.currentLevelIndex = currentLevelIndex;
this.index = index;
this.parent = parent;
this.parentValue = parentValue;
this.property = property;
this.title = title;
this.icon = icon;
this.description = description;
}
public int getIndex() {
return index;
}
public int getCurrentLevelIndex() {
return currentLevelIndex;
}
@Override
public String toString() {
return title + (!description.isEmpty() ? ": " + description : "");
}
public Object getParent() {
return parent;
}
public Object getParentValue() {
return parentValue;
}
public String getProperty() {
return property;
}
public String getTitle() {
return title;
}
public String getDescription() {
return description;
}
@Override
public int hashCode() {
int hash = 7;
hash = 41 * hash + this.currentLevelIndex;
hash = 41 * hash + Objects.hashCode(this.parent);
hash = 41 * hash + Objects.hashCode(this.property);
hash = 41 * hash + this.index;
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final SubValue other = (SubValue) obj;
if (this.currentLevelIndex != other.currentLevelIndex) {
return false;
}
if (this.index != other.index) {
return false;
}
if (!Objects.equals(this.property, other.property)) {
return false;
}
return Objects.equals(this.parent, other.parent);
}
@Override
public TreeIcon getIcon() {
return icon;
}
}
private class ValueWithIndex implements HasIcon {
private final Object parent;
private final int index;
private final int currentLevelIndex;
private final TreeType type;
private final Object value;
private final String description;
private final String title;
public ValueWithIndex(Object parent, int currentLevelIndex, int index, TreeType type, Object value, String description) {
this.parent = parent;
this.currentLevelIndex = currentLevelIndex;
this.index = index;
this.type = type;
this.value = value;
this.description = description;
this.title = "";
}
public ValueWithIndex(Object parent, int currentLevelIndex, int index, TreeType type, Object value, String description, String title) {
this.parent = parent;
this.currentLevelIndex = currentLevelIndex;
this.index = index;
this.type = type;
this.value = value;
this.description = description;
this.title = title;
}
public Object getRawValue() {
return value;
}
public int getCurrentLevelIndex() {
return currentLevelIndex;
}
public Object getParent() {
return parent;
}
public int getIndex() {
return index;
}
public TreeType getType() {
return type;
}
public String getTitle() {
return title;
}
public String getDescription() {
return description;
}
@Override
public String toString() {
boolean implicit = false;
if (index == 0) {
switch (type) {
case CONSTANT_INT:
case CONSTANT_UINT:
case CONSTANT_DOUBLE:
case CONSTANT_DECIMAL:
case CONSTANT_FLOAT:
case CONSTANT_FLOAT_4:
case CONSTANT_STRING:
case CONSTANT_NAMESPACE:
case CONSTANT_NAMESPACE_SET:
case CONSTANT_MULTINAME:
implicit = true;
}
}
return (!title.isEmpty() ? title + ": " : "") + (implicit ? "[" : "") + type.getAbbreviation() + index + (implicit ? "]" : "") + ": " + description;
}
@Override
public int hashCode() {
int hash = 3;
hash = 31 * hash + Objects.hashCode(this.parent);
hash = 31 * hash + this.currentLevelIndex;
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final ValueWithIndex other = (ValueWithIndex) obj;
if (this.currentLevelIndex != other.currentLevelIndex) {
return false;
}
return Objects.equals(this.parent, other.parent);
}
@Override
public TreeIcon getIcon() {
return type.getIcon();
}
}
private class ExplorerTreeModel implements TreeModel {
private TreeType type;
private ABC abc;
public ExplorerTreeModel(ABC abc, TreeType type) {
this.type = type;
this.abc = abc;
}
@Override
public Object getRoot() {
return type;
}
private ValueWithIndex createValueWithIndex(Object parent, int currentLevelIndex, int index, TreeType valueType, String title) {
if (index == 0) {
switch (valueType) {
case CONSTANT_INT:
case CONSTANT_UINT:
case CONSTANT_DOUBLE:
case CONSTANT_DECIMAL:
case CONSTANT_FLOAT:
case CONSTANT_FLOAT_4:
case CONSTANT_STRING:
case CONSTANT_NAMESPACE:
case CONSTANT_NAMESPACE_SET:
case CONSTANT_MULTINAME:
return new ValueWithIndex(parent, currentLevelIndex, index, valueType, null, "null", title);
}
}
switch (valueType) {
case CONSTANT_INT:
if (index >= abc.constants.getIntCount()) {
return new ValueWithIndex(parent, currentLevelIndex, index, valueType, null, "Unknown(" + index + ")", title);
}
return new ValueWithIndex(parent, currentLevelIndex, index, valueType, abc.constants.getInt(index), "" + abc.constants.getInt(index), title);
case CONSTANT_UINT:
if (index >= abc.constants.getUIntCount()) {
return new ValueWithIndex(parent, currentLevelIndex, index, valueType, null, "Unknown(" + index + ")", title);
}
return new ValueWithIndex(parent, currentLevelIndex, index, valueType, abc.constants.getUInt(index), "" + abc.constants.getUInt(index), title);
case CONSTANT_DOUBLE:
if (index >= abc.constants.getDoubleCount()) {
return new ValueWithIndex(parent, currentLevelIndex, index, valueType, null, "Unknown(" + index + ")", title);
}
return new ValueWithIndex(parent, currentLevelIndex, index, valueType, abc.constants.getDouble(index), EcmaScript.toString(abc.constants.getDouble(index)), title);
case CONSTANT_DECIMAL:
if (index >= abc.constants.getDecimalCount()) {
return new ValueWithIndex(parent, currentLevelIndex, index, valueType, null, "Unknown(" + index + ")", title);
}
return new ValueWithIndex(parent, currentLevelIndex, index, valueType, abc.constants.getDecimal(index), "" + abc.constants.getDecimal(index), title);
case CONSTANT_FLOAT:
if (index >= abc.constants.getFloatCount()) {
return new ValueWithIndex(parent, currentLevelIndex, index, valueType, null, "Unknown(" + index + ")", title);
}
return new ValueWithIndex(parent, currentLevelIndex, index, valueType, abc.constants.getFloat(index), EcmaScript.toString(abc.constants.getFloat(index)), title);
case CONSTANT_FLOAT_4:
if (index >= abc.constants.getFloat4Count()) {
return new ValueWithIndex(parent, currentLevelIndex, index, valueType, null, "Unknown(" + index + ")", title);
}
Float4 f4 = abc.constants.getFloat4(index);
return new ValueWithIndex(parent, currentLevelIndex, index, valueType, f4,
EcmaScript.toString(f4.values[0]) + " "
+ EcmaScript.toString(f4.values[1]) + " "
+ EcmaScript.toString(f4.values[2]) + " "
+ EcmaScript.toString(f4.values[3]),
title
);
case CONSTANT_STRING:
return new ValueWithIndex(parent, currentLevelIndex, index, valueType, index < abc.constants.getStringCount() ? abc.constants.getString(index) : null, formatString(index), title);
case CONSTANT_NAMESPACE:
return new ValueWithIndex(parent, currentLevelIndex, index, valueType, index < abc.constants.getNamespaceCount() ? abc.constants.getNamespace(index) : null, Multiname.namespaceToString(abc.constants, index), title);
case CONSTANT_NAMESPACE_SET:
return new ValueWithIndex(parent, currentLevelIndex, index, valueType, abc.constants.getNamespaceSet(index), Multiname.namespaceSetToString(abc.constants, index), title);
case CONSTANT_MULTINAME:
return new ValueWithIndex(parent, currentLevelIndex, index, valueType, index < abc.constants.getMultinameCount() ? abc.constants.getMultiname(index) : null,
index < abc.constants.getMultinameCount()
? abc.constants.getMultiname(index).toString(abc.constants, new ArrayList<DottedChain>())
: "Unknown(" + index + ")",
title);
case METHOD_INFO:
if (index >= abc.method_info.size()) {
return new ValueWithIndex(parent, currentLevelIndex, index, valueType, null, "Unknown(" + index + ")", title);
}
MethodInfo mi = abc.method_info.get(index);
StringBuilder miStrSb = new StringBuilder();
miStrSb.append("(");
StringBuilderTextWriter miParamStrSbW = new StringBuilderTextWriter(new CodeFormatting(), miStrSb);
mi.getParamStr(miParamStrSbW, abc.constants, null, abc, new ArrayList<>());
miStrSb.append("): ");
String miReturnType = mi.getReturnTypeRaw(abc.constants, new ArrayList<>());
miStrSb.append(miReturnType);
return new ValueWithIndex(parent, currentLevelIndex, index, valueType, mi, miStrSb.toString(), title);
case METHOD_BODY:
if (index >= abc.bodies.size()) {
return new ValueWithIndex(parent, currentLevelIndex, index, valueType, null, "Unknown(" + index + ")", title);
}
MethodBody b = abc.bodies.get(index);
String exceptionsAdd = "";
if (b.exceptions.length > 0) {
exceptionsAdd = ", " + b.exceptions.length + " exceptions";
}
return new ValueWithIndex(parent, currentLevelIndex, index, valueType, b, "mi" + b.method_info + ", " + b.getCodeBytes().length + " bytes code" + exceptionsAdd, title);
case INSTANCE_INFO:
if (index >= abc.instance_info.size()) {
return new ValueWithIndex(parent, currentLevelIndex, index, valueType, null, "Unknown(" + index + ")", title);
}
InstanceInfo ii = abc.instance_info.get(index);
String iiName;
if (ii.name_index >= abc.constants.getMultinameCount() || ii.getName(abc.constants).namespace_index >= abc.constants.getNamespaceCount()) {
iiName = "";
} else {
iiName = "\"" + Helper.escapePCodeString(ii.getName(abc.constants).getNameWithNamespace(abc.constants, false).toRawString()) + "\"";
}
return new ValueWithIndex(parent, currentLevelIndex, index, TreeType.INSTANCE_INFO, ii, iiName + (ii.instance_traits.traits.isEmpty() ? "" : ", " + ii.instance_traits.traits.size() + " traits"), title);
case CLASS_INFO:
if (index >= abc.class_info.size()) {
return new ValueWithIndex(parent, currentLevelIndex, index, valueType, null, "Unknown(" + index + ")", title);
}
ClassInfo ci = abc.class_info.get(index);
return new ValueWithIndex(parent, currentLevelIndex, index, TreeType.CLASS_INFO, ci, "mi" + ci.cinit_index + (ci.static_traits.traits.isEmpty() ? "" : ", " + ci.static_traits.traits.size() + " traits"), title);
case SCRIPT_INFO:
if (index >= abc.script_info.size()) {
return new ValueWithIndex(parent, currentLevelIndex, index, valueType, null, "Unknown(" + index + ")", title);
}
ScriptInfo si = abc.script_info.get(index);
String siName = "";
try {
DottedChain simplePackName = si.getSimplePackName(abc);
if (simplePackName != null) {
siName = " (\"" + Helper.escapePCodeString(simplePackName.toRawString()) + "\")";
}
} catch (IndexOutOfBoundsException iob) {
//ignore
}
return new ValueWithIndex(parent, currentLevelIndex, index, TreeType.SCRIPT_INFO, si, "mi" + si.init_index + (si.traits.traits.isEmpty() ? "" : ", " + si.traits.traits.size() + " traits") + siName, title);
case METADATA_INFO:
if (index >= abc.metadata_info.size()) {
return new ValueWithIndex(parent, currentLevelIndex, index, valueType, null, "Unknown(" + index + ")", title);
}
MetadataInfo md = abc.metadata_info.get(index);
String mdName = formatString(md.name_index);
mdName += " (" + md.values.length + " items)";
return new ValueWithIndex(parent, currentLevelIndex, index, TreeType.METADATA_INFO, md, mdName);
default:
return new ValueWithIndex(parent, currentLevelIndex, index, valueType, null, "", title);
}
}
private int handleGetChildCountTrait(SubValue sv, Traits traits) {
if (sv.getIndex() > -1) {
Trait t = traits.traits.get(sv.getIndex());
int count = 3;
if ((t.kindFlags & Trait.ATTR_Metadata) > 0) {
count++;
}
if (t instanceof TraitSlotConst) {
TraitSlotConst tsc = (TraitSlotConst) t;
if (tsc.value_index == 0) {
return count + 3;
}
return count + 4;
}
if (t instanceof TraitMethodGetterSetter) {
return count + 2;
}
if (t instanceof TraitClass) {
return count + 3;
}
if (t instanceof TraitFunction) {
return count + 2;
}
}
return traits.traits.size();
}
private Object handleGetChildTrait(Object parent, int index, Object parentValue, SubValue sv, Traits traits) {
if (sv.getIndex() > -1) {
Trait t = traits.traits.get(sv.getIndex());
int currentIndex = 0;
switch (index) {
case 0:
return createValueWithIndex(parent, index, t.name_index, TreeType.CONSTANT_MULTINAME, "name");
case 1:
return new SimpleValue(parent, index, "kind", String.format("0x%02X", t.kindType) + " (" + t.getKindToStr() + ")", TreeIcon.KIND);
case 2:
List<String> flagList = new ArrayList<>();
if ((t.kindFlags & Trait.ATTR_Final) > 0) {
flagList.add("FINAL");
}
if ((t.kindFlags & Trait.ATTR_Override) > 0) {
flagList.add("OVERRIDE");
}
if ((t.kindFlags & Trait.ATTR_Metadata) > 0) {
flagList.add("METADATA");
}
if ((t.kindFlags & Trait.ATTR_0x8) > 0) {
flagList.add("0x8");
}
return new SimpleValue(parent, index, "kind_flags", String.format("0x%02X", t.kindFlags) + (flagList.isEmpty() ? "" : " (" + String.join(", ", flagList) + ")"), TreeIcon.FLAGS);
}
if (t instanceof TraitSlotConst) {
TraitSlotConst tsc = (TraitSlotConst) t;
switch (index) {
case 3:
return new SimpleValue(parent, index, "slot_id", "" + tsc.slot_id, TreeIcon.SLOT_ID);
case 4:
return createValueWithIndex(parent, index, tsc.type_index, TreeType.CONSTANT_MULTINAME, "type");
case 5:
if (tsc.value_index == 0) {
return new SimpleValue(parent, index, "value_index", "null", TreeIcon.VALUE_INDEX);
}
switch (tsc.value_kind) {
case ValueKind.CONSTANT_Int:
return createValueWithIndex(parent, index, tsc.value_index, TreeType.CONSTANT_INT, "value_index");
case ValueKind.CONSTANT_UInt:
return createValueWithIndex(parent, index, tsc.value_index, TreeType.CONSTANT_UINT, "value_index");
case ValueKind.CONSTANT_Double:
return createValueWithIndex(parent, index, tsc.value_index, TreeType.CONSTANT_DOUBLE, "value_index");
case ValueKind.CONSTANT_DecimalOrFloat: //?? or float ??
return createValueWithIndex(parent, index, tsc.value_index, TreeType.CONSTANT_DECIMAL, "value_index");
case ValueKind.CONSTANT_Utf8:
return createValueWithIndex(parent, index, tsc.value_index, TreeType.CONSTANT_STRING, "value_index");
case ValueKind.CONSTANT_True:
case ValueKind.CONSTANT_False:
case ValueKind.CONSTANT_Null:
case ValueKind.CONSTANT_Undefined:
return new SimpleValue(parent, index, "value_index", "" + tsc.value_index, TreeIcon.VALUE_INDEX);
case ValueKind.CONSTANT_Namespace:
case ValueKind.CONSTANT_PackageInternalNs:
case ValueKind.CONSTANT_ProtectedNamespace:
case ValueKind.CONSTANT_ExplicitNamespace:
case ValueKind.CONSTANT_StaticProtectedNs:
case ValueKind.CONSTANT_PrivateNs:
return createValueWithIndex(parent, index, tsc.value_index, TreeType.CONSTANT_NAMESPACE, "value_index");
}
case 6:
switch (tsc.value_kind) {
case ValueKind.CONSTANT_Int:
return new SimpleValue(parent, index, "value_kind", "Integer", TreeIcon.VALUE_KIND);
case ValueKind.CONSTANT_UInt:
return new SimpleValue(parent, index, "value_kind", "UInteger", TreeIcon.VALUE_KIND);
case ValueKind.CONSTANT_Double:
return new SimpleValue(parent, index, "value_kind", "Double", TreeIcon.VALUE_KIND);
case ValueKind.CONSTANT_DecimalOrFloat: //?? or float ??
return new SimpleValue(parent, index, "value_kind", "Decimal", TreeIcon.VALUE_KIND);
case ValueKind.CONSTANT_Utf8:
return new SimpleValue(parent, index, "value_kind", "String", TreeIcon.VALUE_KIND);
case ValueKind.CONSTANT_True:
return new SimpleValue(parent, index, "value_kind", "True", TreeIcon.VALUE_KIND);
case ValueKind.CONSTANT_False:
return new SimpleValue(parent, index, "value_kind", "False", TreeIcon.VALUE_KIND);
case ValueKind.CONSTANT_Null:
return new SimpleValue(parent, index, "value_kind", "Null", TreeIcon.VALUE_KIND);
case ValueKind.CONSTANT_Undefined:
return new SimpleValue(parent, index, "value_kind", "Undefined", TreeIcon.VALUE_KIND);
case ValueKind.CONSTANT_Namespace:
return new SimpleValue(parent, index, "value_kind", "Namespace", TreeIcon.VALUE_KIND);
case ValueKind.CONSTANT_PackageInternalNs:
return new SimpleValue(parent, index, "value_kind", "PackageInternalNs", TreeIcon.VALUE_KIND);
case ValueKind.CONSTANT_ProtectedNamespace:
return new SimpleValue(parent, index, "value_kind", "ProtectedNamespace", TreeIcon.VALUE_KIND);
case ValueKind.CONSTANT_ExplicitNamespace:
return new SimpleValue(parent, index, "value_kind", "ExplicitNamespace", TreeIcon.VALUE_KIND);
case ValueKind.CONSTANT_StaticProtectedNs:
return new SimpleValue(parent, index, "value_kind", "StaticProtectedNs", TreeIcon.VALUE_KIND);
case ValueKind.CONSTANT_PrivateNs:
return new SimpleValue(parent, index, "value_kind", "PrivateNamespace", TreeIcon.VALUE_KIND);
}
}
currentIndex = 7;
}
if (t instanceof TraitMethodGetterSetter) {
TraitMethodGetterSetter tmgs = (TraitMethodGetterSetter) t;
switch (index) {
case 3:
return new SimpleValue(parent, index, "disp_id", "" + tmgs.disp_id, TreeIcon.DISP_ID);
case 4:
return createValueWithIndex(parent, index, tmgs.method_info, TreeType.METHOD_INFO, "method_info");
}
currentIndex = 5;
}
if (t instanceof TraitClass) {
TraitClass tc = (TraitClass) t;
switch (index) {
case 3:
return new SimpleValue(parent, index, "slot_id", "" + tc.slot_id, TreeIcon.SLOT_ID);
case 4:
return createValueWithIndex(parent, index, tc.class_info, TreeType.INSTANCE_INFO, "instance_info");
case 5:
return createValueWithIndex(parent, index, tc.class_info, TreeType.CLASS_INFO, "class_info");
}
currentIndex = 6;
}
if (t instanceof TraitFunction) {
TraitFunction tf = (TraitFunction) t;
switch (index) {
case 3:
return new SimpleValue(parent, index, "slot_id", "" + tf.slot_id, TreeIcon.SLOT_ID);
case 4:
return createValueWithIndex(parent, index, tf.method_info, TreeType.METHOD_INFO, "method_index");
}
currentIndex = 5;
}
if (index == currentIndex) {
if ((t.kindFlags & Trait.ATTR_Metadata) > 0) {
return new SubValue(parent, currentIndex, t, "metadata", "metadata", "", TreeIcon.TRAIT_METADATA);
}
}
}
Trait t = traits.traits.get(index);
String traitName = formatString(t.getName(abc).name_index);
TreeIcon icon = TreeIcon.TRAITS_SUB;
switch (t.kindType) {
case Trait.TRAIT_CLASS:
icon = TreeIcon.TRAIT_CLASS;
break;
case Trait.TRAIT_CONST:
icon = TreeIcon.TRAIT_CONST;
break;
case Trait.TRAIT_FUNCTION:
icon = TreeIcon.TRAIT_FUNCTION;
break;
case Trait.TRAIT_GETTER:
icon = TreeIcon.TRAIT_GETTER;
break;
case Trait.TRAIT_METHOD:
icon = TreeIcon.TRAIT_METHOD;
break;
case Trait.TRAIT_SETTER:
icon = TreeIcon.TRAIT_SETTER;
break;
case Trait.TRAIT_SLOT:
icon = TreeIcon.TRAIT_SLOT;
break;
}
return new SubValue(parent, index, index, parentValue, "traits", "t" + index, t.getKindToStr() + ": " + traitName, icon);
}
private String formatString(int index) {
if (index == 0) {
return "null";
}
if (index >= abc.constants.getStringCount()) {
return "Unknown(" + index + ")";
}
return "\"" + Helper.escapePCodeString(abc.constants.getString(index)) + "\"";
}
@Override
public Object getChild(Object parent, int index) {
if (parent == type) {
return createValueWithIndex(parent, index, index, type, "");
}
if (parent instanceof ValueWithIndex) {
ValueWithIndex vwi = (ValueWithIndex) parent;
if (vwi.value instanceof NamespaceSet) {
NamespaceSet nss = (NamespaceSet) vwi.value;
int ns = nss.namespaces[index];
return new ValueWithIndex(parent, index, ns, TreeType.CONSTANT_NAMESPACE, abc.constants.getNamespace(ns), Multiname.namespaceToString(abc.constants, ns));
}
if (vwi.value instanceof Namespace) {
Namespace ns = (Namespace) vwi.value;
switch (index) {
case 0:
return new SimpleValue(parent, index, "kind", Namespace.kindToStr(ns.kind), TreeIcon.KIND);
case 1:
return createValueWithIndex(parent, index, ns.name_index, TreeType.CONSTANT_STRING, "name");
}
}
if (vwi.value instanceof Multiname) {
Multiname m = (Multiname) vwi.value;
if (index == 0) {
return new SimpleValue(parent, index, "kind", m.getKindStr(), TreeIcon.KIND);
}
int kind = m.kind;
if ((kind == Multiname.QNAME) || (kind == Multiname.QNAMEA)) {
switch (index) {
case 1:
return createValueWithIndex(parent, index, m.namespace_index, TreeType.CONSTANT_NAMESPACE, "namespace");
case 2:
return createValueWithIndex(parent, index, m.name_index, TreeType.CONSTANT_STRING, "name");
}
} else if ((kind == Multiname.RTQNAME) || (kind == Multiname.RTQNAMEA)) {
if (index == 1) {
return createValueWithIndex(parent, index, m.name_index, TreeType.CONSTANT_STRING, "name");
}
} else if ((kind == Multiname.RTQNAMEL) || (kind == Multiname.RTQNAMELA)) {
//ignore
} else if ((kind == Multiname.MULTINAME) || (kind == Multiname.MULTINAMEA)) {
switch (index) {
case 1:
return createValueWithIndex(parent, index, m.name_index, TreeType.CONSTANT_STRING, "name");
case 2:
return createValueWithIndex(parent, index, m.namespace_set_index, TreeType.CONSTANT_NAMESPACE_SET, "namespace_set");
}
} else if ((kind == Multiname.MULTINAMEL) || (kind == Multiname.MULTINAMELA)) {
if (index == 1) {
return createValueWithIndex(parent, index, m.namespace_set_index, TreeType.CONSTANT_NAMESPACE_SET, "namespace_set");
}
} else if (kind == Multiname.TYPENAME) {
if (index == 1) {
return createValueWithIndex(parent, index, m.qname_index, TreeType.CONSTANT_MULTINAME, "qname");
}
if (index >= 2 && index - 2 < m.params.length) {
return createValueWithIndex(parent, index, m.params[index - 2], TreeType.CONSTANT_MULTINAME, "param" + (index - 2));
}
}
}
if (vwi.value instanceof MethodInfo) {
MethodInfo mi = (MethodInfo) vwi.value;
switch (index) {
case 0:
return new SubValue(parent, index, mi, "param_types", "param_types", "", TreeIcon.PARAM_TYPES);
case 1:
return createValueWithIndex(parent, index, mi.ret_type, TreeType.CONSTANT_MULTINAME, "return_type");
case 2:
return createValueWithIndex(parent, index, mi.name_index, TreeType.CONSTANT_STRING, "name");
case 3:
List<String> flagList = new ArrayList<>();
if (mi.flagNative()) {
flagList.add("NATIVE");
}
if (mi.flagHas_optional()) {
flagList.add("HAS_OPTIONAL");
}
if (mi.flagHas_paramnames()) {
flagList.add("HAS_PARAM_NAMES");
}
if (mi.flagIgnore_rest()) {
flagList.add("IGNORE_REST");
}
if (mi.flagNeed_activation()) {
flagList.add("NEED_ACTIVATION");
}
if (mi.flagNeed_arguments()) {
flagList.add("NEED_ARGUMENTS");
}
if (mi.flagNeed_rest()) {
flagList.add("NEED_REST");
}
if (mi.flagSetsdxns()) {
flagList.add("SET_DXNS");
}
return new SimpleValue(parent, index, "flags", String.format("0x%02X", mi.flags) + (!flagList.isEmpty() ? " (" + String.join(", ", flagList) + ")" : ""), TreeIcon.FLAGS);
}
int currentIndex = 4;
if (mi.flagHas_optional()) {
if (index == currentIndex) {
return new SubValue(parent, index, mi, "optional", "optional", "", TreeIcon.OPTIONAL);
}
currentIndex++;
}
if (mi.flagHas_paramnames()) {
if (index == currentIndex) {
return new SubValue(parent, index, mi, "param_names", "param_names", "", TreeIcon.PARAM_NAMES);
}
currentIndex++;
}
if (index == currentIndex) {
int bodyIndex = abc.findBodyIndex(vwi.getIndex());
if (bodyIndex != -1) {
return createValueWithIndex(parent, index, bodyIndex, TreeType.METHOD_BODY, "method_body");
}
}
}
if (vwi.value instanceof MethodBody) {
MethodBody body = (MethodBody) vwi.value;
switch (index) {
case 0:
return createValueWithIndex(parent, index, body.method_info, TreeType.METHOD_INFO, "method_info");
case 1:
return new SimpleValue(parent, index, "max_stack", "" + body.max_stack, TreeIcon.MAX_STACK);
case 2:
return new SimpleValue(parent, index, "max_regs", "" + body.max_regs, TreeIcon.MAX_REGS);
case 3:
return new SimpleValue(parent, index, "init_scope_depth", "" + body.init_scope_depth, TreeIcon.INIT_SCOPE_DEPTH);
case 4:
return new SimpleValue(parent, index, "max_scope_depth", "" + body.max_scope_depth, TreeIcon.MAX_SCOPE_DEPTH);
case 5:
return new SimpleValue(parent, index, "code", "" + body.getCodeBytes().length + " bytes", TreeIcon.CODE);
case 6:
return new SubValue(parent, index, body, "exceptions", "exceptions", "", TreeIcon.EXCEPTIONS);
case 7:
return new SubValue(parent, index, body, "traits", "traits", "", TreeIcon.TRAITS);
}
}
if (vwi.value instanceof InstanceInfo) {
InstanceInfo ii = (InstanceInfo) vwi.value;
switch (index) {
case 0:
return createValueWithIndex(parent, index, ii.name_index, TreeType.CONSTANT_MULTINAME, "name");
case 1:
return createValueWithIndex(parent, index, ii.super_index, TreeType.CONSTANT_MULTINAME, "super");
case 2:
List<String> flagList = new ArrayList<>();
if ((ii.flags & InstanceInfo.CLASS_SEALED) == InstanceInfo.CLASS_SEALED) {
flagList.add("SEALED");
}
if ((ii.flags & InstanceInfo.CLASS_FINAL) == InstanceInfo.CLASS_FINAL) {
flagList.add("FINAL");
}
if ((ii.flags & InstanceInfo.CLASS_INTERFACE) == InstanceInfo.CLASS_INTERFACE) {
flagList.add("INTERFACE");
}
if ((ii.flags & InstanceInfo.CLASS_PROTECTEDNS) == InstanceInfo.CLASS_PROTECTEDNS) {
flagList.add("PROTECTEDNS");
}
if ((ii.flags & InstanceInfo.CLASS_NON_NULLABLE) == InstanceInfo.CLASS_NON_NULLABLE) {
flagList.add("NON_NULLABLE");
}
return new SimpleValue(parent, index, "flags", String.format("0x%02X", ii.flags) + (!flagList.isEmpty() ? " (" + String.join(", ", flagList) + ")" : ""), TreeIcon.FLAGS);
}
int currentIndex = 3;
if ((ii.flags & InstanceInfo.CLASS_PROTECTEDNS) == InstanceInfo.CLASS_PROTECTEDNS) {
if (index == currentIndex) {
return createValueWithIndex(parent, index, ii.protectedNS, TreeType.CONSTANT_NAMESPACE, "protected_ns");
}
currentIndex++;
}
if (index == currentIndex) {
return new SubValue(parent, index, ii, "interfaces", "interfaces", "", TreeIcon.INTERFACES);
}
currentIndex++;
if (index == currentIndex) {
return createValueWithIndex(parent, currentIndex, ii.iinit_index, TreeType.METHOD_INFO, "iinit");
}
currentIndex++;
if (index == currentIndex) {
return new SubValue(parent, index, ii, "traits", "traits", "", TreeIcon.TRAITS);
}
}
if (vwi.value instanceof ClassInfo) {
ClassInfo ci = (ClassInfo) vwi.value;
switch (index) {
case 0:
return createValueWithIndex(parent, index, ci.cinit_index, TreeType.METHOD_INFO, "cinit");
case 1:
return new SubValue(parent, index, ci, "traits", "traits", "", TreeIcon.TRAITS);
}
}
if (vwi.value instanceof ScriptInfo) {
ScriptInfo si = (ScriptInfo) vwi.value;
switch (index) {
case 0:
return createValueWithIndex(parent, index, si.init_index, TreeType.METHOD_INFO, "init");
case 1:
return new SubValue(parent, index, si, "traits", "traits", "", TreeIcon.TRAITS);
}
}
if (vwi.value instanceof MetadataInfo) {
MetadataInfo md = (MetadataInfo) vwi.value;
switch (index) {
case 0:
return createValueWithIndex(parent, index, md.name_index, TreeType.CONSTANT_STRING, "name");
case 1:
return new SubValue(parent, index, md, "pairs", "pairs", "", TreeIcon.METADATA_PAIRS);
}
}
}
if (parent instanceof SubValue) {
SubValue sv = (SubValue) parent;
if (sv.getParentValue() instanceof MethodInfo) {
MethodInfo mi = (MethodInfo) sv.getParentValue();
switch (sv.getProperty()) {
case "param_types":
return createValueWithIndex(parent, index, mi.param_types[index], TreeType.CONSTANT_MULTINAME, "pt" + index);
case "optional":
if (sv.getIndex() > -1) {
if (index == 0) {
switch (mi.optional[sv.getIndex()].value_kind) {
case ValueKind.CONSTANT_Int:
return new SimpleValue(parent, index, "value_kind", "Integer", TreeIcon.VALUE_KIND);
case ValueKind.CONSTANT_UInt:
return new SimpleValue(parent, index, "value_kind", "UInteger", TreeIcon.VALUE_KIND);
case ValueKind.CONSTANT_Double:
return new SimpleValue(parent, index, "value_kind", "Double", TreeIcon.VALUE_KIND);
case ValueKind.CONSTANT_DecimalOrFloat: //?? or float ??
return new SimpleValue(parent, index, "value_kind", "Decimal", TreeIcon.VALUE_KIND);
case ValueKind.CONSTANT_Utf8:
return new SimpleValue(parent, index, "value_kind", "String", TreeIcon.VALUE_KIND);
case ValueKind.CONSTANT_True:
return new SimpleValue(parent, index, "value_kind", "True", TreeIcon.VALUE_KIND);
case ValueKind.CONSTANT_False:
return new SimpleValue(parent, index, "value_kind", "False", TreeIcon.VALUE_KIND);
case ValueKind.CONSTANT_Null:
return new SimpleValue(parent, index, "value_kind", "Null", TreeIcon.VALUE_KIND);
case ValueKind.CONSTANT_Undefined:
return new SimpleValue(parent, index, "value_kind", "Undefined", TreeIcon.VALUE_KIND);
case ValueKind.CONSTANT_Namespace:
return new SimpleValue(parent, index, "value_kind", "Namespace", TreeIcon.VALUE_KIND);
case ValueKind.CONSTANT_PackageInternalNs:
return new SimpleValue(parent, index, "value_kind", "PackageInternalNs", TreeIcon.VALUE_KIND);
case ValueKind.CONSTANT_ProtectedNamespace:
return new SimpleValue(parent, index, "value_kind", "ProtectedNamespace", TreeIcon.VALUE_KIND);
case ValueKind.CONSTANT_ExplicitNamespace:
return new SimpleValue(parent, index, "value_kind", "ExplicitNamespace", TreeIcon.VALUE_KIND);
case ValueKind.CONSTANT_StaticProtectedNs:
return new SimpleValue(parent, index, "value_kind", "StaticProtectedNs", TreeIcon.VALUE_KIND);
case ValueKind.CONSTANT_PrivateNs:
return new SimpleValue(parent, index, "value_kind", "PrivateNamespace", TreeIcon.VALUE_KIND);
}
}
if (index == 1) {
int value_index = mi.optional[sv.getIndex()].value_index;
switch (mi.optional[sv.getIndex()].value_kind) {
case ValueKind.CONSTANT_Int:
return createValueWithIndex(parent, index, value_index, TreeType.CONSTANT_INT, "value_index");
case ValueKind.CONSTANT_UInt:
return createValueWithIndex(parent, index, value_index, TreeType.CONSTANT_UINT, "value_index");
case ValueKind.CONSTANT_Double:
return createValueWithIndex(parent, index, value_index, TreeType.CONSTANT_DOUBLE, "value_index");
case ValueKind.CONSTANT_DecimalOrFloat: //?? or float ??
return createValueWithIndex(parent, index, value_index, TreeType.CONSTANT_DECIMAL, "value_index");
case ValueKind.CONSTANT_Utf8:
return createValueWithIndex(parent, index, value_index, TreeType.CONSTANT_STRING, "value_index");
case ValueKind.CONSTANT_True:
break;
case ValueKind.CONSTANT_False:
break;
case ValueKind.CONSTANT_Null:
break;
case ValueKind.CONSTANT_Undefined:
break;
case ValueKind.CONSTANT_Namespace:
case ValueKind.CONSTANT_PackageInternalNs:
case ValueKind.CONSTANT_ProtectedNamespace:
case ValueKind.CONSTANT_ExplicitNamespace:
case ValueKind.CONSTANT_StaticProtectedNs:
case ValueKind.CONSTANT_PrivateNs:
return createValueWithIndex(parent, index, value_index, TreeType.CONSTANT_NAMESPACE, "value_index");
}
}
} else {
return new SubValue(parent, index, index, mi, "optional", "op" + index, mi.optional[index].toASMString(abc.constants), TreeIcon.OPTIONAL_SUB);
}
case "param_names":
return createValueWithIndex(parent, index, mi.paramNames[index], TreeType.CONSTANT_STRING, "pn" + index);
}
}
if (sv.getParentValue() instanceof MethodBody) {
MethodBody body = (MethodBody) sv.getParentValue();
switch (sv.getProperty()) {
case "exceptions":
if (sv.getIndex() > -1) {
ABCException ex = body.exceptions[sv.getIndex()];
switch (index) {
case 0:
return new SimpleValue(parent, index, "start", "" + ex.start, TreeIcon.EXCEPTION_START);
case 1:
return new SimpleValue(parent, index, "end", "" + ex.end, TreeIcon.EXCEPTION_END);
case 2:
return new SimpleValue(parent, index, "target", "" + ex.target, TreeIcon.EXCEPTION_TARGET);
case 3:
return createValueWithIndex(parent, index, ex.name_index, TreeType.CONSTANT_MULTINAME, "name");
case 4:
return createValueWithIndex(parent, index, ex.type_index, TreeType.CONSTANT_MULTINAME, "type");
}
} else {
return new SubValue(parent, index, index, body, "exceptions", "ex" + index, "", TreeIcon.EXCEPTIONS_SUB);
}
case "traits":
return handleGetChildTrait(parent, index, body, sv, body.traits);
}
}
if (sv.getParentValue() instanceof InstanceInfo) {
InstanceInfo ii = (InstanceInfo) sv.getParentValue();
switch (sv.getProperty()) {
case "interfaces":
return createValueWithIndex(parent, index, ii.interfaces[index], TreeType.CONSTANT_MULTINAME, "in" + index);
case "traits":
return handleGetChildTrait(parent, index, ii, sv, ii.instance_traits);
}
}
if (sv.getParentValue() instanceof ClassInfo) {
ClassInfo ci = (ClassInfo) sv.getParentValue();
switch (sv.getProperty()) {
case "traits":
return handleGetChildTrait(parent, index, ci, sv, ci.static_traits);
}
}
if (sv.getParentValue() instanceof ScriptInfo) {
ScriptInfo ci = (ScriptInfo) sv.getParentValue();
switch (sv.getProperty()) {
case "traits":
return handleGetChildTrait(parent, index, ci, sv, ci.traits);
}
}
if (sv.getParentValue() instanceof MetadataInfo) {
MetadataInfo md = (MetadataInfo) sv.getParentValue();
switch (sv.getProperty()) {
case "pairs":
if (sv.getIndex() > -1) {
switch (index) {
case 0:
return createValueWithIndex(parent, index, md.keys[sv.getIndex()], TreeType.CONSTANT_STRING, "key");
case 1:
return createValueWithIndex(parent, index, md.values[sv.getIndex()], TreeType.CONSTANT_STRING, "value");
}
return null;
}
String pairTitle = formatString(md.keys[index]) + " : " + formatString(md.values[index]);
return new SubValue(parent, index, index, md, "pairs", "p" + index, pairTitle, TreeIcon.METADATA_PAIRS_SUB);
}
}
if (sv.getParentValue() instanceof Trait) {
Trait t = (Trait) sv.getParentValue();
switch (sv.getProperty()) {
case "metadata":
return createValueWithIndex(parent, index, t.metadata[index], TreeType.METADATA_INFO, "");
}
}
}
return null;
}
@Override
public int getChildCount(Object parent) {
if (parent == type) {
switch (type) {
case CONSTANT_INT:
return Math.max(1, abc.constants.getIntCount());
case CONSTANT_UINT:
return Math.max(1, abc.constants.getUIntCount());
case CONSTANT_DOUBLE:
return Math.max(1, abc.constants.getDoubleCount());
case CONSTANT_DECIMAL:
return Math.max(1, abc.constants.getDecimalCount());
case CONSTANT_FLOAT:
return Math.max(1, abc.constants.getFloatCount());
case CONSTANT_FLOAT_4:
return Math.max(1, abc.constants.getFloat4Count());
case CONSTANT_STRING:
return Math.max(1, abc.constants.getStringCount());
case CONSTANT_NAMESPACE:
return Math.max(1, abc.constants.getNamespaceCount());
case CONSTANT_NAMESPACE_SET:
return abc.constants.getNamespaceSetCount();
case CONSTANT_MULTINAME:
return Math.max(1, abc.constants.getMultinameCount());
case METHOD_INFO:
return abc.method_info.size();
case METADATA_INFO:
return abc.metadata_info.size();
case INSTANCE_INFO:
return abc.instance_info.size();
case CLASS_INFO:
return abc.class_info.size();
case SCRIPT_INFO:
return abc.script_info.size();
case METHOD_BODY:
return abc.bodies.size();
}
}
if (parent instanceof ValueWithIndex) {
ValueWithIndex vwi = (ValueWithIndex) parent;
if (vwi.value instanceof NamespaceSet) {
NamespaceSet nss = (NamespaceSet) vwi.value;
return nss.namespaces.length;
}
if (vwi.value instanceof Namespace) {
//kind, name
return 2;
}
if (vwi.value instanceof Multiname) {
Multiname m = (Multiname) vwi.value;
int kind = m.kind;
if ((kind == Multiname.QNAME) || (kind == Multiname.QNAMEA)) {
return 1 + 2;
} else if ((kind == Multiname.RTQNAME) || (kind == Multiname.RTQNAMEA)) {
return 1 + 1;
} else if ((kind == Multiname.RTQNAMEL) || (kind == Multiname.RTQNAMELA)) {
return 1;
} else if ((kind == Multiname.MULTINAME) || (kind == Multiname.MULTINAMEA)) {
return 1 + 2;
} else if ((kind == Multiname.MULTINAMEL) || (kind == Multiname.MULTINAMELA)) {
return 1 + 1;
} else if (kind == Multiname.TYPENAME) {
return 1 + 1 + m.params.length;
}
}
if (vwi.value instanceof MethodInfo) {
MethodInfo mi = (MethodInfo) vwi.value;
int count = 4;
if (mi.flagHas_optional()) {
count++;
}
if (mi.flagHas_paramnames()) {
count++;
}
int bodyIndex = abc.findBodyIndex(vwi.getIndex());
if (bodyIndex != -1) {
count++;
}
return count;
}
if (vwi.value instanceof MethodBody) {
return 8;
}
if (vwi.value instanceof InstanceInfo) {
InstanceInfo ii = (InstanceInfo) vwi.value;
if ((ii.flags & InstanceInfo.CLASS_PROTECTEDNS) == InstanceInfo.CLASS_PROTECTEDNS) {
return 7;
}
return 6;
}
if (vwi.value instanceof ClassInfo) {
return 2;
}
if (vwi.value instanceof ScriptInfo) {
return 2;
}
if (vwi.value instanceof MetadataInfo) {
MetadataInfo md = (MetadataInfo) vwi.value;
return 2;
}
}
if (parent instanceof SubValue) {
SubValue sv = (SubValue) parent;
if (sv.getParentValue() instanceof MethodInfo) {
MethodInfo mi = (MethodInfo) sv.getParentValue();
switch (sv.getProperty()) {
case "param_types":
return mi.param_types.length;
case "optional":
if (sv.getIndex() > -1) {
int index = sv.getIndex();
int value_index = mi.optional[index].value_index;
switch (mi.optional[index].value_kind) {
case ValueKind.CONSTANT_True:
case ValueKind.CONSTANT_False:
case ValueKind.CONSTANT_Null:
case ValueKind.CONSTANT_Undefined:
return 1;
case ValueKind.CONSTANT_Int:
case ValueKind.CONSTANT_UInt:
case ValueKind.CONSTANT_Double:
case ValueKind.CONSTANT_DecimalOrFloat: //?? or float ??
case ValueKind.CONSTANT_Utf8:
case ValueKind.CONSTANT_Namespace:
case ValueKind.CONSTANT_PackageInternalNs:
case ValueKind.CONSTANT_ProtectedNamespace:
case ValueKind.CONSTANT_ExplicitNamespace:
case ValueKind.CONSTANT_StaticProtectedNs:
case ValueKind.CONSTANT_PrivateNs:
return 2;
}
return 0;
}
return mi.optional.length;
case "param_names":
return mi.paramNames.length;
}
}
if (sv.getParentValue() instanceof MethodBody) {
MethodBody body = (MethodBody) sv.getParentValue();
switch (sv.getProperty()) {
case "exceptions":
if (sv.getIndex() > -1) {
return 5;
}
return body.exceptions.length;
case "traits":
return handleGetChildCountTrait(sv, body.traits);
}
}
if (sv.getParentValue() instanceof InstanceInfo) {
InstanceInfo ii = (InstanceInfo) sv.getParentValue();
switch (sv.getProperty()) {
case "interfaces":
return ii.interfaces.length;
case "traits":
return handleGetChildCountTrait(sv, ii.instance_traits);
}
}
if (sv.getParentValue() instanceof ClassInfo) {
ClassInfo ci = (ClassInfo) sv.getParentValue();
switch (sv.getProperty()) {
case "traits":
return handleGetChildCountTrait(sv, ci.static_traits);
}
}
if (sv.getParentValue() instanceof ScriptInfo) {
ScriptInfo ci = (ScriptInfo) sv.getParentValue();
switch (sv.getProperty()) {
case "traits":
return handleGetChildCountTrait(sv, ci.traits);
}
}
if (sv.getParentValue() instanceof MetadataInfo) {
MetadataInfo md = (MetadataInfo) sv.getParentValue();
switch (sv.getProperty()) {
case "pairs":
if (sv.getIndex() > -1) {
return 2;
}
return md.keys.length;
}
}
if (sv.getParentValue() instanceof Trait) {
Trait t = (Trait) sv.getParentValue();
switch (sv.getProperty()) {
case "metadata":
return t.metadata.length;
}
}
}
return 0;
}
@Override
public boolean isLeaf(Object node) {
return getChildCount(node) == 0;
}
@Override
public void valueForPathChanged(TreePath path, Object newValue) {
}
@Override
public int getIndexOfChild(Object parent, Object child) {
if (child instanceof ValueWithIndex) {
ValueWithIndex vwi = (ValueWithIndex) child;
if (vwi.getParent() == parent) {
return vwi.getCurrentLevelIndex();
}
}
if (child instanceof SubValue) {
SubValue sv = (SubValue) child;
if (sv.parent == parent) {
return sv.getCurrentLevelIndex();
}
}
if (child instanceof SimpleValue) {
SimpleValue sv = (SimpleValue) child;
if (sv.parent == parent) {
return sv.getCurrentLevelIndex();
}
}
return -1;
}
@Override
public void addTreeModelListener(TreeModelListener l) {
}
@Override
public void removeTreeModelListener(TreeModelListener l) {
}
}
public static class ExplorerTreeCellRenderer extends DefaultTreeCellRenderer {
public ExplorerTreeCellRenderer() {
setUI(new BasicLabelUI());
setOpaque(false);
if (View.isOceanic()) {
setBackgroundNonSelectionColor(Color.white);
}
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
/*if (semiTransparent) {
if (getIcon() != null) {
Color color = getBackground();
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha() / 2));
g2d.setComposite(AlphaComposite.SrcOver);
g2d.fillRect(0, 0, getWidth(), getHeight());
}
}*/
}
@Override
public Component getTreeCellRendererComponent(
JTree tree,
Object value,
boolean sel,
boolean expanded,
boolean leaf,
int row,
boolean hasFocus) {
super.getTreeCellRendererComponent(
tree, value, sel,
expanded, leaf, row,
hasFocus);
if (View.isOceanic()) {
setForeground(Color.BLACK);
}
setToolTipText(null);
if (value instanceof HasIcon) {
HasIcon hi = (HasIcon) value;
String iconFile = hi.getIcon().getFile();
if (!iconFile.isEmpty()) {
setIcon(View.getIcon(iconFile));
}
} else {
setIcon(null);
}
//semitransparent = true;
return this;
}
}
}