mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
style fixes in ghidra.app. {plugin.core.script script}
This commit is contained in:
parent
6bc33bdf65
commit
2015f13542
22 changed files with 442 additions and 372 deletions
|
@ -24,6 +24,7 @@ import java.util.*;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipFile;
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
|
import javax.swing.Icon;
|
||||||
import javax.swing.KeyStroke;
|
import javax.swing.KeyStroke;
|
||||||
|
|
||||||
import docking.ActionContext;
|
import docking.ActionContext;
|
||||||
|
@ -49,18 +50,15 @@ class GhidraScriptActionManager {
|
||||||
KeyEvent.VK_R, DockingUtils.CONTROL_KEY_MODIFIER_MASK | InputEvent.SHIFT_DOWN_MASK);
|
KeyEvent.VK_R, DockingUtils.CONTROL_KEY_MODIFIER_MASK | InputEvent.SHIFT_DOWN_MASK);
|
||||||
private static final String SCRIPT_ACTIONS_KEY = "Scripts_Actions_Key";
|
private static final String SCRIPT_ACTIONS_KEY = "Scripts_Actions_Key";
|
||||||
|
|
||||||
|
private static final String RESOURCE_FILE_ACTION_RUN_GROUP = "1";
|
||||||
|
|
||||||
private GhidraScriptComponentProvider provider;
|
private GhidraScriptComponentProvider provider;
|
||||||
private GhidraScriptMgrPlugin plugin;
|
private GhidraScriptMgrPlugin plugin;
|
||||||
private GhidraScriptInfoManager infoManager;
|
private GhidraScriptInfoManager infoManager;
|
||||||
private DockingAction refreshAction;
|
private DockingAction showBundleStatusAction;
|
||||||
private DockingAction bundleStatusAction;
|
|
||||||
private DockingAction newAction;
|
private DockingAction newAction;
|
||||||
private DockingAction runAction;
|
|
||||||
private DockingAction runLastAction;
|
private DockingAction runLastAction;
|
||||||
private DockingAction globalRunLastAction;
|
private DockingAction globalRunLastAction;
|
||||||
private DockingAction editAction;
|
|
||||||
private DockingAction eclipseAction;
|
|
||||||
private DockingAction deleteAction;
|
|
||||||
private DockingAction renameAction;
|
private DockingAction renameAction;
|
||||||
private DockingAction keyBindingAction;
|
private DockingAction keyBindingAction;
|
||||||
private DockingAction helpAction;
|
private DockingAction helpAction;
|
||||||
|
@ -174,15 +172,12 @@ class GhidraScriptActionManager {
|
||||||
globalRunLastAction.firePropertyChanged(DockingActionIf.DESCRIPTION_PROPERTY, "", newDesc);
|
globalRunLastAction.firePropertyChanged(DockingActionIf.DESCRIPTION_PROPERTY, "", newDesc);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createActions() {
|
private DockingAction createScriptAction(String name, String menuEntry,
|
||||||
//
|
String actionDescription, Icon icon, String toolBarGroup, Runnable runnable) {
|
||||||
// 'run' actions
|
DockingAction action = new DockingAction(name, plugin.getName()) {
|
||||||
//
|
|
||||||
String runGroup = "1";
|
|
||||||
runAction = new DockingAction("Run", plugin.getName()) {
|
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionContext context) {
|
public void actionPerformed(ActionContext context) {
|
||||||
provider.runScript();
|
runnable.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -191,188 +186,79 @@ class GhidraScriptActionManager {
|
||||||
return contextObject instanceof ResourceFile;
|
return contextObject instanceof ResourceFile;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
runAction.setPopupMenuData(new MenuData(new String[] { "Run" },
|
action.setPopupMenuData(new MenuData(new String[] { menuEntry }, icon));
|
||||||
ResourceManager.loadImage("images/play.png"), null));
|
action.setToolBarData(new ToolBarData(icon, toolBarGroup));
|
||||||
runAction.setToolBarData(
|
|
||||||
new ToolBarData(ResourceManager.loadImage("images/play.png"), runGroup));
|
|
||||||
|
|
||||||
runAction.setDescription("Run Script");
|
action.setDescription(actionDescription);
|
||||||
runAction.setEnabled(false);
|
action.setEnabled(false);
|
||||||
plugin.getTool().addLocalAction(provider, runAction);
|
|
||||||
|
|
||||||
runLastAction = new RerunLastScriptAction(runGroup);
|
plugin.getTool().addLocalAction(provider, action);
|
||||||
|
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DockingAction createScriptTableAction(String name, String actionDescription, Icon icon,
|
||||||
|
Runnable runnable) {
|
||||||
|
DockingAction action = new DockingAction(name, plugin.getName()) {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionContext context) {
|
||||||
|
runnable.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAddToPopup(ActionContext context) {
|
||||||
|
Object contextObject = context.getContextObject();
|
||||||
|
return (contextObject instanceof GTable) || (contextObject instanceof ResourceFile);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
action.setPopupMenuData(new MenuData(new String[] { name }, icon));
|
||||||
|
action.setToolBarData(new ToolBarData(icon, null));
|
||||||
|
|
||||||
|
action.setDescription(actionDescription);
|
||||||
|
action.setEnabled(true);
|
||||||
|
|
||||||
|
plugin.getTool().addLocalAction(provider, action);
|
||||||
|
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createActions() {
|
||||||
|
createScriptAction("Run", "Run Script", "Run Script",
|
||||||
|
ResourceManager.loadImage("images/play.png"), RESOURCE_FILE_ACTION_RUN_GROUP,
|
||||||
|
provider::runScript);
|
||||||
|
|
||||||
|
runLastAction = new RerunLastScriptAction(RESOURCE_FILE_ACTION_RUN_GROUP);
|
||||||
plugin.getTool().addLocalAction(provider, runLastAction);
|
plugin.getTool().addLocalAction(provider, runLastAction);
|
||||||
|
|
||||||
globalRunLastAction = new RerunLastScriptAction("Xtra");
|
globalRunLastAction = new RerunLastScriptAction("Xtra");
|
||||||
plugin.getTool().addAction(globalRunLastAction);
|
plugin.getTool().addAction(globalRunLastAction);
|
||||||
|
|
||||||
//
|
createScriptAction("Edit", "Edit with basic editor", "Edit Script with basic editor",
|
||||||
// End 'run' actions
|
ResourceManager.loadImage("images/accessories-text-editor.png"), null,
|
||||||
//
|
provider::editScriptBuiltin);
|
||||||
|
|
||||||
editAction = new DockingAction("Edit", plugin.getName()) {
|
createScriptAction("EditEclipse", "Edit with Eclipse", "Edit Script with Eclipse",
|
||||||
@Override
|
ResourceManager.loadImage("images/eclipse.png"), null, provider::editScriptEclipse);
|
||||||
public void actionPerformed(ActionContext context) {
|
|
||||||
provider.editScriptBuiltin();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
keyBindingAction =
|
||||||
public boolean isEnabledForContext(ActionContext context) {
|
createScriptAction("Key Binding", "Assign Key Binding", "Assign Key Binding",
|
||||||
Object contextObject = context.getContextObject();
|
ResourceManager.loadImage("images/key.png"), null, provider::assignKeyBinding);
|
||||||
return contextObject instanceof ResourceFile;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
editAction.setPopupMenuData(new MenuData(new String[] { "Edit with basic editor" },
|
|
||||||
ResourceManager.loadImage("images/accessories-text-editor.png"), null));
|
|
||||||
editAction.setToolBarData(
|
|
||||||
new ToolBarData(ResourceManager.loadImage("images/accessories-text-editor.png"), null));
|
|
||||||
editAction.setDescription("Edit Script with basic editor");
|
|
||||||
editAction.setEnabled(false);
|
|
||||||
plugin.getTool().addLocalAction(provider, editAction);
|
|
||||||
|
|
||||||
eclipseAction = new DockingAction("EditEclipse", plugin.getName()) {
|
createScriptAction("Delete", "Delete", "Delete Script",
|
||||||
@Override
|
ResourceManager.loadImage("images/edit-delete.png"), null, provider::deleteScript);
|
||||||
public void actionPerformed(ActionContext context) {
|
|
||||||
provider.editScriptEclipse();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
renameAction = createScriptAction("Rename", "Rename", "Rename Script",
|
||||||
public boolean isEnabledForContext(ActionContext context) {
|
ResourceManager.loadImage("images/textfield_rename.png"), null, provider::renameScript);
|
||||||
Object contextObject = context.getContextObject();
|
|
||||||
return contextObject instanceof ResourceFile;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
eclipseAction.setPopupMenuData(new MenuData(new String[] { "Edit with Eclipse" },
|
|
||||||
ResourceManager.loadImage("images/eclipse.png"), null));
|
|
||||||
eclipseAction.setToolBarData(
|
|
||||||
new ToolBarData(ResourceManager.loadImage("images/eclipse.png"), null));
|
|
||||||
eclipseAction.setDescription("Edit Script with Eclipse");
|
|
||||||
eclipseAction.setEnabled(false);
|
|
||||||
plugin.getTool().addLocalAction(provider, eclipseAction);
|
|
||||||
|
|
||||||
keyBindingAction = new DockingAction("Key Binding", plugin.getName()) {
|
newAction = createScriptTableAction("New", "Create New Script",
|
||||||
@Override
|
ResourceManager.loadImage("images/script_add.png"), provider::newScript);
|
||||||
public void actionPerformed(ActionContext context) {
|
|
||||||
provider.assignKeyBinding();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
createScriptTableAction("Refresh", "Refresh Script List",
|
||||||
public boolean isEnabledForContext(ActionContext context) {
|
Icons.REFRESH_ICON, provider::refresh);
|
||||||
Object contextObject = context.getContextObject();
|
|
||||||
return contextObject instanceof ResourceFile;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
keyBindingAction.setPopupMenuData(new MenuData(new String[] { "Assign Key Binding" },
|
|
||||||
ResourceManager.loadImage("images/key.png"), null));
|
|
||||||
keyBindingAction.setToolBarData(
|
|
||||||
new ToolBarData(ResourceManager.loadImage("images/key.png"), null));
|
|
||||||
|
|
||||||
keyBindingAction.setDescription("Assign Key Binding");
|
showBundleStatusAction = createScriptTableAction("Script Directories",
|
||||||
keyBindingAction.setEnabled(false);
|
"Manage Script Directories", ResourceManager.loadImage("images/text_list_bullets.png"),
|
||||||
plugin.getTool().addLocalAction(provider, keyBindingAction);
|
provider::showBundleStatusComponent);
|
||||||
|
|
||||||
deleteAction = new DockingAction("Delete", plugin.getName()) {
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionContext context) {
|
|
||||||
provider.deleteScript();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEnabledForContext(ActionContext context) {
|
|
||||||
Object contextObject = context.getContextObject();
|
|
||||||
return contextObject instanceof ResourceFile;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
deleteAction.setPopupMenuData(new MenuData(new String[] { "Delete" },
|
|
||||||
ResourceManager.loadImage("images/edit-delete.png"), null));
|
|
||||||
deleteAction.setToolBarData(
|
|
||||||
new ToolBarData(ResourceManager.loadImage("images/edit-delete.png"), null));
|
|
||||||
|
|
||||||
deleteAction.setDescription("Delete Script");
|
|
||||||
deleteAction.setEnabled(false);
|
|
||||||
plugin.getTool().addLocalAction(provider, deleteAction);
|
|
||||||
|
|
||||||
renameAction = new DockingAction("Rename", plugin.getName()) {
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionContext context) {
|
|
||||||
provider.renameScript();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEnabledForContext(ActionContext context) {
|
|
||||||
Object contextObject = context.getContextObject();
|
|
||||||
return contextObject instanceof ResourceFile;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
renameAction.setPopupMenuData(new MenuData(new String[] { "Rename" },
|
|
||||||
ResourceManager.loadImage("images/textfield_rename.png"), null));
|
|
||||||
renameAction.setToolBarData(
|
|
||||||
new ToolBarData(ResourceManager.loadImage("images/textfield_rename.png"), null));
|
|
||||||
|
|
||||||
renameAction.setDescription("Rename Script");
|
|
||||||
renameAction.setEnabled(false);
|
|
||||||
plugin.getTool().addLocalAction(provider, renameAction);
|
|
||||||
|
|
||||||
newAction = new DockingAction("New", plugin.getName()) {
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionContext context) {
|
|
||||||
provider.newScript();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isAddToPopup(ActionContext context) {
|
|
||||||
Object contextObject = context.getContextObject();
|
|
||||||
return (contextObject instanceof GTable) || (contextObject instanceof ResourceFile);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
newAction.setPopupMenuData(new MenuData(new String[] { "New" },
|
|
||||||
ResourceManager.loadImage("images/script_add.png"), null));
|
|
||||||
newAction.setToolBarData(
|
|
||||||
new ToolBarData(ResourceManager.loadImage("images/script_add.png"), null));
|
|
||||||
|
|
||||||
newAction.setDescription("Create New Script");
|
|
||||||
newAction.setEnabled(true);
|
|
||||||
plugin.getTool().addLocalAction(provider, newAction);
|
|
||||||
|
|
||||||
refreshAction = new DockingAction("Refresh", plugin.getName()) {
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionContext context) {
|
|
||||||
provider.refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isAddToPopup(ActionContext context) {
|
|
||||||
Object contextObject = context.getContextObject();
|
|
||||||
return (contextObject instanceof GTable) || (contextObject instanceof ResourceFile);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
refreshAction.setPopupMenuData(
|
|
||||||
new MenuData(new String[] { "Refresh" }, Icons.REFRESH_ICON, null));
|
|
||||||
refreshAction.setToolBarData(new ToolBarData(Icons.REFRESH_ICON, null));
|
|
||||||
|
|
||||||
refreshAction.setDescription("Refresh Script List");
|
|
||||||
refreshAction.setEnabled(true);
|
|
||||||
plugin.getTool().addLocalAction(provider, refreshAction);
|
|
||||||
|
|
||||||
bundleStatusAction = new DockingAction("Script Directories", plugin.getName()) {
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionContext context) {
|
|
||||||
provider.showBundleStatusComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isAddToPopup(ActionContext context) {
|
|
||||||
Object contextObject = context.getContextObject();
|
|
||||||
return (contextObject instanceof GTable) || (contextObject instanceof ResourceFile);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
bundleStatusAction.setPopupMenuData(new MenuData(new String[] { "Bundle Status" },
|
|
||||||
ResourceManager.loadImage("images/text_list_bullets.png"), null));
|
|
||||||
bundleStatusAction.setToolBarData(
|
|
||||||
new ToolBarData(ResourceManager.loadImage("images/text_list_bullets.png"), null));
|
|
||||||
|
|
||||||
bundleStatusAction.setDescription("Bundle Status");
|
|
||||||
bundleStatusAction.setEnabled(true);
|
|
||||||
plugin.getTool().addLocalAction(provider, bundleStatusAction);
|
|
||||||
|
|
||||||
helpAction = new DockingAction("Ghidra API Help", plugin.getName()) {
|
helpAction = new DockingAction("Ghidra API Help", plugin.getName()) {
|
||||||
@Override
|
@Override
|
||||||
|
@ -441,7 +327,7 @@ class GhidraScriptActionManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
HelpLocation getPathHelpLocation() {
|
HelpLocation getPathHelpLocation() {
|
||||||
return new HelpLocation(plugin.getName(), bundleStatusAction.getName());
|
return new HelpLocation(plugin.getName(), showBundleStatusAction.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
HelpLocation getKeyBindingHelpLocation() {
|
HelpLocation getKeyBindingHelpLocation() {
|
||||||
|
|
|
@ -20,6 +20,7 @@ import java.awt.Rectangle;
|
||||||
import java.awt.event.*;
|
import java.awt.event.*;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
@ -57,13 +58,12 @@ import util.CollectionUtils;
|
||||||
import utilities.util.FileUtilities;
|
import utilities.util.FileUtilities;
|
||||||
|
|
||||||
public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
|
public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
|
||||||
|
static final String WINDOW_GROUP = "Script Group";
|
||||||
|
|
||||||
private static final double TOP_PREFERRED_RESIZE_WEIGHT = .80;
|
private static final double TOP_PREFERRED_RESIZE_WEIGHT = .80;
|
||||||
private static final String DESCRIPTION_DIVIDER_LOCATION = "DESCRIPTION_DIVIDER_LOCATION";
|
private static final String DESCRIPTION_DIVIDER_LOCATION = "DESCRIPTION_DIVIDER_LOCATION";
|
||||||
private static final String FILTER_TEXT = "FILTER_TEXT";
|
private static final String FILTER_TEXT = "FILTER_TEXT";
|
||||||
|
|
||||||
static final String WINDOW_GROUP = "Script Group";
|
|
||||||
|
|
||||||
private Map<ResourceFile, GhidraScriptEditorComponentProvider> editorMap = new HashMap<>();
|
private Map<ResourceFile, GhidraScriptEditorComponentProvider> editorMap = new HashMap<>();
|
||||||
private final GhidraScriptMgrPlugin plugin;
|
private final GhidraScriptMgrPlugin plugin;
|
||||||
private JPanel component;
|
private JPanel component;
|
||||||
|
@ -126,7 +126,7 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
|
||||||
updateTitle();
|
updateTitle();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void build() {
|
private void buildCategoryTree() {
|
||||||
scriptRoot = new RootNode();
|
scriptRoot = new RootNode();
|
||||||
|
|
||||||
scriptCategoryTree = new GTree(scriptRoot);
|
scriptCategoryTree = new GTree(scriptRoot);
|
||||||
|
@ -159,6 +159,10 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
|
||||||
|
|
||||||
scriptCategoryTree.getSelectionModel()
|
scriptCategoryTree.getSelectionModel()
|
||||||
.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
|
.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void build() {
|
||||||
|
buildCategoryTree();
|
||||||
|
|
||||||
tableModel = new GhidraScriptTableModel(this, infoManager);
|
tableModel = new GhidraScriptTableModel(this, infoManager);
|
||||||
|
|
||||||
|
@ -231,10 +235,11 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
|
||||||
component.add(dataDescriptionSplit, BorderLayout.CENTER);
|
component.add(dataDescriptionSplit, BorderLayout.CENTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
//==================================================================================================
|
/**
|
||||||
// Inner Classes
|
* Restore state for bundles, user actions, and filter.
|
||||||
//==================================================================================================
|
*
|
||||||
|
* @param saveState the state object
|
||||||
|
*/
|
||||||
public void readConfigState(SaveState saveState) {
|
public void readConfigState(SaveState saveState) {
|
||||||
bundleHost.restoreManagedBundleState(saveState, getTool());
|
bundleHost.restoreManagedBundleState(saveState, getTool());
|
||||||
|
|
||||||
|
@ -259,6 +264,12 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
|
||||||
tableFilterPanel.setFilterText(filterText);
|
tableFilterPanel.setFilterText(filterText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save state for bundles, user actions, and filter.
|
||||||
|
*
|
||||||
|
* @param saveState the state object
|
||||||
|
*/
|
||||||
|
|
||||||
public void writeConfigState(SaveState saveState) {
|
public void writeConfigState(SaveState saveState) {
|
||||||
bundleHost.saveManagedBundleState(saveState);
|
bundleHost.saveManagedBundleState(saveState);
|
||||||
|
|
||||||
|
@ -283,6 +294,9 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
|
||||||
bundleStatusComponentProvider.dispose();
|
bundleStatusComponentProvider.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the bundle host used for scripting, ultimately from {@link GhidraScriptUtil#getBundleHost()}
|
||||||
|
*/
|
||||||
public BundleHost getBundleHost() {
|
public BundleHost getBundleHost() {
|
||||||
return bundleHost;
|
return bundleHost;
|
||||||
}
|
}
|
||||||
|
@ -299,10 +313,6 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
|
||||||
return editorMap;
|
return editorMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
void showBundleStatusComponent() {
|
|
||||||
bundleStatusComponentProvider.setVisible(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void assignKeyBinding() {
|
void assignKeyBinding() {
|
||||||
ResourceFile script = getSelectedScript();
|
ResourceFile script = getSelectedScript();
|
||||||
ScriptAction action = actionManager.createAction(script);
|
ScriptAction action = actionManager.createAction(script);
|
||||||
|
@ -360,20 +370,23 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
|
||||||
renameScriptByCopying(script, provider, renameFile);
|
renameScriptByCopying(script, provider, renameFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renameScriptByCopying(ResourceFile script, GhidraScriptProvider provider,
|
/**
|
||||||
ResourceFile renameFile) {
|
* Copy a script, renaming references to the class name.
|
||||||
String oldClassName = GhidraScriptUtil.getBaseName(script);
|
*
|
||||||
String newClassName = GhidraScriptUtil.getBaseName(renameFile);
|
* @param sourceScript source script
|
||||||
|
* @param destinationScript destination script
|
||||||
|
* @throws IOException if we fail to create temp, write contents, copy, or delete temp
|
||||||
|
*/
|
||||||
|
private void copyScript(ResourceFile sourceScript, ResourceFile destinationScript)
|
||||||
|
throws IOException {
|
||||||
|
String oldClassName = GhidraScriptUtil.getBaseName(sourceScript);
|
||||||
|
String newClassName = GhidraScriptUtil.getBaseName(destinationScript);
|
||||||
|
|
||||||
ResourceFile temp = null;
|
ResourceFile parentFile = sourceScript.getParentFile();
|
||||||
PrintWriter writer = null;
|
ResourceFile temp = new ResourceFile(parentFile, "ghidraScript.tmp");
|
||||||
BufferedReader reader = null;
|
try (PrintWriter writer = new PrintWriter(temp.getOutputStream())) {
|
||||||
try {
|
try (BufferedReader reader =
|
||||||
|
new BufferedReader(new InputStreamReader(sourceScript.getInputStream()))) {
|
||||||
ResourceFile parentFile = script.getParentFile();
|
|
||||||
temp = new ResourceFile(parentFile, "ghidraScript.tmp");
|
|
||||||
writer = new PrintWriter(temp.getOutputStream());
|
|
||||||
reader = new BufferedReader(new InputStreamReader(script.getInputStream()));
|
|
||||||
while (true) {
|
while (true) {
|
||||||
String line = reader.readLine();
|
String line = reader.readLine();
|
||||||
if (line == null) {
|
if (line == null) {
|
||||||
|
@ -381,10 +394,21 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
|
||||||
}
|
}
|
||||||
writer.println(line.replaceAll(oldClassName, newClassName));
|
writer.println(line.replaceAll(oldClassName, newClassName));
|
||||||
}
|
}
|
||||||
reader.close();
|
}
|
||||||
writer.close();
|
}
|
||||||
|
FileUtilities.copyFile(temp, destinationScript, TaskMonitor.DUMMY);
|
||||||
|
temp.delete();
|
||||||
|
}
|
||||||
|
|
||||||
FileUtilities.copyFile(temp, renameFile, TaskMonitor.DUMMY);
|
private void renameScriptByCopying(ResourceFile script, GhidraScriptProvider provider,
|
||||||
|
ResourceFile renameFile) {
|
||||||
|
try {
|
||||||
|
copyScript(script, renameFile);
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
Msg.showError(getClass(), getComponent(), "Unable to rename script", e.getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!renameFile.exists()) {
|
if (!renameFile.exists()) {
|
||||||
Msg.showWarn(getClass(), getComponent(), "Unable to rename script",
|
Msg.showWarn(getClass(), getComponent(), "Unable to rename script",
|
||||||
|
@ -407,36 +431,12 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
|
||||||
action.setKeyBindingData(new KeyBindingData(ks));
|
action.setKeyBindingData(new KeyBindingData(ks));
|
||||||
}
|
}
|
||||||
|
|
||||||
assert !infoManager
|
assert !infoManager.containsMetadata(renameFile) : "renamed script already has metadata";
|
||||||
.containsMetadata(renameFile) : "renamed script already has metadata";
|
|
||||||
infoManager.getScriptInfo(renameFile);
|
infoManager.getScriptInfo(renameFile);
|
||||||
|
|
||||||
tableModel.switchScript(script, renameFile);
|
tableModel.switchScript(script, renameFile);
|
||||||
setSelectedScript(renameFile);
|
setSelectedScript(renameFile);
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
|
||||||
Msg.showError(getClass(), getComponent(), "Unable to rename script", e.getMessage());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
if (reader != null) {
|
|
||||||
try {
|
|
||||||
reader.close();
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
// we tried
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (writer != null) {
|
|
||||||
writer.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (temp != null) {
|
|
||||||
temp.delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JTable getTable() {
|
JTable getTable() {
|
||||||
return scriptTable;
|
return scriptTable;
|
||||||
|
@ -450,19 +450,27 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
|
||||||
return tableModel.getScriptAt(tableFilterPanel.getModelRow(viewRowIndex));
|
return tableModel.getScriptAt(tableFilterPanel.getModelRow(viewRowIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return enabled bundle paths from the scripting bundle host
|
||||||
|
*/
|
||||||
public List<ResourceFile> getScriptDirectories() {
|
public List<ResourceFile> getScriptDirectories() {
|
||||||
return bundleHost.getGhidraBundles()
|
return bundleHost.getGhidraBundles()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(bundle -> bundle.isEnabled() && bundle instanceof GhidraSourceBundle)
|
.filter(GhidraSourceBundle.class::isInstance)
|
||||||
|
.filter(GhidraBundle::isEnabled)
|
||||||
.map(GhidraBundle::getPath)
|
.map(GhidraBundle::getPath)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return non-system bundle paths from the scripting bundle host
|
||||||
|
*/
|
||||||
public List<ResourceFile> getWritableScriptDirectories() {
|
public List<ResourceFile> getWritableScriptDirectories() {
|
||||||
return bundleHost.getGhidraBundles()
|
return bundleHost.getGhidraBundles()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(GhidraSourceBundle.class::isInstance)
|
.filter(GhidraSourceBundle.class::isInstance)
|
||||||
.filter(bundle -> !bundle.isSystemBundle())
|
.filter(Predicate.not(GhidraBundle::isSystemBundle))
|
||||||
|
.filter(GhidraBundle::isEnabled)
|
||||||
.map(GhidraBundle::getPath)
|
.map(GhidraBundle::getPath)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
@ -496,7 +504,7 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Msg.showInfo(getClass(), getComponent(), getName(),
|
Msg.showInfo(getClass(), getComponent(), getName(),
|
||||||
"Unable to delete script '" + script.getName() + "'" + "\n" +
|
"Unable to delete script '" + script.getName() + "'\n" +
|
||||||
"Please verify the file permissions.");
|
"Please verify the file permissions.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -521,7 +529,7 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void enableScriptDirectory(ResourceFile scriptDir) {
|
void enableScriptDirectory(ResourceFile scriptDir) {
|
||||||
bundleHost.enablePath(scriptDir);
|
bundleHost.enablePath(scriptDir);
|
||||||
Msg.showInfo(this, getComponent(), "Script Path Added/Enabled",
|
Msg.showInfo(this, getComponent(), "Script Path Added/Enabled",
|
||||||
"The directory has been automatically enabled for use:\n" +
|
"The directory has been automatically enabled for use:\n" +
|
||||||
|
@ -699,6 +707,10 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
|
||||||
return categoryPath;
|
return categoryPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void showBundleStatusComponent() {
|
||||||
|
bundleStatusComponentProvider.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
class RefreshingBundleHostListener implements BundleHostListener {
|
class RefreshingBundleHostListener implements BundleHostListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -41,8 +41,7 @@ import resources.Icons;
|
||||||
import resources.ResourceManager;
|
import resources.ResourceManager;
|
||||||
|
|
||||||
public class GhidraScriptEditorComponentProvider extends ComponentProvider {
|
public class GhidraScriptEditorComponentProvider extends ComponentProvider {
|
||||||
|
static final String EDITOR_COMPONENT_NAME="EDITOR";
|
||||||
private static final int MAX_UNDO_REDO_SIZE = 50;
|
|
||||||
|
|
||||||
static final String CHANGE_DESTINATION_TITLE = "Where Would You Like to Store Your Changes?";
|
static final String CHANGE_DESTINATION_TITLE = "Where Would You Like to Store Your Changes?";
|
||||||
static final String FILE_ON_DISK_CHANGED_TITLE = "File Changed on Disk";
|
static final String FILE_ON_DISK_CHANGED_TITLE = "File Changed on Disk";
|
||||||
|
@ -53,7 +52,9 @@ public class GhidraScriptEditorComponentProvider extends ComponentProvider {
|
||||||
static final String KEEP_CHANGES_TEXT = "Keep Changes";
|
static final String KEEP_CHANGES_TEXT = "Keep Changes";
|
||||||
static final String DISCARD_CHANGES_TEXT = "Discard Changes";
|
static final String DISCARD_CHANGES_TEXT = "Discard Changes";
|
||||||
|
|
||||||
static Font defaultFont = new Font("monospaced", Font.PLAIN, 12);
|
private static final int MAX_UNDO_REDO_SIZE = 50;
|
||||||
|
|
||||||
|
private static Font defaultFont = new Font("monospaced", Font.PLAIN, 12);
|
||||||
|
|
||||||
static void restoreState(SaveState saveState) {
|
static void restoreState(SaveState saveState) {
|
||||||
String name = saveState.getString("DEFAULT_FONT_NAME", "Monospaced");
|
String name = saveState.getString("DEFAULT_FONT_NAME", "Monospaced");
|
||||||
|
@ -68,6 +69,7 @@ public class GhidraScriptEditorComponentProvider extends ComponentProvider {
|
||||||
saveState.putInt("DEFAULT_FONT_SIZE", defaultFont.getSize());
|
saveState.putInt("DEFAULT_FONT_SIZE", defaultFont.getSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private GhidraScriptMgrPlugin plugin;
|
private GhidraScriptMgrPlugin plugin;
|
||||||
private GhidraScriptComponentProvider provider;
|
private GhidraScriptComponentProvider provider;
|
||||||
private String title;
|
private String title;
|
||||||
|
@ -675,7 +677,7 @@ public class GhidraScriptEditorComponentProvider extends ComponentProvider {
|
||||||
super(text);
|
super(text);
|
||||||
|
|
||||||
setFont(defaultFont);
|
setFont(defaultFont);
|
||||||
setName("EDITOR");
|
setName(EDITOR_COMPONENT_NAME);
|
||||||
setWrapStyleWord(false);
|
setWrapStyleWord(false);
|
||||||
Document document = getDocument();
|
Document document = getDocument();
|
||||||
document.addUndoableEditListener(e -> {
|
document.addUndoableEditListener(e -> {
|
||||||
|
|
|
@ -26,8 +26,7 @@ import ghidra.app.plugin.ProgramPlugin;
|
||||||
import ghidra.app.plugin.core.eclipse.EclipseConnection;
|
import ghidra.app.plugin.core.eclipse.EclipseConnection;
|
||||||
import ghidra.app.plugin.core.eclipse.EclipseIntegrationOptionsPlugin;
|
import ghidra.app.plugin.core.eclipse.EclipseIntegrationOptionsPlugin;
|
||||||
import ghidra.app.plugin.core.osgi.BundleHost;
|
import ghidra.app.plugin.core.osgi.BundleHost;
|
||||||
import ghidra.app.script.GhidraScriptUtil;
|
import ghidra.app.script.*;
|
||||||
import ghidra.app.script.GhidraState;
|
|
||||||
import ghidra.app.services.*;
|
import ghidra.app.services.*;
|
||||||
import ghidra.framework.options.SaveState;
|
import ghidra.framework.options.SaveState;
|
||||||
import ghidra.framework.options.ToolOptions;
|
import ghidra.framework.options.ToolOptions;
|
||||||
|
@ -49,12 +48,17 @@ import ghidra.util.task.TaskListener;
|
||||||
)
|
)
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
public class GhidraScriptMgrPlugin extends ProgramPlugin implements GhidraScriptService {
|
public class GhidraScriptMgrPlugin extends ProgramPlugin implements GhidraScriptService {
|
||||||
|
private static int loaded = 0;
|
||||||
|
|
||||||
private final GhidraScriptComponentProvider provider;
|
private final GhidraScriptComponentProvider provider;
|
||||||
|
|
||||||
private static int loaded = 0;
|
|
||||||
private final BundleHost bundleHost;
|
private final BundleHost bundleHost;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link GhidraScriptMgrPlugin} is the entry point for all {@link GhidraScript} capabilities.
|
||||||
|
*
|
||||||
|
* @param tool the tool this plugin is added to
|
||||||
|
*/
|
||||||
public GhidraScriptMgrPlugin(PluginTool tool) {
|
public GhidraScriptMgrPlugin(PluginTool tool) {
|
||||||
super(tool, true, true, true);
|
super(tool, true, true, true);
|
||||||
if (loaded == 0) {
|
if (loaded == 0) {
|
||||||
|
@ -111,6 +115,11 @@ public class GhidraScriptMgrPlugin extends ProgramPlugin implements GhidraScript
|
||||||
provider.runScript(scriptName, listener);
|
provider.runScript(scriptName, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to run a script in a {@link RunScriptTask}.
|
||||||
|
*
|
||||||
|
* @param scriptFile the script's source file
|
||||||
|
*/
|
||||||
public void runScript(ResourceFile scriptFile) {
|
public void runScript(ResourceFile scriptFile) {
|
||||||
provider.runScript(scriptFile);
|
provider.runScript(scriptFile);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,13 +35,12 @@ import ghidra.util.table.column.GColumnRenderer;
|
||||||
import resources.Icons;
|
import resources.Icons;
|
||||||
|
|
||||||
class GhidraScriptTableModel extends GDynamicColumnTableModel<ResourceFile, Object> {
|
class GhidraScriptTableModel extends GDynamicColumnTableModel<ResourceFile, Object> {
|
||||||
|
static final String SCRIPT_ACTION_COLUMN_NAME = "In Tool";
|
||||||
|
static final String SCRIPT_STATUS_COLUMN_NAME = "Status";
|
||||||
|
|
||||||
private static final String EMPTY_STRING = "";
|
private static final String EMPTY_STRING = "";
|
||||||
private static final ImageIcon ERROR_IMG = Icons.ERROR_ICON;
|
private static final ImageIcon ERROR_IMG = Icons.ERROR_ICON;
|
||||||
|
|
||||||
static final String SCRIPT_ACTION_COLUMN_NAME = "In Tool";
|
|
||||||
static final String SCRIPT_STATUS_COLUMN_NAME = "Status";
|
|
||||||
|
|
||||||
private GhidraScriptComponentProvider provider;
|
private GhidraScriptComponentProvider provider;
|
||||||
private List<ResourceFile> scriptList = new ArrayList<>();
|
private List<ResourceFile> scriptList = new ArrayList<>();
|
||||||
private final GhidraScriptInfoManager infoManager;
|
private final GhidraScriptInfoManager infoManager;
|
||||||
|
@ -276,7 +275,7 @@ class GhidraScriptTableModel extends GDynamicColumnTableModel<ResourceFile, Obje
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getColumnName() {
|
public String getColumnName() {
|
||||||
return "Status";
|
return SCRIPT_STATUS_COLUMN_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/* ###
|
/* ###
|
||||||
* IP: GHIDRA
|
* IP: GHIDRA
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -17,5 +16,5 @@
|
||||||
package ghidra.app.plugin.core.script;
|
package ghidra.app.plugin.core.script;
|
||||||
|
|
||||||
public interface Ingredient {
|
public interface Ingredient {
|
||||||
public IngredientDescription [] getIngredientDescriptions();
|
IngredientDescription [] getIngredientDescriptions();
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,13 +30,13 @@ import ghidra.app.script.GhidraScriptUtil;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
|
|
||||||
public class PickProviderDialog extends DialogComponentProvider {
|
public class PickProviderDialog extends DialogComponentProvider {
|
||||||
|
private static String lastSelectedProviderDescription;
|
||||||
|
|
||||||
private List<GhidraScriptProvider> providers;
|
private List<GhidraScriptProvider> providers;
|
||||||
private ListPanel listPanel;
|
private ListPanel listPanel;
|
||||||
private JComponent parent;
|
private JComponent parent;
|
||||||
private boolean wasCancelled;
|
private boolean wasCancelled;
|
||||||
|
|
||||||
private static String lastSelectedProviderDescription;
|
|
||||||
|
|
||||||
PickProviderDialog(JComponent parent, HelpLocation help) {
|
PickProviderDialog(JComponent parent, HelpLocation help) {
|
||||||
super("New Script: Type");
|
super("New Script: Type");
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
|
@ -55,6 +55,12 @@ public class PickProviderDialog extends DialogComponentProvider {
|
||||||
setHelpLocation(help);
|
setHelpLocation(help);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor used in testing only!
|
||||||
|
*
|
||||||
|
* @param testItems values to populate model with
|
||||||
|
* @param defaultItem the default selection
|
||||||
|
*/
|
||||||
public PickProviderDialog(List<String> testItems, String defaultItem) {
|
public PickProviderDialog(List<String> testItems, String defaultItem) {
|
||||||
super("New Script: Type");
|
super("New Script: Type");
|
||||||
|
|
||||||
|
@ -76,6 +82,8 @@ public class PickProviderDialog extends DialogComponentProvider {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For testing...
|
* For testing...
|
||||||
|
*
|
||||||
|
* @param provider the provider selection
|
||||||
*/
|
*/
|
||||||
void setSelectedProvider(GhidraScriptProvider provider) {
|
void setSelectedProvider(GhidraScriptProvider provider) {
|
||||||
listPanel.setSelectedValue(provider);
|
listPanel.setSelectedValue(provider);
|
||||||
|
@ -95,6 +103,9 @@ public class PickProviderDialog extends DialogComponentProvider {
|
||||||
return (GhidraScriptProvider) listPanel.getSelectedValue();
|
return (GhidraScriptProvider) listPanel.getSelectedValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* close any open dialog
|
||||||
|
*/
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,8 @@ import ghidra.util.HelpLocation;
|
||||||
|
|
||||||
public class SaveDialog extends DialogComponentProvider implements ListSelectionListener {
|
public class SaveDialog extends DialogComponentProvider implements ListSelectionListener {
|
||||||
protected GhidraScriptComponentProvider componentProvider;
|
protected GhidraScriptComponentProvider componentProvider;
|
||||||
|
protected ResourceFile scriptFile;
|
||||||
|
|
||||||
private GhidraScriptProvider provider;
|
private GhidraScriptProvider provider;
|
||||||
|
|
||||||
private List<ResourceFile> paths;
|
private List<ResourceFile> paths;
|
||||||
|
@ -44,15 +46,22 @@ public class SaveDialog extends DialogComponentProvider implements ListSelection
|
||||||
private JTextField nameField;
|
private JTextField nameField;
|
||||||
private boolean cancelled;
|
private boolean cancelled;
|
||||||
|
|
||||||
protected ResourceFile scriptFile;
|
SaveDialog(Component parent, String title, GhidraScriptComponentProvider componentProvider,
|
||||||
|
ResourceFile scriptFile, HelpLocation help) {
|
||||||
public SaveDialog(Component parent, String title,
|
|
||||||
GhidraScriptComponentProvider componentProvider, ResourceFile scriptFile,
|
|
||||||
HelpLocation help) {
|
|
||||||
this(parent, title, componentProvider, componentProvider.getWritableScriptDirectories(),
|
this(parent, title, componentProvider, componentProvider.getWritableScriptDirectories(),
|
||||||
scriptFile, help);
|
scriptFile, help);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only called directly from testing!
|
||||||
|
*
|
||||||
|
* @param parent parent component
|
||||||
|
* @param title dialog title
|
||||||
|
* @param componentProvider the provider
|
||||||
|
* @param scriptDirs list of directories to give as options when saving
|
||||||
|
* @param scriptFile the default save location
|
||||||
|
* @param help contextual help, e.g. for rename or save
|
||||||
|
*/
|
||||||
public SaveDialog(Component parent, String title,
|
public SaveDialog(Component parent, String title,
|
||||||
GhidraScriptComponentProvider componentProvider, List<ResourceFile> scriptDirs,
|
GhidraScriptComponentProvider componentProvider, List<ResourceFile> scriptDirs,
|
||||||
ResourceFile scriptFile, HelpLocation help) {
|
ResourceFile scriptFile, HelpLocation help) {
|
||||||
|
|
|
@ -27,7 +27,7 @@ public class ScriptCategoryNode extends GTreeNode {
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
public ScriptCategoryNode(String name) {
|
ScriptCategoryNode(String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,6 +129,9 @@ import ghidra.util.task.TaskMonitor;
|
||||||
* @see ghidra.program.model.listing.Program
|
* @see ghidra.program.model.listing.Program
|
||||||
*/
|
*/
|
||||||
public abstract class GhidraScript extends FlatProgramAPI {
|
public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
|
// Stores last-selected value for askXxx() methods, used to pre-populate askXxx()
|
||||||
|
// GUI dialogs if they are run more than once
|
||||||
|
private static Map<String, Map<Class<?>, Object>> askMap = new HashMap<>();
|
||||||
|
|
||||||
protected ResourceFile sourceFile;
|
protected ResourceFile sourceFile;
|
||||||
protected GhidraState state;
|
protected GhidraState state;
|
||||||
|
@ -174,16 +177,19 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
SUSPENDED
|
SUSPENDED
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stores last-selected value for askXxx() methods, used to pre-populate askXxx()
|
|
||||||
// GUI dialogs if they are run more than once
|
|
||||||
private static Map<String, Map<Class<?>, Object>> askMap = new HashMap<>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The run method is where the script specific code is placed.
|
* The run method is where the script specific code is placed.
|
||||||
* @throws Exception if any exception occurs.
|
* @throws Exception if any exception occurs.
|
||||||
*/
|
*/
|
||||||
protected abstract void run() throws Exception;
|
protected abstract void run() throws Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the context for this script.
|
||||||
|
*
|
||||||
|
* @param state state object
|
||||||
|
* @param monitor the monitor to use during run
|
||||||
|
* @param writer the target of script "print" statements
|
||||||
|
*/
|
||||||
public final void set(GhidraState state, TaskMonitor monitor, PrintWriter writer) {
|
public final void set(GhidraState state, TaskMonitor monitor, PrintWriter writer) {
|
||||||
this.state = state;
|
this.state = state;
|
||||||
this.monitor = monitor;
|
this.monitor = monitor;
|
||||||
|
@ -191,6 +197,14 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
loadVariablesFromState();
|
loadVariablesFromState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute/run script and {@link #doCleanup} afterwards.
|
||||||
|
*
|
||||||
|
* @param runState state object
|
||||||
|
* @param runMonitor the monitor to use during run
|
||||||
|
* @param runWriter the target of script "print" statements
|
||||||
|
* @throws Exception if the script excepts
|
||||||
|
*/
|
||||||
public final void execute(GhidraState runState, TaskMonitor runMonitor, PrintWriter runWriter)
|
public final void execute(GhidraState runState, TaskMonitor runMonitor, PrintWriter runWriter)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
boolean success = false;
|
boolean success = false;
|
||||||
|
@ -203,8 +217,8 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final void doExecute(GhidraState runState, TaskMonitor runMonitor,
|
private void doExecute(GhidraState runState, TaskMonitor runMonitor, PrintWriter runWriter)
|
||||||
PrintWriter runWriter) throws Exception {
|
throws Exception {
|
||||||
this.state = runState;
|
this.state = runState;
|
||||||
this.monitor = runMonitor;
|
this.monitor = runMonitor;
|
||||||
this.writer = runWriter;
|
this.writer = runWriter;
|
||||||
|
@ -478,6 +492,11 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the script {@link #currentAddress}, {@link #currentLocation}, and update state object.
|
||||||
|
*
|
||||||
|
* @param address the new address
|
||||||
|
*/
|
||||||
public final void setCurrentLocation(Address address) {
|
public final void setCurrentLocation(Address address) {
|
||||||
state.setCurrentAddress(address);
|
state.setCurrentAddress(address);
|
||||||
this.currentAddress = address;
|
this.currentAddress = address;
|
||||||
|
@ -545,8 +564,8 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
if (isRunningHeadless()) {
|
if (isRunningHeadless()) {
|
||||||
// only change client authenticator in headless mode
|
// only change client authenticator in headless mode
|
||||||
try {
|
try {
|
||||||
HeadlessClientAuthenticator.installHeadlessClientAuthenticator(
|
HeadlessClientAuthenticator
|
||||||
ClientUtil.getUserName(), null, false);
|
.installHeadlessClientAuthenticator(ClientUtil.getUserName(), null, false);
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
throw new RuntimeException("Unexpected Exception", e);
|
throw new RuntimeException("Unexpected Exception", e);
|
||||||
|
@ -1408,7 +1427,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
// Tests if text actually equals "true" or "false
|
// Tests if text actually equals "true" or "false
|
||||||
String tempBool = analysisOptionValue.toLowerCase();
|
String tempBool = analysisOptionValue.toLowerCase();
|
||||||
|
|
||||||
if (tempBool.equals("true") || tempBool.equals("false")) {
|
if ("true".equals(tempBool) || "false".equals(tempBool)) {
|
||||||
options.setBoolean(analysisOption, Boolean.valueOf(tempBool));
|
options.setBoolean(analysisOption, Boolean.valueOf(tempBool));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1785,13 +1804,13 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
try {
|
try {
|
||||||
SwingUtilities.invokeAndWait(
|
SwingUtilities
|
||||||
() -> Msg.showInfo(getClass(), null, name, message));
|
.invokeAndWait(() -> Msg.showInfo(getClass(), null, name, message));
|
||||||
}
|
}
|
||||||
catch (InterruptedException e1) {
|
catch (InterruptedException e) {
|
||||||
// shouldn't happen
|
// shouldn't happen
|
||||||
}
|
}
|
||||||
catch (InvocationTargetException e1) {
|
catch (InvocationTargetException e) {
|
||||||
// shouldn't happen
|
// shouldn't happen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1970,7 +1989,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
}
|
}
|
||||||
|
|
||||||
private interface CancellableFunction<T, R> {
|
private interface CancellableFunction<T, R> {
|
||||||
public R apply(T t) throws CancelledException;
|
R apply(T t) throws CancelledException;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2778,10 +2797,10 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
* @throws IllegalArgumentException if the parsed value is not a valid double.
|
* @throws IllegalArgumentException if the parsed value is not a valid double.
|
||||||
*/
|
*/
|
||||||
public double parseDouble(String val) {
|
public double parseDouble(String val) {
|
||||||
if (val.equalsIgnoreCase("pi")) {
|
if ("pi".equalsIgnoreCase(val)) {
|
||||||
return Math.PI;
|
return Math.PI;
|
||||||
}
|
}
|
||||||
if (val.equalsIgnoreCase("e")) {
|
if ("e".equalsIgnoreCase(val)) {
|
||||||
return Math.E;
|
return Math.E;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
@ -3254,7 +3273,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
* @throws IllegalArgumentException if the parsed value is not a valid boolean.
|
* @throws IllegalArgumentException if the parsed value is not a valid boolean.
|
||||||
*/
|
*/
|
||||||
public Boolean parseBoolean(String val) {
|
public Boolean parseBoolean(String val) {
|
||||||
if (val.equalsIgnoreCase("true") || val.equalsIgnoreCase("false")) {
|
if ("true".equalsIgnoreCase(val) || "false".equalsIgnoreCase(val)) {
|
||||||
return Boolean.parseBoolean(val);
|
return Boolean.parseBoolean(val);
|
||||||
}
|
}
|
||||||
throw new IllegalArgumentException("Invalid boolean: " + val);
|
throw new IllegalArgumentException("Invalid boolean: " + val);
|
||||||
|
|
|
@ -28,6 +28,9 @@ public class GhidraScriptInfoManager {
|
||||||
private Map<ResourceFile, ScriptInfo> scriptFileToInfoMap = new HashMap<>();
|
private Map<ResourceFile, ScriptInfo> scriptFileToInfoMap = new HashMap<>();
|
||||||
private Map<String, List<ResourceFile>> scriptNameToFilesMap = new HashMap<>();
|
private Map<String, List<ResourceFile>> scriptNameToFilesMap = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clear stored metadata
|
||||||
|
*/
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
clearMetadata();
|
clearMetadata();
|
||||||
}
|
}
|
||||||
|
@ -110,6 +113,12 @@ public class GhidraScriptInfoManager {
|
||||||
return scriptFileToInfoMap.containsKey(scriptFile);
|
return scriptFileToInfoMap.containsKey(scriptFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get {@link ScriptInfo} for {@code script} under the assumption that it's already managed.
|
||||||
|
*
|
||||||
|
* @param script the script
|
||||||
|
* @return info or null if the assumption was wrong. If null is returned, an error dialog is shown
|
||||||
|
*/
|
||||||
public ScriptInfo getExistingScriptInfo(ResourceFile script) {
|
public ScriptInfo getExistingScriptInfo(ResourceFile script) {
|
||||||
ScriptInfo info = scriptFileToInfoMap.get(script);
|
ScriptInfo info = scriptFileToInfoMap.get(script);
|
||||||
if (info == null) {
|
if (info == null) {
|
||||||
|
|
|
@ -33,7 +33,7 @@ public class GhidraScriptProperties {
|
||||||
private HashMap<String, String> propertiesMap;
|
private HashMap<String, String> propertiesMap;
|
||||||
private String baseName;
|
private String baseName;
|
||||||
|
|
||||||
public GhidraScriptProperties() {
|
GhidraScriptProperties() {
|
||||||
propertiesMap = new HashMap<>();
|
propertiesMap = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,6 +73,9 @@ public class GhidraScriptProperties {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the properties file name
|
||||||
|
*/
|
||||||
public String getFilename() {
|
public String getFilename() {
|
||||||
return baseName + ".properties";
|
return baseName + ".properties";
|
||||||
}
|
}
|
||||||
|
@ -138,6 +141,10 @@ public class GhidraScriptProperties {
|
||||||
return propertiesMap.put(key.trim(), value);
|
return propertiesMap.put(key.trim(), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param keyString the property name
|
||||||
|
* @return the value of the key in the properties file, or an empty string if no property exists
|
||||||
|
*/
|
||||||
public String getValue(String keyString) {
|
public String getValue(String keyString) {
|
||||||
|
|
||||||
if (propertiesMap.size() == 0) {
|
if (propertiesMap.size() == 0) {
|
||||||
|
@ -151,10 +158,19 @@ public class GhidraScriptProperties {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if there are no properties
|
||||||
|
*/
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return (propertiesMap.size() == 0);
|
return (propertiesMap.size() == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the named property
|
||||||
|
*
|
||||||
|
* @param keyString the property name
|
||||||
|
* @return the previous value or null
|
||||||
|
*/
|
||||||
protected String remove(String keyString) {
|
protected String remove(String keyString) {
|
||||||
return propertiesMap.remove(keyString);
|
return propertiesMap.remove(keyString);
|
||||||
}
|
}
|
||||||
|
@ -163,14 +179,25 @@ public class GhidraScriptProperties {
|
||||||
propertiesMap.clear();
|
propertiesMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param keyString a property name
|
||||||
|
* @return true if the key exists in the property file
|
||||||
|
*/
|
||||||
public boolean containsKey(String keyString) {
|
public boolean containsKey(String keyString) {
|
||||||
return propertiesMap.containsKey(keyString);
|
return propertiesMap.containsKey(keyString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param valueString a value string
|
||||||
|
* @return true if any property has the given value
|
||||||
|
*/
|
||||||
public boolean containsValue(String valueString) {
|
public boolean containsValue(String valueString) {
|
||||||
return propertiesMap.containsValue(valueString);
|
return propertiesMap.containsValue(valueString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the property names for all properties
|
||||||
|
*/
|
||||||
public Set<String> keySet() {
|
public Set<String> keySet() {
|
||||||
return propertiesMap.keySet();
|
return propertiesMap.keySet();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/* ###
|
/* ###
|
||||||
* IP: GHIDRA
|
* IP: GHIDRA
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -20,7 +19,7 @@ import generic.jar.ResourceFile;
|
||||||
|
|
||||||
class GhidraScriptUnsupportedClassVersionError extends RuntimeException {
|
class GhidraScriptUnsupportedClassVersionError extends RuntimeException {
|
||||||
|
|
||||||
private ResourceFile classFile;
|
private final ResourceFile classFile;
|
||||||
|
|
||||||
GhidraScriptUnsupportedClassVersionError(UnsupportedClassVersionError cause,
|
GhidraScriptUnsupportedClassVersionError(UnsupportedClassVersionError cause,
|
||||||
ResourceFile classFile) {
|
ResourceFile classFile) {
|
||||||
|
|
|
@ -15,7 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.script;
|
package ghidra.app.script;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
@ -31,31 +32,38 @@ import ghidra.util.classfinder.ClassSearcher;
|
||||||
* A utility class for managing script directories and ScriptInfo objects.
|
* A utility class for managing script directories and ScriptInfo objects.
|
||||||
*/
|
*/
|
||||||
public class GhidraScriptUtil {
|
public class GhidraScriptUtil {
|
||||||
|
|
||||||
private static final String SCRIPTS_SUBDIR_NAME = "ghidra_scripts";
|
|
||||||
private static final String DEV_SCRIPTS_SUBDIR_NAME = "developer_scripts";
|
|
||||||
|
|
||||||
private static List<GhidraScriptProvider> providers = null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User's home scripts directory
|
* User's home scripts directory
|
||||||
*/
|
*/
|
||||||
public static String USER_SCRIPTS_DIR = buildUserScriptsDirectory();
|
public static String USER_SCRIPTS_DIR = buildUserScriptsDirectory();
|
||||||
|
|
||||||
static BundleHost _bundleHost;
|
private static BundleHost bundleHost;
|
||||||
|
|
||||||
|
private static final String SCRIPTS_SUBDIR_NAME = "ghidra_scripts";
|
||||||
|
private static final String DEV_SCRIPTS_SUBDIR_NAME = "developer_scripts";
|
||||||
|
|
||||||
|
private static List<GhidraScriptProvider> providers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the bundle host used for scripting
|
||||||
|
*/
|
||||||
public static BundleHost getBundleHost() {
|
public static BundleHost getBundleHost() {
|
||||||
return _bundleHost;
|
return bundleHost;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void setBundleHost(BundleHost bundleHost) {
|
/**
|
||||||
if (_bundleHost != null) {
|
* set the bundle host and start the framework
|
||||||
|
*
|
||||||
|
* @param aBundleHost the bundle host
|
||||||
|
*/
|
||||||
|
private static void setBundleHost(BundleHost aBundleHost) {
|
||||||
|
if (bundleHost != null) {
|
||||||
throw new RuntimeException("GhidraScriptUtil initialized multiple times!");
|
throw new RuntimeException("GhidraScriptUtil initialized multiple times!");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
_bundleHost = bundleHost;
|
bundleHost = aBundleHost;
|
||||||
_bundleHost.startFramework();
|
bundleHost.startFramework();
|
||||||
}
|
}
|
||||||
catch (OSGiException | IOException e) {
|
catch (OSGiException | IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
@ -66,26 +74,29 @@ public class GhidraScriptUtil {
|
||||||
/**
|
/**
|
||||||
* initialize state of GhidraScriptUtil with user, system paths, and optional extra system paths.
|
* initialize state of GhidraScriptUtil with user, system paths, and optional extra system paths.
|
||||||
*
|
*
|
||||||
* @param bundleHost the host to use
|
* @param aBundleHost the host to use
|
||||||
* @param extraSystemPaths additional system paths for this run, can be null
|
* @param extraSystemPaths additional system paths for this run, can be null
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public static void initialize(BundleHost bundleHost, List<String> extraSystemPaths) {
|
public static void initialize(BundleHost aBundleHost, List<String> extraSystemPaths) {
|
||||||
setBundleHost(bundleHost);
|
setBundleHost(aBundleHost);
|
||||||
if (extraSystemPaths != null) {
|
if (extraSystemPaths != null) {
|
||||||
for (String path : extraSystemPaths) {
|
for (String path : extraSystemPaths) {
|
||||||
bundleHost.add(new ResourceFile(path), true, true);
|
bundleHost.add(new ResourceFile(path), true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bundleHost.add(GhidraScriptUtil.getUserScriptDirectory(), true, false);
|
bundleHost.add(getUserScriptDirectory(), true, false);
|
||||||
bundleHost.add(GhidraScriptUtil.getSystemScriptPaths(), true, true);
|
bundleHost.add(getSystemScriptPaths(), true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dispose of the bundle host and providers list
|
||||||
|
*/
|
||||||
public static void dispose() {
|
public static void dispose() {
|
||||||
if (_bundleHost != null) {
|
if (bundleHost != null) {
|
||||||
_bundleHost.dispose();
|
bundleHost.dispose();
|
||||||
_bundleHost = null;
|
bundleHost = null;
|
||||||
}
|
}
|
||||||
providers = null;
|
providers = null;
|
||||||
}
|
}
|
||||||
|
@ -95,8 +106,10 @@ public class GhidraScriptUtil {
|
||||||
* @return a list of the current script directories
|
* @return a list of the current script directories
|
||||||
*/
|
*/
|
||||||
public static List<ResourceFile> getScriptSourceDirectories() {
|
public static List<ResourceFile> getScriptSourceDirectories() {
|
||||||
return _bundleHost.getBundlePaths().stream().filter(ResourceFile::isDirectory).collect(
|
return bundleHost.getBundlePaths()
|
||||||
Collectors.toList());
|
.stream()
|
||||||
|
.filter(ResourceFile::isDirectory)
|
||||||
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ResourceFile getSourceDirectoryContaining(ResourceFile sourceFile) {
|
public static ResourceFile getSourceDirectoryContaining(ResourceFile sourceFile) {
|
||||||
|
@ -199,8 +212,10 @@ public class GhidraScriptUtil {
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public static List<ResourceFile> getExplodedCompiledSourceBundlePaths() {
|
public static List<ResourceFile> getExplodedCompiledSourceBundlePaths() {
|
||||||
try {
|
try {
|
||||||
return Files.list(BundleHost.getOsgiDir()).filter(Files::isDirectory).map(
|
return Files.list(BundleHost.getOsgiDir())
|
||||||
x -> new ResourceFile(x.toFile())).collect(Collectors.toList());
|
.filter(Files::isDirectory)
|
||||||
|
.map(x -> new ResourceFile(x.toFile()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
Msg.showError(GhidraScriptUtil.class, null, "error",
|
Msg.showError(GhidraScriptUtil.class, null, "error",
|
||||||
|
@ -231,7 +246,7 @@ public class GhidraScriptUtil {
|
||||||
* @return a list of all Ghidra script providers
|
* @return a list of all Ghidra script providers
|
||||||
*/
|
*/
|
||||||
// Note: this method is synchronized so that two threads do not try to create the list when null
|
// Note: this method is synchronized so that two threads do not try to create the list when null
|
||||||
public synchronized static List<GhidraScriptProvider> getProviders() {
|
public static synchronized List<GhidraScriptProvider> getProviders() {
|
||||||
if (providers == null) {
|
if (providers == null) {
|
||||||
List<GhidraScriptProvider> newProviders =
|
List<GhidraScriptProvider> newProviders =
|
||||||
new ArrayList<>(ClassSearcher.getInstances(GhidraScriptProvider.class));
|
new ArrayList<>(ClassSearcher.getInstances(GhidraScriptProvider.class));
|
||||||
|
@ -338,8 +353,7 @@ public class GhidraScriptUtil {
|
||||||
return path + ".java";
|
return path + ".java";
|
||||||
}
|
}
|
||||||
|
|
||||||
static ResourceFile findScriptFileInPaths(
|
static ResourceFile findScriptFileInPaths(Collection<ResourceFile> scriptDirectories,
|
||||||
Collection<ResourceFile> scriptDirectories,
|
|
||||||
String filename) {
|
String filename) {
|
||||||
|
|
||||||
String validatedName = fixupName(filename);
|
String validatedName = fixupName(filename);
|
||||||
|
|
|
@ -41,7 +41,7 @@ public class GhidraState {
|
||||||
private ProgramSelection currentSelection;
|
private ProgramSelection currentSelection;
|
||||||
private ProgramSelection currentHighlight;
|
private ProgramSelection currentHighlight;
|
||||||
private HashMap<String, Object> envmap = new HashMap<>();
|
private HashMap<String, Object> envmap = new HashMap<>();
|
||||||
private GatherParamPanel gatherParamPanel = null;
|
private GatherParamPanel gatherParamPanel;
|
||||||
private Project project;
|
private Project project;
|
||||||
private final boolean isGlobalState;
|
private final boolean isGlobalState;
|
||||||
|
|
||||||
|
@ -105,6 +105,7 @@ public class GhidraState {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the current program.
|
* Sets the current program.
|
||||||
|
* @param program the new program object
|
||||||
*/
|
*/
|
||||||
public void setCurrentProgram(Program program) {
|
public void setCurrentProgram(Program program) {
|
||||||
if (program == currentProgram) {
|
if (program == currentProgram) {
|
||||||
|
@ -117,11 +118,19 @@ public class GhidraState {
|
||||||
gatherParamPanel.currentProgramChanged();
|
gatherParamPanel.currentProgramChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the address of the current location
|
||||||
|
*/
|
||||||
public Address getCurrentAddress() {
|
public Address getCurrentAddress() {
|
||||||
return currentLocation != null ? currentLocation.getAddress() : null;
|
return currentLocation != null ? currentLocation.getAddress() : null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If it differs, set the current location to the given address and fire a {@link ProgramLocationPluginEvent}.
|
||||||
|
*
|
||||||
|
* @param address the address
|
||||||
|
*/
|
||||||
public void setCurrentAddress(Address address) {
|
public void setCurrentAddress(Address address) {
|
||||||
if (SystemUtilities.isEqual(address, getCurrentAddress())) {
|
if (SystemUtilities.isEqual(address, getCurrentAddress())) {
|
||||||
return;
|
return;
|
||||||
|
@ -129,10 +138,18 @@ public class GhidraState {
|
||||||
setCurrentLocation(new ProgramLocation(currentProgram, address));
|
setCurrentLocation(new ProgramLocation(currentProgram, address));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the current location
|
||||||
|
*/
|
||||||
public ProgramLocation getCurrentLocation() {
|
public ProgramLocation getCurrentLocation() {
|
||||||
return currentLocation;
|
return currentLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If it differs, set the current location and fire a {@link ProgramLocationPluginEvent}.
|
||||||
|
*
|
||||||
|
* @param location
|
||||||
|
*/
|
||||||
public void setCurrentLocation(ProgramLocation location) {
|
public void setCurrentLocation(ProgramLocation location) {
|
||||||
if (SystemUtilities.isEqual(currentLocation, location)) {
|
if (SystemUtilities.isEqual(currentLocation, location)) {
|
||||||
return;
|
return;
|
||||||
|
@ -144,10 +161,18 @@ public class GhidraState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the currently highlighted selection
|
||||||
|
*/
|
||||||
public ProgramSelection getCurrentHighlight() {
|
public ProgramSelection getCurrentHighlight() {
|
||||||
return currentHighlight;
|
return currentHighlight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the currently highlighted selection and fire a {@link ProgramHighlightPluginEvent}.
|
||||||
|
*
|
||||||
|
* @param highlight the selection
|
||||||
|
*/
|
||||||
public void setCurrentHighlight(ProgramSelection highlight) {
|
public void setCurrentHighlight(ProgramSelection highlight) {
|
||||||
if (SystemUtilities.isEqual(currentHighlight, highlight)) {
|
if (SystemUtilities.isEqual(currentHighlight, highlight)) {
|
||||||
return;
|
return;
|
||||||
|
@ -162,10 +187,18 @@ public class GhidraState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the current selection
|
||||||
|
*/
|
||||||
public ProgramSelection getCurrentSelection() {
|
public ProgramSelection getCurrentSelection() {
|
||||||
return currentSelection;
|
return currentSelection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the current selection and fire a {@link kProgramSelectionPluginEvent}.
|
||||||
|
*
|
||||||
|
* @param selection the selection
|
||||||
|
*/
|
||||||
public void setCurrentSelection(ProgramSelection selection) {
|
public void setCurrentSelection(ProgramSelection selection) {
|
||||||
if (SystemUtilities.isEqual(currentSelection, selection)) {
|
if (SystemUtilities.isEqual(currentSelection, selection)) {
|
||||||
return;
|
return;
|
||||||
|
@ -181,27 +214,27 @@ public class GhidraState {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addEnvironmentVar(String name, byte value) {
|
public void addEnvironmentVar(String name, byte value) {
|
||||||
envmap.put(name, new Byte(value));
|
envmap.put(name, Byte.valueOf(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addEnvironmentVar(String name, short value) {
|
public void addEnvironmentVar(String name, short value) {
|
||||||
envmap.put(name, new Short(value));
|
envmap.put(name, Short.valueOf(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addEnvironmentVar(String name, int value) {
|
public void addEnvironmentVar(String name, int value) {
|
||||||
envmap.put(name, new Integer(value));
|
envmap.put(name, Integer.valueOf(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addEnvironmentVar(String name, long value) {
|
public void addEnvironmentVar(String name, long value) {
|
||||||
envmap.put(name, new Long(value));
|
envmap.put(name, Long.valueOf(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addEnvironmentVar(String name, float value) {
|
public void addEnvironmentVar(String name, float value) {
|
||||||
envmap.put(name, new Float(value));
|
envmap.put(name, Float.valueOf(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addEnvironmentVar(String name, double value) {
|
public void addEnvironmentVar(String name, double value) {
|
||||||
envmap.put(name, new Double(value));
|
envmap.put(name, Double.valueOf(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addEnvironmentVar(String name, Object value) {
|
public void addEnvironmentVar(String name, Object value) {
|
||||||
|
|
|
@ -24,18 +24,27 @@ import ghidra.app.plugin.core.osgi.*;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
|
|
||||||
public class JavaScriptProvider extends GhidraScriptProvider {
|
public class JavaScriptProvider extends GhidraScriptProvider {
|
||||||
final private BundleHost _bundleHost;
|
private final BundleHost bundleHost;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link JavaScriptProvider} associated with the current bundle host used by scripting.
|
||||||
|
*/
|
||||||
public JavaScriptProvider() {
|
public JavaScriptProvider() {
|
||||||
_bundleHost = GhidraScriptUtil.getBundleHost();
|
bundleHost = GhidraScriptUtil.getBundleHost();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the {@link GhidraSourceBundle} containing the given source file, assuming it already exists.
|
||||||
|
*
|
||||||
|
* @param sourceFile the source file
|
||||||
|
* @return the bundle
|
||||||
|
*/
|
||||||
public GhidraSourceBundle getBundleForSource(ResourceFile sourceFile) {
|
public GhidraSourceBundle getBundleForSource(ResourceFile sourceFile) {
|
||||||
ResourceFile sourceDir = GhidraScriptUtil.getSourceDirectoryContaining(sourceFile);
|
ResourceFile sourceDir = GhidraScriptUtil.getSourceDirectoryContaining(sourceFile);
|
||||||
if (sourceDir == null) {
|
if (sourceDir == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (GhidraSourceBundle) _bundleHost.getExistingGhidraBundle(sourceDir);
|
return (GhidraSourceBundle) bundleHost.getExistingGhidraBundle(sourceDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -53,7 +62,7 @@ public class JavaScriptProvider extends GhidraScriptProvider {
|
||||||
try {
|
try {
|
||||||
Bundle osgiBundle = getBundleForSource(sourceFile).getOSGiBundle();
|
Bundle osgiBundle = getBundleForSource(sourceFile).getOSGiBundle();
|
||||||
if (osgiBundle != null) {
|
if (osgiBundle != null) {
|
||||||
_bundleHost.deactivateSynchronously(osgiBundle);
|
bundleHost.deactivateSynchronously(osgiBundle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (GhidraBundleException | InterruptedException e) {
|
catch (GhidraBundleException | InterruptedException e) {
|
||||||
|
@ -92,13 +101,22 @@ public class JavaScriptProvider extends GhidraScriptProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activate and build the {@link GhidraSourceBundle} containing {@code sourceFile}
|
||||||
|
* then load the script's class from its class loader.
|
||||||
|
*
|
||||||
|
* @param sourceFile the source file
|
||||||
|
* @param writer the target for build messages
|
||||||
|
* @return the loaded {@link Class} object
|
||||||
|
* @throws Exception if build, activation, or class loading fail
|
||||||
|
*/
|
||||||
public Class<?> loadClass(ResourceFile sourceFile, PrintWriter writer) throws Exception {
|
public Class<?> loadClass(ResourceFile sourceFile, PrintWriter writer) throws Exception {
|
||||||
GhidraSourceBundle gb = getBundleForSource(sourceFile);
|
GhidraSourceBundle gb = getBundleForSource(sourceFile);
|
||||||
gb.build(writer);
|
gb.build(writer);
|
||||||
|
|
||||||
Bundle b = _bundleHost.install(gb);
|
Bundle b = bundleHost.install(gb);
|
||||||
|
|
||||||
_bundleHost.activateSynchronously(b);
|
bundleHost.activateSynchronously(b);
|
||||||
|
|
||||||
String classname = gb.classNameForScript(sourceFile);
|
String classname = gb.classNameForScript(sourceFile);
|
||||||
Class<?> clazz = b.loadClass(classname); // throws ClassNotFoundException
|
Class<?> clazz = b.loadClass(classname); // throws ClassNotFoundException
|
||||||
|
|
|
@ -34,11 +34,18 @@ public class ResourceFileJavaFileManager implements JavaFileManager {
|
||||||
|
|
||||||
private StandardJavaFileManager fileManager;
|
private StandardJavaFileManager fileManager;
|
||||||
private List<ResourceFile> sourceDirs;
|
private List<ResourceFile> sourceDirs;
|
||||||
private Set<ResourceFile> avoid;
|
private Set<ResourceFile> filesToAvoid;
|
||||||
|
|
||||||
public ResourceFileJavaFileManager(List<ResourceFile> sourceDirs, Set<ResourceFile> avoid) {
|
/**
|
||||||
|
* Create a {@link JavaFileManager} for use by the {@link JavaCompiler}.
|
||||||
|
*
|
||||||
|
* @param sourceDirs the directories containing source
|
||||||
|
* @param filesToAvoid known "bad" files to hide from the compiler
|
||||||
|
*/
|
||||||
|
public ResourceFileJavaFileManager(List<ResourceFile> sourceDirs,
|
||||||
|
Set<ResourceFile> filesToAvoid) {
|
||||||
this.sourceDirs = sourceDirs;
|
this.sourceDirs = sourceDirs;
|
||||||
this.avoid = avoid;
|
this.filesToAvoid = filesToAvoid;
|
||||||
JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
|
JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
|
||||||
if (javaCompiler == null) {
|
if (javaCompiler == null) {
|
||||||
throw new AssertException("Can't find java compiler");
|
throw new AssertException("Can't find java compiler");
|
||||||
|
@ -79,7 +86,7 @@ public class ResourceFileJavaFileManager implements JavaFileManager {
|
||||||
private void gatherFiles(ResourceFile root, ResourceFile file, List<JavaFileObject> accumulator,
|
private void gatherFiles(ResourceFile root, ResourceFile file, List<JavaFileObject> accumulator,
|
||||||
Set<Kind> kinds, boolean recurse) {
|
Set<Kind> kinds, boolean recurse) {
|
||||||
List<ResourceFile> listFiles = new ArrayList<>(Arrays.asList(file.listFiles()));
|
List<ResourceFile> listFiles = new ArrayList<>(Arrays.asList(file.listFiles()));
|
||||||
listFiles.removeAll(avoid);
|
listFiles.removeAll(filesToAvoid);
|
||||||
for (ResourceFile resourceFile : listFiles) {
|
for (ResourceFile resourceFile : listFiles) {
|
||||||
if (resourceFile.isDirectory()) {
|
if (resourceFile.isDirectory()) {
|
||||||
if (recurse) {
|
if (recurse) {
|
||||||
|
@ -154,7 +161,7 @@ public class ResourceFileJavaFileManager implements JavaFileManager {
|
||||||
@Override
|
@Override
|
||||||
public JavaFileObject getJavaFileForInput(Location location, String className, Kind kind)
|
public JavaFileObject getJavaFileForInput(Location location, String className, Kind kind)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if (!location.equals(StandardLocation.SOURCE_PATH) || className.equals("module-info")) {
|
if (!location.equals(StandardLocation.SOURCE_PATH) || "module-info".equals(className)) {
|
||||||
// Our Ghidra scripts will not use Java 9's module definition file (module-info.java).
|
// Our Ghidra scripts will not use Java 9's module definition file (module-info.java).
|
||||||
return fileManager.getJavaFileForInput(location, className, kind);
|
return fileManager.getJavaFileForInput(location, className, kind);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import java.net.URI;
|
||||||
|
|
||||||
import javax.lang.model.element.Modifier;
|
import javax.lang.model.element.Modifier;
|
||||||
import javax.lang.model.element.NestingKind;
|
import javax.lang.model.element.NestingKind;
|
||||||
|
import javax.tools.JavaCompiler;
|
||||||
import javax.tools.JavaFileObject;
|
import javax.tools.JavaFileObject;
|
||||||
|
|
||||||
import generic.jar.ResourceFile;
|
import generic.jar.ResourceFile;
|
||||||
|
@ -35,6 +36,13 @@ public class ResourceFileJavaFileObject implements JavaFileObject {
|
||||||
private String pathName;
|
private String pathName;
|
||||||
private Kind kind;
|
private Kind kind;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a {@link ResourceFile} for a {@link JavaCompiler} via a {@link ResourceFileJavaFileManager}
|
||||||
|
*
|
||||||
|
* @param sourceRoot the root source directory
|
||||||
|
* @param file the file
|
||||||
|
* @param kind the kind
|
||||||
|
*/
|
||||||
public ResourceFileJavaFileObject(ResourceFile sourceRoot, ResourceFile file, Kind kind) {
|
public ResourceFileJavaFileObject(ResourceFile sourceRoot, ResourceFile file, Kind kind) {
|
||||||
this.file = file;
|
this.file = file;
|
||||||
this.kind = kind;
|
this.kind = kind;
|
||||||
|
@ -43,6 +51,9 @@ public class ResourceFileJavaFileObject implements JavaFileObject {
|
||||||
pathName = file.getAbsolutePath().substring(sourceRootPath.length() + 1);
|
pathName = file.getAbsolutePath().substring(sourceRootPath.length() + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the {@link ResourceFile} this object represents
|
||||||
|
*/
|
||||||
public ResourceFile getFile() {
|
public ResourceFile getFile() {
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,12 +36,8 @@ import resources.ResourceManager;
|
||||||
* This class parses the meta-data about a script.
|
* This class parses the meta-data about a script.
|
||||||
*/
|
*/
|
||||||
public class ScriptInfo {
|
public class ScriptInfo {
|
||||||
|
|
||||||
private static final Pattern DOCUMENTATION_START = Pattern.compile("/\\*");
|
|
||||||
private static final Pattern DOCUMENTATION_END = Pattern.compile("\\*/");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The delimiter used to categories and menu paths.
|
* The delimiter used in categories and menu paths.
|
||||||
*/
|
*/
|
||||||
public static final String DELIMITTER = ".";
|
public static final String DELIMITTER = ".";
|
||||||
|
|
||||||
|
@ -51,6 +47,9 @@ public class ScriptInfo {
|
||||||
static final String AT_MENUPATH = "@menupath";
|
static final String AT_MENUPATH = "@menupath";
|
||||||
static final String AT_TOOLBAR = "@toolbar";
|
static final String AT_TOOLBAR = "@toolbar";
|
||||||
|
|
||||||
|
private static final Pattern DOCUMENTATION_START = Pattern.compile("/\\*");
|
||||||
|
private static final Pattern DOCUMENTATION_END = Pattern.compile("\\*/");
|
||||||
|
|
||||||
// omit from METADATA to avoid pre-populating in new scripts
|
// omit from METADATA to avoid pre-populating in new scripts
|
||||||
private static final String AT_IMPORTPACKAGE = "@importpackage";
|
private static final String AT_IMPORTPACKAGE = "@importpackage";
|
||||||
|
|
||||||
|
@ -231,7 +230,7 @@ public class ScriptInfo {
|
||||||
description = buffer.toString();
|
description = buffer.toString();
|
||||||
modified = sourceFile.lastModified();
|
modified = sourceFile.lastModified();
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (IOException e) {
|
||||||
Msg.debug(this, "Unexpected exception reading script: " + sourceFile, e);
|
Msg.debug(this, "Unexpected exception reading script: " + sourceFile, e);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
@ -403,6 +402,9 @@ public class ScriptInfo {
|
||||||
return keyBinding;
|
return keyBinding;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return an error resulting from parsing keybinding metadata
|
||||||
|
*/
|
||||||
public String getKeyBindingErrorMessage() {
|
public String getKeyBindingErrorMessage() {
|
||||||
return keybindingErrorMessage;
|
return keybindingErrorMessage;
|
||||||
}
|
}
|
||||||
|
@ -460,7 +462,6 @@ public class ScriptInfo {
|
||||||
String space = HTML_SPACE;
|
String space = HTML_SPACE;
|
||||||
String htmlAuthor = bold("Author:") + space + escapeHTML(toString(author));
|
String htmlAuthor = bold("Author:") + space + escapeHTML(toString(author));
|
||||||
String htmlCategory = bold("Category:") + space + escapeHTML(toString(category));
|
String htmlCategory = bold("Category:") + space + escapeHTML(toString(category));
|
||||||
|
|
||||||
String htmlKeyBinding = bold("Key Binding:") + space + getKeybindingToolTip();
|
String htmlKeyBinding = bold("Key Binding:") + space + getKeybindingToolTip();
|
||||||
String htmlMenuPath = bold("Menu Path:") + space + escapeHTML(toString(menupath));
|
String htmlMenuPath = bold("Menu Path:") + space + escapeHTML(toString(menupath));
|
||||||
|
|
||||||
|
@ -505,10 +506,16 @@ public class ScriptInfo {
|
||||||
return StringUtils.defaultString(joined);
|
return StringUtils.defaultString(joined);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if the script either has compiler errors, or is a duplicate
|
||||||
|
*/
|
||||||
public boolean hasErrors() {
|
public boolean hasErrors() {
|
||||||
return isCompileErrors() || isDuplicate();
|
return isCompileErrors() || isDuplicate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return a generic error message
|
||||||
|
*/
|
||||||
public String getErrorMessage() {
|
public String getErrorMessage() {
|
||||||
if (isCompileErrors()) {
|
if (isCompileErrors()) {
|
||||||
return "Script contains compiler errors";
|
return "Script contains compiler errors";
|
||||||
|
|
|
@ -16,6 +16,5 @@
|
||||||
package ghidra.app.script;
|
package ghidra.app.script;
|
||||||
|
|
||||||
public interface StringTransformer<T> {
|
public interface StringTransformer<T> {
|
||||||
|
T apply(String s);
|
||||||
public T apply(String s);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -174,11 +174,11 @@ public abstract class AbstractGhidraScriptMgrPluginTest
|
||||||
env.dispose();
|
env.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
static protected void wipe(ResourceFile path) throws IOException {
|
protected static void wipe(ResourceFile path) throws IOException {
|
||||||
wipe(Paths.get(path.getAbsolutePath()));
|
wipe(Paths.get(path.getAbsolutePath()));
|
||||||
}
|
}
|
||||||
|
|
||||||
static protected void wipe(Path path) throws IOException {
|
protected static void wipe(Path path) throws IOException {
|
||||||
if (Files.exists(path)) {
|
if (Files.exists(path)) {
|
||||||
for (Path p : (Iterable<Path>) Files.walk(path)
|
for (Path p : (Iterable<Path>) Files.walk(path)
|
||||||
.sorted(Comparator.reverseOrder())::iterator) {
|
.sorted(Comparator.reverseOrder())::iterator) {
|
||||||
|
@ -392,7 +392,7 @@ public abstract class AbstractGhidraScriptMgrPluginTest
|
||||||
|
|
||||||
assertNotNull(editor);
|
assertNotNull(editor);
|
||||||
|
|
||||||
editorTextArea = (JTextArea) findComponentByName(editor.getComponent(), "EDITOR");
|
editorTextArea = (JTextArea) findComponentByName(editor.getComponent(), GhidraScriptEditorComponentProvider.EDITOR_COMPONENT_NAME);
|
||||||
assertNotNull(editorTextArea);
|
assertNotNull(editorTextArea);
|
||||||
|
|
||||||
buffer = new StringBuffer(editorTextArea.getText());
|
buffer = new StringBuffer(editorTextArea.getText());
|
||||||
|
@ -411,7 +411,7 @@ public abstract class AbstractGhidraScriptMgrPluginTest
|
||||||
|
|
||||||
// initialize our editor variable to the newly opened editor
|
// initialize our editor variable to the newly opened editor
|
||||||
editor = waitForComponentProvider(GhidraScriptEditorComponentProvider.class);
|
editor = waitForComponentProvider(GhidraScriptEditorComponentProvider.class);
|
||||||
editorTextArea = (JTextArea) findComponentByName(editor.getComponent(), "EDITOR");
|
editorTextArea = (JTextArea) findComponentByName(editor.getComponent(), GhidraScriptEditorComponentProvider.EDITOR_COMPONENT_NAME);
|
||||||
|
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
|
||||||
|
@ -850,7 +850,7 @@ public abstract class AbstractGhidraScriptMgrPluginTest
|
||||||
Map<ResourceFile, GhidraScriptEditorComponentProvider> map = provider.getEditorMap();
|
Map<ResourceFile, GhidraScriptEditorComponentProvider> map = provider.getEditorMap();
|
||||||
GhidraScriptEditorComponentProvider fileEditor = map.get(file);
|
GhidraScriptEditorComponentProvider fileEditor = map.get(file);
|
||||||
final JTextArea textArea =
|
final JTextArea textArea =
|
||||||
(JTextArea) findComponentByName(fileEditor.getComponent(), "EDITOR");
|
(JTextArea) findComponentByName(fileEditor.getComponent(), GhidraScriptEditorComponentProvider.EDITOR_COMPONENT_NAME);
|
||||||
assertNotNull(textArea);
|
assertNotNull(textArea);
|
||||||
|
|
||||||
final String[] box = new String[1];
|
final String[] box = new String[1];
|
||||||
|
@ -1164,7 +1164,7 @@ public abstract class AbstractGhidraScriptMgrPluginTest
|
||||||
return info.getSourceFile();
|
return info.getSourceFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
static protected String CANCELLABLE_SCRIPT_NAME = TestChangeProgramScript.class.getName();
|
protected static String CANCELLABLE_SCRIPT_NAME = TestChangeProgramScript.class.getName();
|
||||||
|
|
||||||
protected void cancel() throws Exception {
|
protected void cancel() throws Exception {
|
||||||
Window window = waitForWindowByTitleContaining(CANCELLABLE_SCRIPT_NAME);
|
Window window = waitForWindowByTitleContaining(CANCELLABLE_SCRIPT_NAME);
|
||||||
|
@ -1494,7 +1494,7 @@ public abstract class AbstractGhidraScriptMgrPluginTest
|
||||||
|
|
||||||
protected JTextComponent grabScriptEditorTextArea() {
|
protected JTextComponent grabScriptEditorTextArea() {
|
||||||
GhidraScriptEditorComponentProvider scriptEditor = grabScriptEditor();
|
GhidraScriptEditorComponentProvider scriptEditor = grabScriptEditor();
|
||||||
JTextArea textArea = (JTextArea) findComponentByName(scriptEditor.getComponent(), "EDITOR");
|
JTextArea textArea = (JTextArea) findComponentByName(scriptEditor.getComponent(), GhidraScriptEditorComponentProvider.EDITOR_COMPONENT_NAME);
|
||||||
assertNotNull(textArea);
|
assertNotNull(textArea);
|
||||||
return textArea;
|
return textArea;
|
||||||
}
|
}
|
||||||
|
@ -1596,9 +1596,9 @@ public abstract class AbstractGhidraScriptMgrPluginTest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (CancelledException ce) {
|
catch (CancelledException e) {
|
||||||
doneLatch.countDown();
|
doneLatch.countDown();
|
||||||
throw ce;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
doneLatch.countDown();
|
doneLatch.countDown();
|
||||||
|
|
|
@ -119,7 +119,7 @@ public class GhidraScriptMgrPluginScreenShots extends GhidraScreenShotGenerator
|
||||||
BundleStatusComponentProvider bundleStatusComponentProvider =
|
BundleStatusComponentProvider bundleStatusComponentProvider =
|
||||||
showProvider(BundleStatusComponentProvider.class);
|
showProvider(BundleStatusComponentProvider.class);
|
||||||
|
|
||||||
bundleStatusComponentProvider.getModel().setPathsForTesting(paths);
|
bundleStatusComponentProvider.setPathsForTesting(paths);
|
||||||
|
|
||||||
waitForComponentProvider(BundleStatusComponentProvider.class);
|
waitForComponentProvider(BundleStatusComponentProvider.class);
|
||||||
captureComponent(bundleStatusComponentProvider.getComponent());
|
captureComponent(bundleStatusComponentProvider.getComponent());
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue