mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 10:49:34 +02:00
GP-1743 - Added a method to GhiraScript to allow script writers to
disable reusing previously chosen values in the various 'ask' methods.
This commit is contained in:
parent
7a5f0b4e16
commit
ea52da673e
2 changed files with 90 additions and 43 deletions
|
@ -94,8 +94,8 @@ import ghidra.util.task.TaskMonitor;
|
||||||
* </pre>
|
* </pre>
|
||||||
* <h3>Ghidra Script State</h3>
|
* <h3>Ghidra Script State</h3>
|
||||||
* <blockquote>
|
* <blockquote>
|
||||||
*
|
*
|
||||||
* <p>All scripts, when run, will be handed the current state in the form of class instance
|
* <p>All scripts, when run, will be handed the current state in the form of class instance
|
||||||
* variable. These variables are:
|
* variable. These variables are:
|
||||||
* <ol>
|
* <ol>
|
||||||
* <li><code>currentProgram</code>: the active program</li>
|
* <li><code>currentProgram</code>: the active program</li>
|
||||||
|
@ -140,6 +140,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
// Stores any parameters in a .properties file sharing the same base name as this GhidraScript
|
// Stores any parameters in a .properties file sharing the same base name as this GhidraScript
|
||||||
protected GhidraScriptProperties propertiesFileParams;
|
protected GhidraScriptProperties propertiesFileParams;
|
||||||
protected List<ResourceFile> potentialPropertiesFileLocs = new ArrayList<>();
|
protected List<ResourceFile> potentialPropertiesFileLocs = new ArrayList<>();
|
||||||
|
private boolean reusePreviousChoices = true;
|
||||||
private CodeUnitFormat cuFormat;
|
private CodeUnitFormat cuFormat;
|
||||||
|
|
||||||
// Stores any script-specific arguments
|
// Stores any script-specific arguments
|
||||||
|
@ -181,7 +182,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the context for this script.
|
* Set the context for this script.
|
||||||
*
|
*
|
||||||
* @param state state object
|
* @param state state object
|
||||||
* @param monitor the monitor to use during run
|
* @param monitor the monitor to use during run
|
||||||
* @param writer the target of script "print" statements
|
* @param writer the target of script "print" statements
|
||||||
|
@ -193,9 +194,28 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
loadVariablesFromState();
|
loadVariablesFromState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether the user's previously selected values should be used when showing the various
|
||||||
|
* {@code ask} methods. This is true by default, meaning that previous choices will be shown
|
||||||
|
* instead of any provided default value.
|
||||||
|
* @param reuse true to reuse values; false to not reuse previous values
|
||||||
|
*/
|
||||||
|
public void setReusePreviousChoices(boolean reuse) {
|
||||||
|
this.reusePreviousChoices = reuse;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether scripts will reuse previously selected values when showing the various
|
||||||
|
* {@code ask} methods.
|
||||||
|
* @return true to reuse values; false to not reuse previous values
|
||||||
|
*/
|
||||||
|
public boolean getReusePreviousChoices() {
|
||||||
|
return reusePreviousChoices;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute/run script and {@link #doCleanup} afterwards.
|
* Execute/run script and {@link #doCleanup} afterwards.
|
||||||
*
|
*
|
||||||
* @param runState state object
|
* @param runState state object
|
||||||
* @param runMonitor the monitor to use during run
|
* @param runMonitor the monitor to use during run
|
||||||
* @param runWriter the target of script "print" statements
|
* @param runWriter the target of script "print" statements
|
||||||
|
@ -490,7 +510,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the script {@link #currentAddress}, {@link #currentLocation}, and update state object.
|
* Set the script {@link #currentAddress}, {@link #currentLocation}, and update state object.
|
||||||
*
|
*
|
||||||
* @param address the new address
|
* @param address the new address
|
||||||
*/
|
*/
|
||||||
public final void setCurrentLocation(Address address) {
|
public final void setCurrentLocation(Address address) {
|
||||||
|
@ -1707,7 +1727,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
* action from a selection in the table.
|
* action from a selection in the table.
|
||||||
* <p>
|
* <p>
|
||||||
* This method is unavailable in headless mode.
|
* This method is unavailable in headless mode.
|
||||||
*
|
*
|
||||||
* @param title the title of the dialog
|
* @param title the title of the dialog
|
||||||
* @param executor the TableChooserExecuter to be used to apply operations on table entries.
|
* @param executor the TableChooserExecuter to be used to apply operations on table entries.
|
||||||
* @return a new TableChooserDialog.
|
* @return a new TableChooserDialog.
|
||||||
|
@ -1725,7 +1745,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
* action from a selection in the table.
|
* action from a selection in the table.
|
||||||
* <p>
|
* <p>
|
||||||
* This method is unavailable in headless mode.
|
* This method is unavailable in headless mode.
|
||||||
*
|
*
|
||||||
* @param title of the dialog
|
* @param title of the dialog
|
||||||
* @param executor the TableChooserExecuter to be used to apply operations on table entries.
|
* @param executor the TableChooserExecuter to be used to apply operations on table entries.
|
||||||
* @param isModal indicates whether the dialog should be modal or not
|
* @param isModal indicates whether the dialog should be modal or not
|
||||||
|
@ -1954,7 +1974,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
Map<Class<?>, Object> map = getScriptMap(key1, key2);
|
Map<Class<?>, Object> map = getScriptMap(key1, key2);
|
||||||
|
|
||||||
T mappedValue = null;
|
T mappedValue = null;
|
||||||
if (clazz != null) {
|
if (clazz != null && reusePreviousChoices) {
|
||||||
mappedValue = (T) map.get(clazz);
|
mappedValue = (T) map.get(clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2402,7 +2422,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
* .properties value (if it exists), or throws an Exception if there is an invalid or
|
* .properties value (if it exists), or throws an Exception if there is an invalid or
|
||||||
* missing .properties value.</li>
|
* missing .properties value.</li>
|
||||||
* </ol>
|
* </ol>
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @param title the title of the dialog (in GUI mode) or the first part of the variable name
|
* @param title the title of the dialog (in GUI mode) or the first part of the variable name
|
||||||
* (in headless mode or when using .properties file)
|
* (in headless mode or when using .properties file)
|
||||||
|
@ -2475,7 +2495,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
* .properties value (if it exists), or throws an Exception if there is an invalid or
|
* .properties value (if it exists), or throws an Exception if there is an invalid or
|
||||||
* missing .properties value.</li>
|
* missing .properties value.</li>
|
||||||
* </ol>
|
* </ol>
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @param title the title of the dialog (in GUI mode) or the first part of the variable name
|
* @param title the title of the dialog (in GUI mode) or the first part of the variable name
|
||||||
* (in headless mode or when using .properties file)
|
* (in headless mode or when using .properties file)
|
||||||
|
@ -2549,7 +2569,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
* .properties byte pattern value (if it exists), or throws an Exception if there is
|
* .properties byte pattern value (if it exists), or throws an Exception if there is
|
||||||
* an invalid or missing .properties value.</li>
|
* an invalid or missing .properties value.</li>
|
||||||
* </ol>
|
* </ol>
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @param title the title of the dialog (in GUI mode) or the first part of the variable
|
* @param title the title of the dialog (in GUI mode) or the first part of the variable
|
||||||
* name (in headless mode or when using .properties file)
|
* name (in headless mode or when using .properties file)
|
||||||
|
@ -2608,7 +2628,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
* then that value is returned. Otherwise, an Exception is thrown if there is an
|
* then that value is returned. Otherwise, an Exception is thrown if there is an
|
||||||
* invalid or missing .properties value.</li>
|
* invalid or missing .properties value.</li>
|
||||||
* </ol>
|
* </ol>
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @param title the title of the pop-up dialog (in GUI mode) or the variable name (in
|
* @param title the title of the pop-up dialog (in GUI mode) or the variable name (in
|
||||||
* headless mode)
|
* headless mode)
|
||||||
|
@ -2694,7 +2714,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
* then that value is returned. Otherwise, an Exception is thrown if there is an invalid
|
* then that value is returned. Otherwise, an Exception is thrown if there is an invalid
|
||||||
* or missing .properties value.</li>
|
* or missing .properties value.</li>
|
||||||
* </ol>
|
* </ol>
|
||||||
*
|
*
|
||||||
* @param title the title of the pop-up dialog (in GUI mode) or the variable name (in headless
|
* @param title the title of the pop-up dialog (in GUI mode) or the variable name (in headless
|
||||||
* mode or when using .properties file)
|
* mode or when using .properties file)
|
||||||
* @throws IllegalArgumentException if in headless mode, there was a missing or invalid domain
|
* @throws IllegalArgumentException if in headless mode, there was a missing or invalid domain
|
||||||
|
@ -2831,7 +2851,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
* .properties value (if it exists), or throws an Exception if there is an invalid or
|
* .properties value (if it exists), or throws an Exception if there is an invalid or
|
||||||
* missing .properties value.</li>
|
* missing .properties value.</li>
|
||||||
* </ol>
|
* </ol>
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @param title the title of the dialog (in GUI mode) or the first part of the variable name
|
* @param title the title of the dialog (in GUI mode) or the first part of the variable name
|
||||||
* (in headless mode or when using .properties file)
|
* (in headless mode or when using .properties file)
|
||||||
|
@ -2874,7 +2894,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
* not null or an empty String, it is returned. In all other cases, an exception
|
* not null or an empty String, it is returned. In all other cases, an exception
|
||||||
* is thrown.</li>
|
* is thrown.</li>
|
||||||
* </ol>
|
* </ol>
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @param title the title of the dialog (in GUI mode) or the first part of the variable name
|
* @param title the title of the dialog (in GUI mode) or the first part of the variable name
|
||||||
* (in headless mode or when using .properties file)
|
* (in headless mode or when using .properties file)
|
||||||
|
@ -2948,7 +2968,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
* .properties value (if it exists and is a valid choice), or throws an Exception if
|
* .properties value (if it exists and is a valid choice), or throws an Exception if
|
||||||
* there is an invalid or missing .properties value.</li>
|
* there is an invalid or missing .properties value.</li>
|
||||||
* </ol>
|
* </ol>
|
||||||
*
|
*
|
||||||
* @param title the title of the dialog (in GUI mode) or the first part of the variable name
|
* @param title the title of the dialog (in GUI mode) or the first part of the variable name
|
||||||
* (in headless mode or when using .properties file)
|
* (in headless mode or when using .properties file)
|
||||||
* @param message the message to display next to the input field (in GUI mode) or the second
|
* @param message the message to display next to the input field (in GUI mode) or the second
|
||||||
|
@ -3088,7 +3108,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
*
|
*
|
||||||
* @throws CancelledException if the user hits the 'cancel' button
|
* @throws CancelledException if the user hits the 'cancel' button
|
||||||
* @throws IllegalArgumentException if in headless mode, there was a missing or invalid set of
|
* @throws IllegalArgumentException if in headless mode, there was a missing or invalid set of
|
||||||
* choices specified in the .properties file
|
* choices specified in the .properties file
|
||||||
*/
|
*/
|
||||||
public <T> List<T> askChoices(String title, String message, List<T> choices)
|
public <T> List<T> askChoices(String title, String message, List<T> choices)
|
||||||
throws CancelledException {
|
throws CancelledException {
|
||||||
|
@ -3160,8 +3180,8 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
* @return the user-selected value(s); null if no selection was made
|
* @return the user-selected value(s); null if no selection was made
|
||||||
*
|
*
|
||||||
* @throws CancelledException if the user hits the 'cancel' button
|
* @throws CancelledException if the user hits the 'cancel' button
|
||||||
* @throws IllegalArgumentException if choices is empty; if in headless mode,
|
* @throws IllegalArgumentException if choices is empty; if in headless mode,
|
||||||
* there was a missing or invalid set of choices specified in the .properties file
|
* there was a missing or invalid set of choices specified in the .properties file
|
||||||
*/
|
*/
|
||||||
public <T> List<T> askChoices(String title, String message, List<T> choices,
|
public <T> List<T> askChoices(String title, String message, List<T> choices,
|
||||||
List<String> choiceLabels) throws CancelledException {
|
List<String> choiceLabels) throws CancelledException {
|
||||||
|
@ -3232,7 +3252,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
||||||
* then that value is returned. Otherwise, an Exception is thrown if there is an
|
* then that value is returned. Otherwise, an Exception is thrown if there is an
|
||||||
* invalid or missing .properties value.</li>
|
* invalid or missing .properties value.</li>
|
||||||
* </ol>
|
* </ol>
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @param title the title of the dialog (in GUI mode) or the first part of the variable name
|
* @param title the title of the dialog (in GUI mode) or the first part of the variable name
|
||||||
* (in headless mode)
|
* (in headless mode)
|
||||||
|
|
|
@ -123,7 +123,7 @@ public class GhidraScriptAskMethodsTest extends AbstractGhidraHeadedIntegrationT
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Calling askProgram() would stacktrace if the user 1) didn't select a program in the
|
* Calling askProgram() would stacktrace if the user 1) didn't select a program in the
|
||||||
* tree and then 2) pressed the OK button.
|
* tree and then 2) pressed the OK button.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
|
@ -151,17 +151,17 @@ public class GhidraScriptAskMethodsTest extends AbstractGhidraHeadedIntegrationT
|
||||||
runSwing(() -> dtd.close());
|
runSwing(() -> dtd.close());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For scripts with properties files in a different location (could be the case with subscripts),
|
* For scripts with properties files in a different location (could be the case with subscripts),
|
||||||
* tests that the .properties file is found in the default location and that the default value
|
* tests that the .properties file is found in the default location and that the default value
|
||||||
* for the input field is provided by the .properties file in the alternate location.
|
* for the input field is provided by the .properties file in the alternate location.
|
||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testAlternateLocationPropertiesFile() throws Exception {
|
public void testAlternateLocationPropertiesFile() throws Exception {
|
||||||
|
|
||||||
// Create a temporary .properties file and set the potentialPropertiesFileLocs to look
|
// Create a temporary .properties file and set the potentialPropertiesFileLocs to look
|
||||||
// in that location
|
// in that location
|
||||||
String tempDirPath = AbstractGTest.getTestDirectoryPath();
|
String tempDirPath = AbstractGTest.getTestDirectoryPath();
|
||||||
File tempDir = new File(tempDirPath);
|
File tempDir = new File(tempDirPath);
|
||||||
|
@ -481,7 +481,7 @@ public class GhidraScriptAskMethodsTest extends AbstractGhidraHeadedIntegrationT
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Test that askInt method auto-populates dialog with value in .properties file.
|
* Test that askInt method auto-populates dialog with value in .properties file.
|
||||||
*
|
*
|
||||||
* Also test that subsequent calls to the dialog show the last-used value.
|
* Also test that subsequent calls to the dialog show the last-used value.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
|
@ -622,13 +622,40 @@ public class GhidraScriptAskMethodsTest extends AbstractGhidraHeadedIntegrationT
|
||||||
|
|
||||||
createScript();
|
createScript();
|
||||||
|
|
||||||
final String defaultValue = "a default value";
|
String defaultValue = "a default value";
|
||||||
String myString = ask_TextInput(() -> {
|
String myString = ask_TextInput(() -> {
|
||||||
return script.askString("Default Test", "Enter a string here:", defaultValue);
|
return script.askString("Default Test", "Enter a string here:", defaultValue);
|
||||||
});
|
});
|
||||||
assertEquals(defaultValue, myString);
|
assertEquals(defaultValue, myString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAskStringDefaultValue_DoNotReusePreviousValues() throws Exception {
|
||||||
|
createScript();
|
||||||
|
|
||||||
|
String defaultValue = "a default value";
|
||||||
|
String myString = ask_TextInput(() -> {
|
||||||
|
return script.askString("Default Test", "Enter a string here:", defaultValue);
|
||||||
|
});
|
||||||
|
assertEquals(defaultValue, myString);
|
||||||
|
|
||||||
|
script.setReusePreviousChoices(false);
|
||||||
|
|
||||||
|
String secondDefaultValue = "a new default value";
|
||||||
|
String secondString = ask_TextInput(() -> {
|
||||||
|
return script.askString("Default Test", "Enter a string here:", secondDefaultValue);
|
||||||
|
});
|
||||||
|
assertEquals(secondDefaultValue, secondString);
|
||||||
|
|
||||||
|
script.setReusePreviousChoices(true);
|
||||||
|
|
||||||
|
String thirdDefaultValue = "a third default value";
|
||||||
|
String thirdString = ask_TextInput(() -> {
|
||||||
|
return script.askString("Default Test", "Enter a string here:", thirdDefaultValue);
|
||||||
|
});
|
||||||
|
assertEquals(secondString, thirdString);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAskChoice() throws Exception {
|
public void testAskChoice() throws Exception {
|
||||||
createScript();
|
createScript();
|
||||||
|
@ -673,37 +700,37 @@ public class GhidraScriptAskMethodsTest extends AbstractGhidraHeadedIntegrationT
|
||||||
assertEquals(choices.get(choiceIndex), chosen);
|
assertEquals(choices.get(choiceIndex), chosen);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO test for askChoices()
|
// TODO test for askChoices()
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* No test for either of the two versions of 'askChoices()" because it does not use either the
|
* No test for either of the two versions of 'askChoices()" because it does not use either the
|
||||||
* the last-selected value or a .properties file value to pre-populate the user choice in the
|
* the last-selected value or a .properties file value to pre-populate the user choice in the
|
||||||
* GUI.
|
* GUI.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* No test for 'askYesNo()" because it does not use either the the last-selected value or
|
* No test for 'askYesNo()" because it does not use either the the last-selected value or
|
||||||
* a .properties file value to pre-populate the user choice in the GUI.
|
* a .properties file value to pre-populate the user choice in the GUI.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* No test for 'askProjectFolder()" because it does not use either the the last-selected value
|
* No test for 'askProjectFolder()" because it does not use either the the last-selected value
|
||||||
* or a .properties file value to pre-populate the user choice in the GUI.
|
* or a .properties file value to pre-populate the user choice in the GUI.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* No test for 'askProgram()" because it does not use either the the last-selected value or
|
* No test for 'askProgram()" because it does not use either the the last-selected value or
|
||||||
* a .properties file value to pre-populate the user choice in the GUI.
|
* a .properties file value to pre-populate the user choice in the GUI.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* No test for 'askDomainFile()" because it does not use either the the last-selected value or
|
* No test for 'askDomainFile()" because it does not use either the the last-selected value or
|
||||||
* a .properties file value to pre-populate the user choice in the GUI.
|
* a .properties file value to pre-populate the user choice in the GUI.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
// Private Methods
|
// Private Methods
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
private <T> T ask_ComboInput(Callable<T> c) {
|
private <T> T ask_ComboInput(Callable<T> c) {
|
||||||
return ask_TextInput(null, c);
|
return ask_TextInput(null, c);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue