mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-02-18 00:20:10 +00:00
style fixes in ghidra.app. {plugin.core.script script}
This commit is contained in:
parent
6bc33bdf65
commit
2015f13542
@ -24,6 +24,7 @@ import java.util.*;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.KeyStroke;
|
||||
|
||||
import docking.ActionContext;
|
||||
@ -49,18 +50,15 @@ class GhidraScriptActionManager {
|
||||
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 RESOURCE_FILE_ACTION_RUN_GROUP = "1";
|
||||
|
||||
private GhidraScriptComponentProvider provider;
|
||||
private GhidraScriptMgrPlugin plugin;
|
||||
private GhidraScriptInfoManager infoManager;
|
||||
private DockingAction refreshAction;
|
||||
private DockingAction bundleStatusAction;
|
||||
private DockingAction showBundleStatusAction;
|
||||
private DockingAction newAction;
|
||||
private DockingAction runAction;
|
||||
private DockingAction runLastAction;
|
||||
private DockingAction globalRunLastAction;
|
||||
private DockingAction editAction;
|
||||
private DockingAction eclipseAction;
|
||||
private DockingAction deleteAction;
|
||||
private DockingAction renameAction;
|
||||
private DockingAction keyBindingAction;
|
||||
private DockingAction helpAction;
|
||||
@ -174,15 +172,12 @@ class GhidraScriptActionManager {
|
||||
globalRunLastAction.firePropertyChanged(DockingActionIf.DESCRIPTION_PROPERTY, "", newDesc);
|
||||
}
|
||||
|
||||
private void createActions() {
|
||||
//
|
||||
// 'run' actions
|
||||
//
|
||||
String runGroup = "1";
|
||||
runAction = new DockingAction("Run", plugin.getName()) {
|
||||
private DockingAction createScriptAction(String name, String menuEntry,
|
||||
String actionDescription, Icon icon, String toolBarGroup, Runnable runnable) {
|
||||
DockingAction action = new DockingAction(name, plugin.getName()) {
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
provider.runScript();
|
||||
runnable.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -191,188 +186,79 @@ class GhidraScriptActionManager {
|
||||
return contextObject instanceof ResourceFile;
|
||||
}
|
||||
};
|
||||
runAction.setPopupMenuData(new MenuData(new String[] { "Run" },
|
||||
ResourceManager.loadImage("images/play.png"), null));
|
||||
runAction.setToolBarData(
|
||||
new ToolBarData(ResourceManager.loadImage("images/play.png"), runGroup));
|
||||
action.setPopupMenuData(new MenuData(new String[] { menuEntry }, icon));
|
||||
action.setToolBarData(new ToolBarData(icon, toolBarGroup));
|
||||
|
||||
runAction.setDescription("Run Script");
|
||||
runAction.setEnabled(false);
|
||||
plugin.getTool().addLocalAction(provider, runAction);
|
||||
action.setDescription(actionDescription);
|
||||
action.setEnabled(false);
|
||||
|
||||
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);
|
||||
|
||||
globalRunLastAction = new RerunLastScriptAction("Xtra");
|
||||
plugin.getTool().addAction(globalRunLastAction);
|
||||
|
||||
//
|
||||
// End 'run' actions
|
||||
//
|
||||
createScriptAction("Edit", "Edit with basic editor", "Edit Script with basic editor",
|
||||
ResourceManager.loadImage("images/accessories-text-editor.png"), null,
|
||||
provider::editScriptBuiltin);
|
||||
|
||||
editAction = new DockingAction("Edit", plugin.getName()) {
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
provider.editScriptBuiltin();
|
||||
}
|
||||
createScriptAction("EditEclipse", "Edit with Eclipse", "Edit Script with Eclipse",
|
||||
ResourceManager.loadImage("images/eclipse.png"), null, provider::editScriptEclipse);
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
Object contextObject = context.getContextObject();
|
||||
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);
|
||||
keyBindingAction =
|
||||
createScriptAction("Key Binding", "Assign Key Binding", "Assign Key Binding",
|
||||
ResourceManager.loadImage("images/key.png"), null, provider::assignKeyBinding);
|
||||
|
||||
eclipseAction = new DockingAction("EditEclipse", plugin.getName()) {
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
provider.editScriptEclipse();
|
||||
}
|
||||
createScriptAction("Delete", "Delete", "Delete Script",
|
||||
ResourceManager.loadImage("images/edit-delete.png"), null, provider::deleteScript);
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
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);
|
||||
renameAction = createScriptAction("Rename", "Rename", "Rename Script",
|
||||
ResourceManager.loadImage("images/textfield_rename.png"), null, provider::renameScript);
|
||||
|
||||
keyBindingAction = new DockingAction("Key Binding", plugin.getName()) {
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
provider.assignKeyBinding();
|
||||
}
|
||||
newAction = createScriptTableAction("New", "Create New Script",
|
||||
ResourceManager.loadImage("images/script_add.png"), provider::newScript);
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
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));
|
||||
createScriptTableAction("Refresh", "Refresh Script List",
|
||||
Icons.REFRESH_ICON, provider::refresh);
|
||||
|
||||
keyBindingAction.setDescription("Assign Key Binding");
|
||||
keyBindingAction.setEnabled(false);
|
||||
plugin.getTool().addLocalAction(provider, keyBindingAction);
|
||||
|
||||
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);
|
||||
showBundleStatusAction = createScriptTableAction("Script Directories",
|
||||
"Manage Script Directories", ResourceManager.loadImage("images/text_list_bullets.png"),
|
||||
provider::showBundleStatusComponent);
|
||||
|
||||
helpAction = new DockingAction("Ghidra API Help", plugin.getName()) {
|
||||
@Override
|
||||
@ -441,7 +327,7 @@ class GhidraScriptActionManager {
|
||||
}
|
||||
|
||||
HelpLocation getPathHelpLocation() {
|
||||
return new HelpLocation(plugin.getName(), bundleStatusAction.getName());
|
||||
return new HelpLocation(plugin.getName(), showBundleStatusAction.getName());
|
||||
}
|
||||
|
||||
HelpLocation getKeyBindingHelpLocation() {
|
||||
|
@ -20,6 +20,7 @@ import java.awt.Rectangle;
|
||||
import java.awt.event.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.swing.*;
|
||||
@ -57,13 +58,12 @@ import util.CollectionUtils;
|
||||
import utilities.util.FileUtilities;
|
||||
|
||||
public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
|
||||
static final String WINDOW_GROUP = "Script Group";
|
||||
|
||||
private static final double TOP_PREFERRED_RESIZE_WEIGHT = .80;
|
||||
private static final String DESCRIPTION_DIVIDER_LOCATION = "DESCRIPTION_DIVIDER_LOCATION";
|
||||
private static final String FILTER_TEXT = "FILTER_TEXT";
|
||||
|
||||
static final String WINDOW_GROUP = "Script Group";
|
||||
|
||||
private Map<ResourceFile, GhidraScriptEditorComponentProvider> editorMap = new HashMap<>();
|
||||
private final GhidraScriptMgrPlugin plugin;
|
||||
private JPanel component;
|
||||
@ -126,7 +126,7 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
|
||||
updateTitle();
|
||||
}
|
||||
|
||||
private void build() {
|
||||
private void buildCategoryTree() {
|
||||
scriptRoot = new RootNode();
|
||||
|
||||
scriptCategoryTree = new GTree(scriptRoot);
|
||||
@ -159,6 +159,10 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
|
||||
|
||||
scriptCategoryTree.getSelectionModel()
|
||||
.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
|
||||
}
|
||||
|
||||
private void build() {
|
||||
buildCategoryTree();
|
||||
|
||||
tableModel = new GhidraScriptTableModel(this, infoManager);
|
||||
|
||||
@ -231,10 +235,11 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
|
||||
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) {
|
||||
bundleHost.restoreManagedBundleState(saveState, getTool());
|
||||
|
||||
@ -259,6 +264,12 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
|
||||
tableFilterPanel.setFilterText(filterText);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save state for bundles, user actions, and filter.
|
||||
*
|
||||
* @param saveState the state object
|
||||
*/
|
||||
|
||||
public void writeConfigState(SaveState saveState) {
|
||||
bundleHost.saveManagedBundleState(saveState);
|
||||
|
||||
@ -283,6 +294,9 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
|
||||
bundleStatusComponentProvider.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the bundle host used for scripting, ultimately from {@link GhidraScriptUtil#getBundleHost()}
|
||||
*/
|
||||
public BundleHost getBundleHost() {
|
||||
return bundleHost;
|
||||
}
|
||||
@ -299,10 +313,6 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
|
||||
return editorMap;
|
||||
}
|
||||
|
||||
void showBundleStatusComponent() {
|
||||
bundleStatusComponentProvider.setVisible(true);
|
||||
}
|
||||
|
||||
void assignKeyBinding() {
|
||||
ResourceFile script = getSelectedScript();
|
||||
ScriptAction action = actionManager.createAction(script);
|
||||
@ -360,82 +370,72 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
|
||||
renameScriptByCopying(script, provider, renameFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy a script, renaming references to the class name.
|
||||
*
|
||||
* @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 parentFile = sourceScript.getParentFile();
|
||||
ResourceFile temp = new ResourceFile(parentFile, "ghidraScript.tmp");
|
||||
try (PrintWriter writer = new PrintWriter(temp.getOutputStream())) {
|
||||
try (BufferedReader reader =
|
||||
new BufferedReader(new InputStreamReader(sourceScript.getInputStream()))) {
|
||||
while (true) {
|
||||
String line = reader.readLine();
|
||||
if (line == null) {
|
||||
break;
|
||||
}
|
||||
writer.println(line.replaceAll(oldClassName, newClassName));
|
||||
}
|
||||
}
|
||||
}
|
||||
FileUtilities.copyFile(temp, destinationScript, TaskMonitor.DUMMY);
|
||||
temp.delete();
|
||||
}
|
||||
|
||||
private void renameScriptByCopying(ResourceFile script, GhidraScriptProvider provider,
|
||||
ResourceFile renameFile) {
|
||||
String oldClassName = GhidraScriptUtil.getBaseName(script);
|
||||
String newClassName = GhidraScriptUtil.getBaseName(renameFile);
|
||||
|
||||
ResourceFile temp = null;
|
||||
PrintWriter writer = null;
|
||||
BufferedReader reader = null;
|
||||
try {
|
||||
|
||||
ResourceFile parentFile = script.getParentFile();
|
||||
temp = new ResourceFile(parentFile, "ghidraScript.tmp");
|
||||
writer = new PrintWriter(temp.getOutputStream());
|
||||
reader = new BufferedReader(new InputStreamReader(script.getInputStream()));
|
||||
while (true) {
|
||||
String line = reader.readLine();
|
||||
if (line == null) {
|
||||
break;
|
||||
}
|
||||
writer.println(line.replaceAll(oldClassName, newClassName));
|
||||
}
|
||||
reader.close();
|
||||
writer.close();
|
||||
|
||||
FileUtilities.copyFile(temp, renameFile, TaskMonitor.DUMMY);
|
||||
|
||||
if (!renameFile.exists()) {
|
||||
Msg.showWarn(getClass(), getComponent(), "Unable to rename script",
|
||||
"The rename operation failed.\nPlease check file permissions.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!provider.deleteScript(script)) {
|
||||
Msg.showWarn(getClass(), getComponent(), "Unable to rename script",
|
||||
"Unable to remove original file.\nPlease check file permissions.");
|
||||
renameFile.delete();
|
||||
return;
|
||||
}
|
||||
infoManager.removeMetadata(script);
|
||||
|
||||
if (actionManager.hasScriptAction(script)) {
|
||||
KeyStroke ks = actionManager.getKeyBinding(script);
|
||||
actionManager.removeAction(script);
|
||||
ScriptAction action = actionManager.createAction(renameFile);
|
||||
action.setKeyBindingData(new KeyBindingData(ks));
|
||||
}
|
||||
|
||||
assert !infoManager
|
||||
.containsMetadata(renameFile) : "renamed script already has metadata";
|
||||
infoManager.getScriptInfo(renameFile);
|
||||
|
||||
tableModel.switchScript(script, renameFile);
|
||||
setSelectedScript(renameFile);
|
||||
copyScript(script, 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();
|
||||
}
|
||||
if (!renameFile.exists()) {
|
||||
Msg.showWarn(getClass(), getComponent(), "Unable to rename script",
|
||||
"The rename operation failed.\nPlease check file permissions.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!provider.deleteScript(script)) {
|
||||
Msg.showWarn(getClass(), getComponent(), "Unable to rename script",
|
||||
"Unable to remove original file.\nPlease check file permissions.");
|
||||
renameFile.delete();
|
||||
return;
|
||||
}
|
||||
infoManager.removeMetadata(script);
|
||||
|
||||
if (actionManager.hasScriptAction(script)) {
|
||||
KeyStroke ks = actionManager.getKeyBinding(script);
|
||||
actionManager.removeAction(script);
|
||||
ScriptAction action = actionManager.createAction(renameFile);
|
||||
action.setKeyBindingData(new KeyBindingData(ks));
|
||||
}
|
||||
|
||||
assert !infoManager.containsMetadata(renameFile) : "renamed script already has metadata";
|
||||
infoManager.getScriptInfo(renameFile);
|
||||
|
||||
tableModel.switchScript(script, renameFile);
|
||||
setSelectedScript(renameFile);
|
||||
}
|
||||
|
||||
JTable getTable() {
|
||||
@ -450,19 +450,27 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
|
||||
return tableModel.getScriptAt(tableFilterPanel.getModelRow(viewRowIndex));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return enabled bundle paths from the scripting bundle host
|
||||
*/
|
||||
public List<ResourceFile> getScriptDirectories() {
|
||||
return bundleHost.getGhidraBundles()
|
||||
.stream()
|
||||
.filter(bundle -> bundle.isEnabled() && bundle instanceof GhidraSourceBundle)
|
||||
.filter(GhidraSourceBundle.class::isInstance)
|
||||
.filter(GhidraBundle::isEnabled)
|
||||
.map(GhidraBundle::getPath)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-system bundle paths from the scripting bundle host
|
||||
*/
|
||||
public List<ResourceFile> getWritableScriptDirectories() {
|
||||
return bundleHost.getGhidraBundles()
|
||||
.stream()
|
||||
.filter(GhidraSourceBundle.class::isInstance)
|
||||
.filter(bundle -> !bundle.isSystemBundle())
|
||||
.filter(Predicate.not(GhidraBundle::isSystemBundle))
|
||||
.filter(GhidraBundle::isEnabled)
|
||||
.map(GhidraBundle::getPath)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
@ -496,7 +504,7 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
|
||||
}
|
||||
else {
|
||||
Msg.showInfo(getClass(), getComponent(), getName(),
|
||||
"Unable to delete script '" + script.getName() + "'" + "\n" +
|
||||
"Unable to delete script '" + script.getName() + "'\n" +
|
||||
"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);
|
||||
Msg.showInfo(this, getComponent(), "Script Path Added/Enabled",
|
||||
"The directory has been automatically enabled for use:\n" +
|
||||
@ -699,6 +707,10 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
|
||||
return categoryPath;
|
||||
}
|
||||
|
||||
void showBundleStatusComponent() {
|
||||
bundleStatusComponentProvider.setVisible(true);
|
||||
}
|
||||
|
||||
class RefreshingBundleHostListener implements BundleHostListener {
|
||||
|
||||
@Override
|
||||
|
@ -41,9 +41,8 @@ import resources.Icons;
|
||||
import resources.ResourceManager;
|
||||
|
||||
public class GhidraScriptEditorComponentProvider extends ComponentProvider {
|
||||
|
||||
private static final int MAX_UNDO_REDO_SIZE = 50;
|
||||
|
||||
static final String EDITOR_COMPONENT_NAME="EDITOR";
|
||||
|
||||
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_MISSING_TITLE = "File on Disk is Missing";
|
||||
@ -53,7 +52,9 @@ public class GhidraScriptEditorComponentProvider extends ComponentProvider {
|
||||
static final String KEEP_CHANGES_TEXT = "Keep 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) {
|
||||
String name = saveState.getString("DEFAULT_FONT_NAME", "Monospaced");
|
||||
@ -68,6 +69,7 @@ public class GhidraScriptEditorComponentProvider extends ComponentProvider {
|
||||
saveState.putInt("DEFAULT_FONT_SIZE", defaultFont.getSize());
|
||||
}
|
||||
|
||||
|
||||
private GhidraScriptMgrPlugin plugin;
|
||||
private GhidraScriptComponentProvider provider;
|
||||
private String title;
|
||||
@ -675,7 +677,7 @@ public class GhidraScriptEditorComponentProvider extends ComponentProvider {
|
||||
super(text);
|
||||
|
||||
setFont(defaultFont);
|
||||
setName("EDITOR");
|
||||
setName(EDITOR_COMPONENT_NAME);
|
||||
setWrapStyleWord(false);
|
||||
Document document = getDocument();
|
||||
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.EclipseIntegrationOptionsPlugin;
|
||||
import ghidra.app.plugin.core.osgi.BundleHost;
|
||||
import ghidra.app.script.GhidraScriptUtil;
|
||||
import ghidra.app.script.GhidraState;
|
||||
import ghidra.app.script.*;
|
||||
import ghidra.app.services.*;
|
||||
import ghidra.framework.options.SaveState;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
@ -49,12 +48,17 @@ import ghidra.util.task.TaskListener;
|
||||
)
|
||||
//@formatter:on
|
||||
public class GhidraScriptMgrPlugin extends ProgramPlugin implements GhidraScriptService {
|
||||
private static int loaded = 0;
|
||||
|
||||
private final GhidraScriptComponentProvider provider;
|
||||
|
||||
private static int loaded = 0;
|
||||
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) {
|
||||
super(tool, true, true, true);
|
||||
if (loaded == 0) {
|
||||
@ -111,6 +115,11 @@ public class GhidraScriptMgrPlugin extends ProgramPlugin implements GhidraScript
|
||||
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) {
|
||||
provider.runScript(scriptFile);
|
||||
}
|
||||
|
@ -35,13 +35,12 @@ import ghidra.util.table.column.GColumnRenderer;
|
||||
import resources.Icons;
|
||||
|
||||
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 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 List<ResourceFile> scriptList = new ArrayList<>();
|
||||
private final GhidraScriptInfoManager infoManager;
|
||||
@ -276,7 +275,7 @@ class GhidraScriptTableModel extends GDynamicColumnTableModel<ResourceFile, Obje
|
||||
|
||||
@Override
|
||||
public String getColumnName() {
|
||||
return "Status";
|
||||
return SCRIPT_STATUS_COLUMN_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -17,5 +16,5 @@
|
||||
package ghidra.app.plugin.core.script;
|
||||
|
||||
public interface Ingredient {
|
||||
public IngredientDescription [] getIngredientDescriptions();
|
||||
IngredientDescription [] getIngredientDescriptions();
|
||||
}
|
||||
|
@ -30,13 +30,13 @@ import ghidra.app.script.GhidraScriptUtil;
|
||||
import ghidra.util.HelpLocation;
|
||||
|
||||
public class PickProviderDialog extends DialogComponentProvider {
|
||||
private static String lastSelectedProviderDescription;
|
||||
|
||||
private List<GhidraScriptProvider> providers;
|
||||
private ListPanel listPanel;
|
||||
private JComponent parent;
|
||||
private boolean wasCancelled;
|
||||
|
||||
private static String lastSelectedProviderDescription;
|
||||
|
||||
PickProviderDialog(JComponent parent, HelpLocation help) {
|
||||
super("New Script: Type");
|
||||
this.parent = parent;
|
||||
@ -55,6 +55,12 @@ public class PickProviderDialog extends DialogComponentProvider {
|
||||
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) {
|
||||
super("New Script: Type");
|
||||
|
||||
@ -76,6 +82,8 @@ public class PickProviderDialog extends DialogComponentProvider {
|
||||
|
||||
/**
|
||||
* For testing...
|
||||
*
|
||||
* @param provider the provider selection
|
||||
*/
|
||||
void setSelectedProvider(GhidraScriptProvider provider) {
|
||||
listPanel.setSelectedValue(provider);
|
||||
@ -95,6 +103,9 @@ public class PickProviderDialog extends DialogComponentProvider {
|
||||
return (GhidraScriptProvider) listPanel.getSelectedValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* close any open dialog
|
||||
*/
|
||||
public void dispose() {
|
||||
close();
|
||||
}
|
||||
|
@ -37,6 +37,8 @@ import ghidra.util.HelpLocation;
|
||||
|
||||
public class SaveDialog extends DialogComponentProvider implements ListSelectionListener {
|
||||
protected GhidraScriptComponentProvider componentProvider;
|
||||
protected ResourceFile scriptFile;
|
||||
|
||||
private GhidraScriptProvider provider;
|
||||
|
||||
private List<ResourceFile> paths;
|
||||
@ -44,15 +46,22 @@ public class SaveDialog extends DialogComponentProvider implements ListSelection
|
||||
private JTextField nameField;
|
||||
private boolean cancelled;
|
||||
|
||||
protected ResourceFile scriptFile;
|
||||
|
||||
public SaveDialog(Component parent, String title,
|
||||
GhidraScriptComponentProvider componentProvider, ResourceFile scriptFile,
|
||||
HelpLocation help) {
|
||||
SaveDialog(Component parent, String title, GhidraScriptComponentProvider componentProvider,
|
||||
ResourceFile scriptFile, HelpLocation help) {
|
||||
this(parent, title, componentProvider, componentProvider.getWritableScriptDirectories(),
|
||||
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,
|
||||
GhidraScriptComponentProvider componentProvider, List<ResourceFile> scriptDirs,
|
||||
ResourceFile scriptFile, HelpLocation help) {
|
||||
|
@ -27,7 +27,7 @@ public class ScriptCategoryNode extends GTreeNode {
|
||||
|
||||
private final String name;
|
||||
|
||||
public ScriptCategoryNode(String name) {
|
||||
ScriptCategoryNode(String name) {
|
||||
this.name = name;
|
||||
|
||||
}
|
||||
|
@ -129,6 +129,9 @@ import ghidra.util.task.TaskMonitor;
|
||||
* @see ghidra.program.model.listing.Program
|
||||
*/
|
||||
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 GhidraState state;
|
||||
@ -174,16 +177,19 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||
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.
|
||||
* @throws Exception if any exception occurs.
|
||||
*/
|
||||
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) {
|
||||
this.state = state;
|
||||
this.monitor = monitor;
|
||||
@ -191,6 +197,14 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||
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)
|
||||
throws Exception {
|
||||
boolean success = false;
|
||||
@ -203,8 +217,8 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||
}
|
||||
}
|
||||
|
||||
private final void doExecute(GhidraState runState, TaskMonitor runMonitor,
|
||||
PrintWriter runWriter) throws Exception {
|
||||
private void doExecute(GhidraState runState, TaskMonitor runMonitor, PrintWriter runWriter)
|
||||
throws Exception {
|
||||
this.state = runState;
|
||||
this.monitor = runMonitor;
|
||||
this.writer = runWriter;
|
||||
@ -478,6 +492,11 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the script {@link #currentAddress}, {@link #currentLocation}, and update state object.
|
||||
*
|
||||
* @param address the new address
|
||||
*/
|
||||
public final void setCurrentLocation(Address address) {
|
||||
state.setCurrentAddress(address);
|
||||
this.currentAddress = address;
|
||||
@ -545,8 +564,8 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||
if (isRunningHeadless()) {
|
||||
// only change client authenticator in headless mode
|
||||
try {
|
||||
HeadlessClientAuthenticator.installHeadlessClientAuthenticator(
|
||||
ClientUtil.getUserName(), null, false);
|
||||
HeadlessClientAuthenticator
|
||||
.installHeadlessClientAuthenticator(ClientUtil.getUserName(), null, false);
|
||||
}
|
||||
catch (IOException 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
|
||||
String tempBool = analysisOptionValue.toLowerCase();
|
||||
|
||||
if (tempBool.equals("true") || tempBool.equals("false")) {
|
||||
if ("true".equals(tempBool) || "false".equals(tempBool)) {
|
||||
options.setBoolean(analysisOption, Boolean.valueOf(tempBool));
|
||||
}
|
||||
|
||||
@ -1785,13 +1804,13 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||
}
|
||||
else {
|
||||
try {
|
||||
SwingUtilities.invokeAndWait(
|
||||
() -> Msg.showInfo(getClass(), null, name, message));
|
||||
SwingUtilities
|
||||
.invokeAndWait(() -> Msg.showInfo(getClass(), null, name, message));
|
||||
}
|
||||
catch (InterruptedException e1) {
|
||||
catch (InterruptedException e) {
|
||||
// shouldn't happen
|
||||
}
|
||||
catch (InvocationTargetException e1) {
|
||||
catch (InvocationTargetException e) {
|
||||
// shouldn't happen
|
||||
}
|
||||
}
|
||||
@ -1970,7 +1989,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
public double parseDouble(String val) {
|
||||
if (val.equalsIgnoreCase("pi")) {
|
||||
if ("pi".equalsIgnoreCase(val)) {
|
||||
return Math.PI;
|
||||
}
|
||||
if (val.equalsIgnoreCase("e")) {
|
||||
if ("e".equalsIgnoreCase(val)) {
|
||||
return Math.E;
|
||||
}
|
||||
try {
|
||||
@ -3254,7 +3273,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||
* @throws IllegalArgumentException if the parsed value is not a valid boolean.
|
||||
*/
|
||||
public Boolean parseBoolean(String val) {
|
||||
if (val.equalsIgnoreCase("true") || val.equalsIgnoreCase("false")) {
|
||||
if ("true".equalsIgnoreCase(val) || "false".equalsIgnoreCase(val)) {
|
||||
return Boolean.parseBoolean(val);
|
||||
}
|
||||
throw new IllegalArgumentException("Invalid boolean: " + val);
|
||||
|
@ -28,6 +28,9 @@ public class GhidraScriptInfoManager {
|
||||
private Map<ResourceFile, ScriptInfo> scriptFileToInfoMap = new HashMap<>();
|
||||
private Map<String, List<ResourceFile>> scriptNameToFilesMap = new HashMap<>();
|
||||
|
||||
/**
|
||||
* clear stored metadata
|
||||
*/
|
||||
public void dispose() {
|
||||
clearMetadata();
|
||||
}
|
||||
@ -110,6 +113,12 @@ public class GhidraScriptInfoManager {
|
||||
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) {
|
||||
ScriptInfo info = scriptFileToInfoMap.get(script);
|
||||
if (info == null) {
|
||||
|
@ -33,7 +33,7 @@ public class GhidraScriptProperties {
|
||||
private HashMap<String, String> propertiesMap;
|
||||
private String baseName;
|
||||
|
||||
public GhidraScriptProperties() {
|
||||
GhidraScriptProperties() {
|
||||
propertiesMap = new HashMap<>();
|
||||
}
|
||||
|
||||
@ -73,6 +73,9 @@ public class GhidraScriptProperties {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the properties file name
|
||||
*/
|
||||
public String getFilename() {
|
||||
return baseName + ".properties";
|
||||
}
|
||||
@ -138,6 +141,10 @@ public class GhidraScriptProperties {
|
||||
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) {
|
||||
|
||||
if (propertiesMap.size() == 0) {
|
||||
@ -151,10 +158,19 @@ public class GhidraScriptProperties {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if there are no properties
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return (propertiesMap.size() == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the named property
|
||||
*
|
||||
* @param keyString the property name
|
||||
* @return the previous value or null
|
||||
*/
|
||||
protected String remove(String keyString) {
|
||||
return propertiesMap.remove(keyString);
|
||||
}
|
||||
@ -163,14 +179,25 @@ public class GhidraScriptProperties {
|
||||
propertiesMap.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param keyString a property name
|
||||
* @return true if the key exists in the property file
|
||||
*/
|
||||
public boolean containsKey(String keyString) {
|
||||
return propertiesMap.containsKey(keyString);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param valueString a value string
|
||||
* @return true if any property has the given value
|
||||
*/
|
||||
public boolean containsValue(String valueString) {
|
||||
return propertiesMap.containsValue(valueString);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the property names for all properties
|
||||
*/
|
||||
public Set<String> keySet() {
|
||||
return propertiesMap.keySet();
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (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 {
|
||||
|
||||
private ResourceFile classFile;
|
||||
private final ResourceFile classFile;
|
||||
|
||||
GhidraScriptUnsupportedClassVersionError(UnsupportedClassVersionError cause,
|
||||
ResourceFile classFile) {
|
||||
|
@ -15,7 +15,8 @@
|
||||
*/
|
||||
package ghidra.app.script;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
@ -31,31 +32,38 @@ import ghidra.util.classfinder.ClassSearcher;
|
||||
* A utility class for managing script directories and ScriptInfo objects.
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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() {
|
||||
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!");
|
||||
}
|
||||
|
||||
try {
|
||||
_bundleHost = bundleHost;
|
||||
_bundleHost.startFramework();
|
||||
bundleHost = aBundleHost;
|
||||
bundleHost.startFramework();
|
||||
}
|
||||
catch (OSGiException | IOException e) {
|
||||
e.printStackTrace();
|
||||
@ -66,26 +74,29 @@ public class GhidraScriptUtil {
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
public static void initialize(BundleHost bundleHost, List<String> extraSystemPaths) {
|
||||
setBundleHost(bundleHost);
|
||||
public static void initialize(BundleHost aBundleHost, List<String> extraSystemPaths) {
|
||||
setBundleHost(aBundleHost);
|
||||
if (extraSystemPaths != null) {
|
||||
for (String path : extraSystemPaths) {
|
||||
bundleHost.add(new ResourceFile(path), true, true);
|
||||
}
|
||||
}
|
||||
|
||||
bundleHost.add(GhidraScriptUtil.getUserScriptDirectory(), true, false);
|
||||
bundleHost.add(GhidraScriptUtil.getSystemScriptPaths(), true, true);
|
||||
bundleHost.add(getUserScriptDirectory(), true, false);
|
||||
bundleHost.add(getSystemScriptPaths(), true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* dispose of the bundle host and providers list
|
||||
*/
|
||||
public static void dispose() {
|
||||
if (_bundleHost != null) {
|
||||
_bundleHost.dispose();
|
||||
_bundleHost = null;
|
||||
if (bundleHost != null) {
|
||||
bundleHost.dispose();
|
||||
bundleHost = null;
|
||||
}
|
||||
providers = null;
|
||||
}
|
||||
@ -95,8 +106,10 @@ public class GhidraScriptUtil {
|
||||
* @return a list of the current script directories
|
||||
*/
|
||||
public static List<ResourceFile> getScriptSourceDirectories() {
|
||||
return _bundleHost.getBundlePaths().stream().filter(ResourceFile::isDirectory).collect(
|
||||
Collectors.toList());
|
||||
return bundleHost.getBundlePaths()
|
||||
.stream()
|
||||
.filter(ResourceFile::isDirectory)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static ResourceFile getSourceDirectoryContaining(ResourceFile sourceFile) {
|
||||
@ -199,8 +212,10 @@ public class GhidraScriptUtil {
|
||||
@Deprecated
|
||||
public static List<ResourceFile> getExplodedCompiledSourceBundlePaths() {
|
||||
try {
|
||||
return Files.list(BundleHost.getOsgiDir()).filter(Files::isDirectory).map(
|
||||
x -> new ResourceFile(x.toFile())).collect(Collectors.toList());
|
||||
return Files.list(BundleHost.getOsgiDir())
|
||||
.filter(Files::isDirectory)
|
||||
.map(x -> new ResourceFile(x.toFile()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
catch (IOException e) {
|
||||
Msg.showError(GhidraScriptUtil.class, null, "error",
|
||||
@ -231,7 +246,7 @@ public class GhidraScriptUtil {
|
||||
* @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
|
||||
public synchronized static List<GhidraScriptProvider> getProviders() {
|
||||
public static synchronized List<GhidraScriptProvider> getProviders() {
|
||||
if (providers == null) {
|
||||
List<GhidraScriptProvider> newProviders =
|
||||
new ArrayList<>(ClassSearcher.getInstances(GhidraScriptProvider.class));
|
||||
@ -338,8 +353,7 @@ public class GhidraScriptUtil {
|
||||
return path + ".java";
|
||||
}
|
||||
|
||||
static ResourceFile findScriptFileInPaths(
|
||||
Collection<ResourceFile> scriptDirectories,
|
||||
static ResourceFile findScriptFileInPaths(Collection<ResourceFile> scriptDirectories,
|
||||
String filename) {
|
||||
|
||||
String validatedName = fixupName(filename);
|
||||
|
@ -41,7 +41,7 @@ public class GhidraState {
|
||||
private ProgramSelection currentSelection;
|
||||
private ProgramSelection currentHighlight;
|
||||
private HashMap<String, Object> envmap = new HashMap<>();
|
||||
private GatherParamPanel gatherParamPanel = null;
|
||||
private GatherParamPanel gatherParamPanel;
|
||||
private Project project;
|
||||
private final boolean isGlobalState;
|
||||
|
||||
@ -105,6 +105,7 @@ public class GhidraState {
|
||||
|
||||
/**
|
||||
* Sets the current program.
|
||||
* @param program the new program object
|
||||
*/
|
||||
public void setCurrentProgram(Program program) {
|
||||
if (program == currentProgram) {
|
||||
@ -117,11 +118,19 @@ public class GhidraState {
|
||||
gatherParamPanel.currentProgramChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the address of the current location
|
||||
*/
|
||||
public Address getCurrentAddress() {
|
||||
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) {
|
||||
if (SystemUtilities.isEqual(address, getCurrentAddress())) {
|
||||
return;
|
||||
@ -129,10 +138,18 @@ public class GhidraState {
|
||||
setCurrentLocation(new ProgramLocation(currentProgram, address));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the current location
|
||||
*/
|
||||
public ProgramLocation getCurrentLocation() {
|
||||
return currentLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* If it differs, set the current location and fire a {@link ProgramLocationPluginEvent}.
|
||||
*
|
||||
* @param location
|
||||
*/
|
||||
public void setCurrentLocation(ProgramLocation location) {
|
||||
if (SystemUtilities.isEqual(currentLocation, location)) {
|
||||
return;
|
||||
@ -144,10 +161,18 @@ public class GhidraState {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the currently highlighted selection
|
||||
*/
|
||||
public ProgramSelection getCurrentHighlight() {
|
||||
return currentHighlight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the currently highlighted selection and fire a {@link ProgramHighlightPluginEvent}.
|
||||
*
|
||||
* @param highlight the selection
|
||||
*/
|
||||
public void setCurrentHighlight(ProgramSelection highlight) {
|
||||
if (SystemUtilities.isEqual(currentHighlight, highlight)) {
|
||||
return;
|
||||
@ -162,10 +187,18 @@ public class GhidraState {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the current selection
|
||||
*/
|
||||
public ProgramSelection getCurrentSelection() {
|
||||
return currentSelection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current selection and fire a {@link kProgramSelectionPluginEvent}.
|
||||
*
|
||||
* @param selection the selection
|
||||
*/
|
||||
public void setCurrentSelection(ProgramSelection selection) {
|
||||
if (SystemUtilities.isEqual(currentSelection, selection)) {
|
||||
return;
|
||||
@ -181,27 +214,27 @@ public class GhidraState {
|
||||
}
|
||||
|
||||
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) {
|
||||
envmap.put(name, new Short(value));
|
||||
envmap.put(name, Short.valueOf(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) {
|
||||
envmap.put(name, new Long(value));
|
||||
envmap.put(name, Long.valueOf(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) {
|
||||
envmap.put(name, new Double(value));
|
||||
envmap.put(name, Double.valueOf(value));
|
||||
}
|
||||
|
||||
public void addEnvironmentVar(String name, Object value) {
|
||||
|
@ -24,18 +24,27 @@ import ghidra.app.plugin.core.osgi.*;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
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() {
|
||||
_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) {
|
||||
ResourceFile sourceDir = GhidraScriptUtil.getSourceDirectoryContaining(sourceFile);
|
||||
if (sourceDir == null) {
|
||||
return null;
|
||||
}
|
||||
return (GhidraSourceBundle) _bundleHost.getExistingGhidraBundle(sourceDir);
|
||||
return (GhidraSourceBundle) bundleHost.getExistingGhidraBundle(sourceDir);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -53,7 +62,7 @@ public class JavaScriptProvider extends GhidraScriptProvider {
|
||||
try {
|
||||
Bundle osgiBundle = getBundleForSource(sourceFile).getOSGiBundle();
|
||||
if (osgiBundle != null) {
|
||||
_bundleHost.deactivateSynchronously(osgiBundle);
|
||||
bundleHost.deactivateSynchronously(osgiBundle);
|
||||
}
|
||||
}
|
||||
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 {
|
||||
GhidraSourceBundle gb = getBundleForSource(sourceFile);
|
||||
gb.build(writer);
|
||||
|
||||
Bundle b = _bundleHost.install(gb);
|
||||
|
||||
_bundleHost.activateSynchronously(b);
|
||||
Bundle b = bundleHost.install(gb);
|
||||
|
||||
bundleHost.activateSynchronously(b);
|
||||
|
||||
String classname = gb.classNameForScript(sourceFile);
|
||||
Class<?> clazz = b.loadClass(classname); // throws ClassNotFoundException
|
||||
|
@ -34,11 +34,18 @@ public class ResourceFileJavaFileManager implements JavaFileManager {
|
||||
|
||||
private StandardJavaFileManager fileManager;
|
||||
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.avoid = avoid;
|
||||
this.filesToAvoid = filesToAvoid;
|
||||
JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
|
||||
if (javaCompiler == null) {
|
||||
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,
|
||||
Set<Kind> kinds, boolean recurse) {
|
||||
List<ResourceFile> listFiles = new ArrayList<>(Arrays.asList(file.listFiles()));
|
||||
listFiles.removeAll(avoid);
|
||||
listFiles.removeAll(filesToAvoid);
|
||||
for (ResourceFile resourceFile : listFiles) {
|
||||
if (resourceFile.isDirectory()) {
|
||||
if (recurse) {
|
||||
@ -154,7 +161,7 @@ public class ResourceFileJavaFileManager implements JavaFileManager {
|
||||
@Override
|
||||
public JavaFileObject getJavaFileForInput(Location location, String className, Kind kind)
|
||||
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).
|
||||
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.NestingKind;
|
||||
import javax.tools.JavaCompiler;
|
||||
import javax.tools.JavaFileObject;
|
||||
|
||||
import generic.jar.ResourceFile;
|
||||
@ -35,6 +36,13 @@ public class ResourceFileJavaFileObject implements JavaFileObject {
|
||||
private String pathName;
|
||||
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) {
|
||||
this.file = file;
|
||||
this.kind = kind;
|
||||
@ -43,6 +51,9 @@ public class ResourceFileJavaFileObject implements JavaFileObject {
|
||||
pathName = file.getAbsolutePath().substring(sourceRootPath.length() + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link ResourceFile} this object represents
|
||||
*/
|
||||
public ResourceFile getFile() {
|
||||
return file;
|
||||
}
|
||||
|
@ -36,12 +36,8 @@ import resources.ResourceManager;
|
||||
* This class parses the meta-data about a script.
|
||||
*/
|
||||
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 = ".";
|
||||
|
||||
@ -51,6 +47,9 @@ public class ScriptInfo {
|
||||
static final String AT_MENUPATH = "@menupath";
|
||||
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
|
||||
private static final String AT_IMPORTPACKAGE = "@importpackage";
|
||||
|
||||
@ -231,7 +230,7 @@ public class ScriptInfo {
|
||||
description = buffer.toString();
|
||||
modified = sourceFile.lastModified();
|
||||
}
|
||||
catch (Exception e) {
|
||||
catch (IOException e) {
|
||||
Msg.debug(this, "Unexpected exception reading script: " + sourceFile, e);
|
||||
}
|
||||
finally {
|
||||
@ -403,6 +402,9 @@ public class ScriptInfo {
|
||||
return keyBinding;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an error resulting from parsing keybinding metadata
|
||||
*/
|
||||
public String getKeyBindingErrorMessage() {
|
||||
return keybindingErrorMessage;
|
||||
}
|
||||
@ -460,7 +462,6 @@ public class ScriptInfo {
|
||||
String space = HTML_SPACE;
|
||||
String htmlAuthor = bold("Author:") + space + escapeHTML(toString(author));
|
||||
String htmlCategory = bold("Category:") + space + escapeHTML(toString(category));
|
||||
|
||||
String htmlKeyBinding = bold("Key Binding:") + space + getKeybindingToolTip();
|
||||
String htmlMenuPath = bold("Menu Path:") + space + escapeHTML(toString(menupath));
|
||||
|
||||
@ -505,10 +506,16 @@ public class ScriptInfo {
|
||||
return StringUtils.defaultString(joined);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the script either has compiler errors, or is a duplicate
|
||||
*/
|
||||
public boolean hasErrors() {
|
||||
return isCompileErrors() || isDuplicate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a generic error message
|
||||
*/
|
||||
public String getErrorMessage() {
|
||||
if (isCompileErrors()) {
|
||||
return "Script contains compiler errors";
|
||||
|
@ -16,6 +16,5 @@
|
||||
package ghidra.app.script;
|
||||
|
||||
public interface StringTransformer<T> {
|
||||
|
||||
public T apply(String s);
|
||||
T apply(String s);
|
||||
}
|
||||
|
@ -174,11 +174,11 @@ public abstract class AbstractGhidraScriptMgrPluginTest
|
||||
env.dispose();
|
||||
}
|
||||
|
||||
static protected void wipe(ResourceFile path) throws IOException {
|
||||
protected static void wipe(ResourceFile path) throws IOException {
|
||||
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)) {
|
||||
for (Path p : (Iterable<Path>) Files.walk(path)
|
||||
.sorted(Comparator.reverseOrder())::iterator) {
|
||||
@ -392,7 +392,7 @@ public abstract class AbstractGhidraScriptMgrPluginTest
|
||||
|
||||
assertNotNull(editor);
|
||||
|
||||
editorTextArea = (JTextArea) findComponentByName(editor.getComponent(), "EDITOR");
|
||||
editorTextArea = (JTextArea) findComponentByName(editor.getComponent(), GhidraScriptEditorComponentProvider.EDITOR_COMPONENT_NAME);
|
||||
assertNotNull(editorTextArea);
|
||||
|
||||
buffer = new StringBuffer(editorTextArea.getText());
|
||||
@ -411,7 +411,7 @@ public abstract class AbstractGhidraScriptMgrPluginTest
|
||||
|
||||
// initialize our editor variable to the newly opened editor
|
||||
editor = waitForComponentProvider(GhidraScriptEditorComponentProvider.class);
|
||||
editorTextArea = (JTextArea) findComponentByName(editor.getComponent(), "EDITOR");
|
||||
editorTextArea = (JTextArea) findComponentByName(editor.getComponent(), GhidraScriptEditorComponentProvider.EDITOR_COMPONENT_NAME);
|
||||
|
||||
waitForSwing();
|
||||
|
||||
@ -850,7 +850,7 @@ public abstract class AbstractGhidraScriptMgrPluginTest
|
||||
Map<ResourceFile, GhidraScriptEditorComponentProvider> map = provider.getEditorMap();
|
||||
GhidraScriptEditorComponentProvider fileEditor = map.get(file);
|
||||
final JTextArea textArea =
|
||||
(JTextArea) findComponentByName(fileEditor.getComponent(), "EDITOR");
|
||||
(JTextArea) findComponentByName(fileEditor.getComponent(), GhidraScriptEditorComponentProvider.EDITOR_COMPONENT_NAME);
|
||||
assertNotNull(textArea);
|
||||
|
||||
final String[] box = new String[1];
|
||||
@ -1164,7 +1164,7 @@ public abstract class AbstractGhidraScriptMgrPluginTest
|
||||
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 {
|
||||
Window window = waitForWindowByTitleContaining(CANCELLABLE_SCRIPT_NAME);
|
||||
@ -1494,7 +1494,7 @@ public abstract class AbstractGhidraScriptMgrPluginTest
|
||||
|
||||
protected JTextComponent grabScriptEditorTextArea() {
|
||||
GhidraScriptEditorComponentProvider scriptEditor = grabScriptEditor();
|
||||
JTextArea textArea = (JTextArea) findComponentByName(scriptEditor.getComponent(), "EDITOR");
|
||||
JTextArea textArea = (JTextArea) findComponentByName(scriptEditor.getComponent(), GhidraScriptEditorComponentProvider.EDITOR_COMPONENT_NAME);
|
||||
assertNotNull(textArea);
|
||||
return textArea;
|
||||
}
|
||||
@ -1596,9 +1596,9 @@ public abstract class AbstractGhidraScriptMgrPluginTest
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (CancelledException ce) {
|
||||
catch (CancelledException e) {
|
||||
doneLatch.countDown();
|
||||
throw ce;
|
||||
throw e;
|
||||
}
|
||||
|
||||
doneLatch.countDown();
|
||||
|
@ -119,7 +119,7 @@ public class GhidraScriptMgrPluginScreenShots extends GhidraScreenShotGenerator
|
||||
BundleStatusComponentProvider bundleStatusComponentProvider =
|
||||
showProvider(BundleStatusComponentProvider.class);
|
||||
|
||||
bundleStatusComponentProvider.getModel().setPathsForTesting(paths);
|
||||
bundleStatusComponentProvider.setPathsForTesting(paths);
|
||||
|
||||
waitForComponentProvider(BundleStatusComponentProvider.class);
|
||||
captureComponent(bundleStatusComponentProvider.getComponent());
|
||||
|
Loading…
Reference in New Issue
Block a user