Merge remote-tracking branch 'origin/GP-1870_ghidravore_add_simple_string_properties_to_user_data--SQUASHED'

This commit is contained in:
Ryan Kurtz 2022-03-31 00:53:08 -04:00
commit 0fd9dddceb
4 changed files with 236 additions and 140 deletions

View file

@ -19,6 +19,7 @@ import static org.junit.Assert.*;
import java.io.File;
import java.util.Random;
import java.util.Set;
import org.junit.*;
@ -142,10 +143,8 @@ public class ProgramUserDataTest extends AbstractGhidraHeadedIntegrationTest {
DomainFile df2;
Program program =
(Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY);
Program program = (Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY);
space = program.getAddressFactory().getDefaultAddressSpace();
try {
assertFalse(program.isChanged());
assertTrue(program.canSave());
@ -165,29 +164,21 @@ public class ProgramUserDataTest extends AbstractGhidraHeadedIntegrationTest {
String newName = df.getName() + ".1";
df2 = df.getParent().createFile(newName, program, TaskMonitor.DUMMY);
}
finally {
program.release(this);
}
program =
(Program) df2.getDomainObject(this, false, false, TaskMonitor.DUMMY);
try {
program = (Program) df2.getDomainObject(this, false, false, TaskMonitor.DUMMY);
assertFalse(program.isChanged());
// Verify user data content
ProgramUserData userData = program.getProgramUserData();
userData = program.getProgramUserData();
StringPropertyMap map =
userData.getStringProperty(testName.getMethodName(), "STRING", false);
assertEquals("Str0", map.getString(space.getAddress(0)));
assertEquals("Str10", map.getString(space.getAddress(10)));
assertNull(map.getString(space.getAddress(20)));
assertFalse(program.isChanged());
}
finally {
program.release(this);
}
program.release(this);
}
@Test
@ -204,10 +195,8 @@ public class ProgramUserDataTest extends AbstractGhidraHeadedIntegrationTest {
File dbDir = new File(dataDir, "00/~00000000.db");
int ver;
Program program =
(Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY);
Program program = (Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY);
space = program.getAddressFactory().getDefaultAddressSpace();
try {
assertFalse(program.isChanged());
assertTrue(program.canSave());
@ -226,22 +215,17 @@ public class ProgramUserDataTest extends AbstractGhidraHeadedIntegrationTest {
change(userData, "STRING", space.getAddress(10), "Str10");
assertFalse(program.isChanged());
}
finally {
program.release(this);
}
assertEquals("User data files missing", 2, userDataSubDir.list().length);
assertEquals("Program database should not have been updated", ver,
getLatestDbVersion(dbDir));
program =
(Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY);
try {
program = (Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY);
assertFalse(program.isChanged());
// Verify user data content
ProgramUserData userData = program.getProgramUserData();
userData = program.getProgramUserData();
StringPropertyMap map =
userData.getStringProperty(testName.getMethodName(), "STRING", false);
assertEquals("Str0", map.getString(space.getAddress(0)));
@ -253,28 +237,21 @@ public class ProgramUserDataTest extends AbstractGhidraHeadedIntegrationTest {
change(userData, "STRING", space.getAddress(10), "Str10a");
change(userData, "STRING", space.getAddress(20), "Str20a");
assertFalse(program.isChanged());
}
finally {
program.release(this);
}
program =
(Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY);
try {
program.release(this);
program = (Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY);
assertFalse(program.isChanged());
// Verify user data content
ProgramUserData userData = program.getProgramUserData();
StringPropertyMap map =
userData.getStringProperty(testName.getMethodName(), "STRING", false);
userData = program.getProgramUserData();
map = userData.getStringProperty(testName.getMethodName(), "STRING", false);
assertEquals("Str0", map.getString(space.getAddress(0)));
assertEquals("Str10a", map.getString(space.getAddress(10)));
assertEquals("Str20a", map.getString(space.getAddress(20)));
assertFalse(program.isChanged());
}
finally {
program.release(this);
}
assertEquals("User data files missing", 2, userDataSubDir.list().length);
df.delete();
@ -288,18 +265,14 @@ public class ProgramUserDataTest extends AbstractGhidraHeadedIntegrationTest {
// TODO: Multi-user repository connect case not tested
Program program =
(Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY);
Program program = (Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY);
space = program.getAddressFactory().getDefaultAddressSpace();
try {
// Create user data content
ProgramUserData userData = program.getProgramUserData();
change(userData, "STRING", space.getAddress(0), "Str0");
change(userData, "STRING", space.getAddress(10), "Str10");
}
finally {
program.release(this);
}
// Close and re-open (domain file remains intact)
project.close();
@ -308,23 +281,19 @@ public class ProgramUserDataTest extends AbstractGhidraHeadedIntegrationTest {
df = project.getProjectData().getFile("/test");
program =
(Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY);
try {
program = (Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY);
assertFalse(program.isChanged());
// Verify user data content
ProgramUserData userData = program.getProgramUserData();
userData = program.getProgramUserData();
StringPropertyMap map =
userData.getStringProperty(testName.getMethodName(), "STRING", false);
assertEquals("Str0", map.getString(space.getAddress(0)));
assertEquals("Str10", map.getString(space.getAddress(10)));
assertNull(map.getString(space.getAddress(20)));
assertFalse(program.isChanged());
}
finally {
program.release(this);
}
// Close and re-open (domain file removed)
project.close();
@ -351,4 +320,70 @@ public class ProgramUserDataTest extends AbstractGhidraHeadedIntegrationTest {
}
}
@Test
public void testSetGetStringProperty() throws Exception {
Program program = (Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY);
ProgramUserData userData = program.getProgramUserData();
userData.setStringProperty("Foo", "Bar");
assertEquals("Bar", userData.getStringProperty("Foo", null));
program.release(this);
program = (Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY);
userData = program.getProgramUserData();
assertEquals("Bar", userData.getStringProperty("Foo", null));
program.release(this);
}
@Test
public void testGetStringPropertyNames() throws Exception {
Program program = (Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY);
ProgramUserData userData = program.getProgramUserData();
userData.setStringProperty("Alpha", "alpha");
userData.setStringProperty("Beta", "beta");
Set<String> stringPropertyNames = userData.getStringPropertyNames();
assertEquals(2, stringPropertyNames.size());
assertTrue(stringPropertyNames.contains("Alpha"));
assertTrue(stringPropertyNames.contains("Beta"));
program.release(this);
}
@Test
public void testGetStringPropertyForNondefinedProperty() throws Exception {
Program program = (Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY);
ProgramUserData userData = program.getProgramUserData();
assertEquals("xxx", userData.getStringProperty("ABC", "xxx"));
assertEquals("zzz", userData.getStringProperty("ABC", "zzz"));
program.release(this);
}
@Test
public void testRemoveStringProperty() throws Exception {
Program program = (Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY);
ProgramUserData userData = program.getProgramUserData();
userData.setStringProperty("foo", "bar");
program.release(this);
// reload and make sure the property is there
program = (Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY);
userData = program.getProgramUserData();
assertEquals("bar", userData.getStringProperty("foo", null));
assertEquals("bar", userData.removeStringProperty("foo"));
program.release(this);
// reload and make sure the property is gone
program = (Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY);
userData = program.getProgramUserData();
assertNull(userData.getStringProperty("foo", null));
program.release(this);
}
}

View file

@ -602,6 +602,7 @@ public abstract class DomainObjectAdapterDB extends DomainObjectAdapter
DomainObjectAdapterDB userData = getUserData();
if (userData != null && userData.isChanged() && (getDomainFile() instanceof GhidraFile)) {
try {
userData.prepareToSave();
userData.save(null, TaskMonitorAdapter.DUMMY_MONITOR);
}
catch (CancelledException e) {

View file

@ -242,7 +242,8 @@ class ProgramUserDataDB extends DomainObjectAdapterDB implements ProgramUserData
Language newLanguage = language;
Language oldLanguage = OldLanguageFactory.getOldLanguageFactory().getOldLanguage(
Language oldLanguage = OldLanguageFactory.getOldLanguageFactory()
.getOldLanguage(
languageID, languageVersion);
if (oldLanguage == null) {
// Assume minor version behavior - old language does not exist for current major version
@ -253,7 +254,8 @@ class ProgramUserDataDB extends DomainObjectAdapterDB implements ProgramUserData
// Ensure that we can upgrade the language
languageUpgradeTranslator =
LanguageTranslatorFactory.getLanguageTranslatorFactory().getLanguageTranslator(
LanguageTranslatorFactory.getLanguageTranslatorFactory()
.getLanguageTranslator(
oldLanguage, newLanguage);
if (languageUpgradeTranslator == null) {
throw new LanguageNotFoundException(language.getLanguageID(),
@ -285,7 +287,8 @@ class ProgramUserDataDB extends DomainObjectAdapterDB implements ProgramUserData
throws LanguageNotFoundException {
languageUpgradeTranslator =
LanguageTranslatorFactory.getLanguageTranslatorFactory().getLanguageTranslator(
LanguageTranslatorFactory.getLanguageTranslatorFactory()
.getLanguageTranslator(
languageID, languageVersion);
if (languageUpgradeTranslator == null) {
throw e;
@ -372,6 +375,7 @@ class ProgramUserDataDB extends DomainObjectAdapterDB implements ProgramUserData
if (storedVersion < UPGRADE_REQUIRED_BEFORE_VERSION) {
requiresUpgrade = true;
}
loadMetadata();
return requiresUpgrade ? new VersionException(true) : null;
}
@ -686,4 +690,27 @@ class ProgramUserDataDB extends DomainObjectAdapterDB implements ProgramUserData
// fireEvent(new DomainObjectChangeRecord(DomainObject.DO_OBJECT_SAVED));
}
@Override
public void setStringProperty(String propertyName, String value) {
metadata.put(propertyName, value);
changed = true;
}
@Override
public String getStringProperty(String propertyName, String defaultValue) {
String value = metadata.get(propertyName);
return value == null ? defaultValue : value;
}
@Override
public Set<String> getStringPropertyNames() {
return metadata.keySet();
}
@Override
public String removeStringProperty(String propertyName) {
changed = true;
return metadata.remove(propertyName);
}
}

View file

@ -16,6 +16,7 @@
package ghidra.program.model.listing;
import java.util.List;
import java.util.Set;
import ghidra.framework.model.UserData;
import ghidra.framework.options.Options;
@ -33,16 +34,16 @@ public interface ProgramUserData extends UserData {
/**
* End a previously started transaction
* @param transactionID
* @param transactionID the id of the transaction to close
*/
public void endTransaction(int transactionID);
/**
* Get a address-based String property map
* @param owner name of property owner (e.g., plugin name)
* @param propertyName
* @param propertyName the name of property map
* @param create creates the property map if it does not exist
* @return property map
* @return the property map for the given name
* @throws PropertyTypeMismatchException if a conflicting map definition was found
*/
public StringPropertyMap getStringProperty(String owner, String propertyName, boolean create)
@ -51,7 +52,7 @@ public interface ProgramUserData extends UserData {
/**
* Get a address-based Long property map
* @param owner name of property owner (e.g., plugin name)
* @param propertyName
* @param propertyName the name of property map
* @param create creates the property map if it does not exist
* @return property map
* @throws PropertyTypeMismatchException if a conflicting map definition was found
@ -62,7 +63,7 @@ public interface ProgramUserData extends UserData {
/**
* Get a address-based Integer property map
* @param owner name of property owner (e.g., plugin name)
* @param propertyName
* @param propertyName the name of property map
* @param create creates the property map if it does not exist
* @return property map
* @throws PropertyTypeMismatchException if a conflicting map definition was found
@ -73,7 +74,7 @@ public interface ProgramUserData extends UserData {
/**
* Get a address-based Boolean property map
* @param owner name of property owner (e.g., plugin name)
* @param propertyName
* @param propertyName the name of property map
* @param create creates the property map if it does not exist
* @return property map
* @throws PropertyTypeMismatchException if a conflicting map definition was found
@ -84,7 +85,8 @@ public interface ProgramUserData extends UserData {
/**
* Get a address-based Saveable-object property map
* @param owner name of property owner (e.g., plugin name)
* @param propertyName
* @param propertyName the name of property map
* @param saveableObjectClass the class type for the object property map
* @param create creates the property map if it does not exist
* @return property map
* @throws PropertyTypeMismatchException if a conflicting map definition was found
@ -101,19 +103,50 @@ public interface ProgramUserData extends UserData {
/**
* Returns list of all property owners for which property maps have been defined.
* @return list of all property owners for which property maps have been defined.
*/
public List<String> getPropertyOwners();
/**
* Returns all properties lists contained by this domain object.
* Returns all names of all the Options objects store in the user data
*
* @return all property lists contained by this domain object.
* @return all names of all the Options objects store in the user data
*/
public List<String> getOptionsNames();
/**
* Get the property list for the given name.
* @param propertyListName name of property list
* Get the Options for the given optionsName
* @param optionsName the name of the options options to retrieve
* @return The options for the given name
*/
public Options getOptions(String propertyListName);
public Options getOptions(String optionsName);
/**
* Sets the given String property
* @param propertyName the name of the property
* @param value the value of the property
*/
public void setStringProperty(String propertyName, String value);
/**
* Gets the value for the given property name
* @param propertyName the name of the string property to retrieve
* @param defaultValue the value to return if there is no saved value for the given name
* @return the value for the given property name
*/
public String getStringProperty(String propertyName, String defaultValue);
/**
* Removes the String property with the given name;
* @param propertyName the name of the property to remove;
* @return returns the value of the property that was removed or null if the property doesn't
* exist
*/
public String removeStringProperty(String propertyName);
/**
* Returns a set of all String properties that have been set on this ProgramUserData object
* @return a set of all String properties that have been set on this ProgramUserData object
*/
public Set<String> getStringPropertyNames();
}