mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +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>
|
||||
* <h3>Ghidra Script State</h3>
|
||||
* <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:
|
||||
* <ol>
|
||||
* <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
|
||||
protected GhidraScriptProperties propertiesFileParams;
|
||||
protected List<ResourceFile> potentialPropertiesFileLocs = new ArrayList<>();
|
||||
private boolean reusePreviousChoices = true;
|
||||
private CodeUnitFormat cuFormat;
|
||||
|
||||
// Stores any script-specific arguments
|
||||
|
@ -181,7 +182,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
|||
|
||||
/**
|
||||
* 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
|
||||
|
@ -193,9 +194,28 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
|||
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.
|
||||
*
|
||||
*
|
||||
* @param runState state object
|
||||
* @param runMonitor the monitor to use during run
|
||||
* @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.
|
||||
*
|
||||
*
|
||||
* @param address the new address
|
||||
*/
|
||||
public final void setCurrentLocation(Address address) {
|
||||
|
@ -1707,7 +1727,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
|||
* action from a selection in the table.
|
||||
* <p>
|
||||
* This method is unavailable in headless mode.
|
||||
*
|
||||
*
|
||||
* @param title the title of the dialog
|
||||
* @param executor the TableChooserExecuter to be used to apply operations on table entries.
|
||||
* @return a new TableChooserDialog.
|
||||
|
@ -1725,7 +1745,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
|||
* action from a selection in the table.
|
||||
* <p>
|
||||
* This method is unavailable in headless mode.
|
||||
*
|
||||
*
|
||||
* @param title of the dialog
|
||||
* @param executor the TableChooserExecuter to be used to apply operations on table entries.
|
||||
* @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);
|
||||
|
||||
T mappedValue = null;
|
||||
if (clazz != null) {
|
||||
if (clazz != null && reusePreviousChoices) {
|
||||
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
|
||||
* missing .properties value.</li>
|
||||
* </ol>
|
||||
*
|
||||
*
|
||||
*
|
||||
* @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)
|
||||
|
@ -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
|
||||
* missing .properties value.</li>
|
||||
* </ol>
|
||||
*
|
||||
*
|
||||
*
|
||||
* @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)
|
||||
|
@ -2549,7 +2569,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
|||
* .properties byte pattern value (if it exists), or throws an Exception if there is
|
||||
* an invalid or missing .properties value.</li>
|
||||
* </ol>
|
||||
*
|
||||
*
|
||||
*
|
||||
* @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)
|
||||
|
@ -2608,7 +2628,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
|||
* then that value is returned. Otherwise, an Exception is thrown if there is an
|
||||
* invalid or missing .properties value.</li>
|
||||
* </ol>
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param title the title of the pop-up dialog (in GUI mode) or the variable name (in
|
||||
* 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
|
||||
* or missing .properties value.</li>
|
||||
* </ol>
|
||||
*
|
||||
*
|
||||
* @param title the title of the pop-up dialog (in GUI mode) or the variable name (in headless
|
||||
* mode or when using .properties file)
|
||||
* @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
|
||||
* missing .properties value.</li>
|
||||
* </ol>
|
||||
*
|
||||
*
|
||||
*
|
||||
* @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)
|
||||
|
@ -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
|
||||
* is thrown.</li>
|
||||
* </ol>
|
||||
*
|
||||
*
|
||||
*
|
||||
* @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)
|
||||
|
@ -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
|
||||
* there is an invalid or missing .properties value.</li>
|
||||
* </ol>
|
||||
*
|
||||
*
|
||||
* @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)
|
||||
* @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 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)
|
||||
throws CancelledException {
|
||||
|
@ -3160,8 +3180,8 @@ public abstract class GhidraScript extends FlatProgramAPI {
|
|||
* @return the user-selected value(s); null if no selection was made
|
||||
*
|
||||
* @throws CancelledException if the user hits the 'cancel' button
|
||||
* @throws IllegalArgumentException if choices is empty; if in headless mode,
|
||||
* there was a missing or invalid set of choices specified in the .properties file
|
||||
* @throws IllegalArgumentException if choices is empty; if in headless mode,
|
||||
* 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,
|
||||
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
|
||||
* invalid or missing .properties value.</li>
|
||||
* </ol>
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param title the title of the dialog (in GUI mode) or the first part of the variable name
|
||||
* (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.
|
||||
*/
|
||||
@Test
|
||||
|
@ -151,17 +151,17 @@ public class GhidraScriptAskMethodsTest extends AbstractGhidraHeadedIntegrationT
|
|||
runSwing(() -> dtd.close());
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* 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
|
||||
* for the input field is provided by the .properties file in the alternate location.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
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
|
||||
String tempDirPath = AbstractGTest.getTestDirectoryPath();
|
||||
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.
|
||||
*
|
||||
*
|
||||
* Also test that subsequent calls to the dialog show the last-used value.
|
||||
*/
|
||||
@Test
|
||||
|
@ -622,13 +622,40 @@ public class GhidraScriptAskMethodsTest extends AbstractGhidraHeadedIntegrationT
|
|||
|
||||
createScript();
|
||||
|
||||
final String defaultValue = "a default value";
|
||||
String defaultValue = "a default value";
|
||||
String myString = ask_TextInput(() -> {
|
||||
return script.askString("Default Test", "Enter a string here:", defaultValue);
|
||||
});
|
||||
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
|
||||
public void testAskChoice() throws Exception {
|
||||
createScript();
|
||||
|
@ -673,37 +700,37 @@ public class GhidraScriptAskMethodsTest extends AbstractGhidraHeadedIntegrationT
|
|||
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
|
||||
* the last-selected value or a .properties file value to pre-populate the user choice in the
|
||||
* GUI.
|
||||
/*
|
||||
* 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
|
||||
* GUI.
|
||||
*/
|
||||
|
||||
/*
|
||||
/*
|
||||
* 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
|
||||
* or 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
|
||||
* 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
|
||||
* 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
|
||||
* 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 <T> T ask_ComboInput(Callable<T> c) {
|
||||
return ask_TextInput(null, c);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue