mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-12-11 05:33:19 +00:00
Merge remote-tracking branch
'origin/GP-3204_ghidra007_fixCreateEnumsFromSelectionDupNameIssue--SQUASHED' (Closes #5036)
This commit is contained in:
commit
667773c9f3
@ -854,7 +854,11 @@
|
||||
or you will be prompted to enter a unique name. The resulting enum will contain a
|
||||
combination of all names and values from the selected enums. NOTE: If more than one of
|
||||
the same value is contained in the enums, they will all be added to the new enum.
|
||||
However, only the first one entered will be applied when this enum is used.</P>
|
||||
However, only the first one entered will be applied when this enum is used. If more than one
|
||||
entry with the same name is contained in the selected enums, any extras with the same value will
|
||||
be ignored and any with different value will be given a new name consisting of original name appended
|
||||
with as many underscores needed to make it unique. A comment will be added so users know which ones
|
||||
had names modified to allow the addition of the entry.</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="DeleteDataType"></A>Deleting a Data Type</H3>
|
||||
|
@ -15,6 +15,9 @@
|
||||
*/
|
||||
package ghidra.app.plugin.core.datamgr.actions;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
@ -107,9 +110,8 @@ public class CreateEnumFromSelectionAction extends DockingAction {
|
||||
|
||||
DataType dt = myDataTypeManager.getDataType(category.getCategoryPath(), newName);
|
||||
while (dt != null) {
|
||||
InputDialog dupInputDialog =
|
||||
new InputDialog("Duplicate ENUM Name",
|
||||
"Please enter a unique name for the new ENUM: ");
|
||||
InputDialog dupInputDialog = new InputDialog("Duplicate ENUM Name",
|
||||
"Please enter a unique name for the new ENUM: ");
|
||||
tool = plugin.getTool();
|
||||
tool.showDialog(dupInputDialog);
|
||||
|
||||
@ -119,7 +121,7 @@ public class CreateEnumFromSelectionAction extends DockingAction {
|
||||
newName = dupInputDialog.getValue();
|
||||
dt = myDataTypeManager.getDataType(category.getCategoryPath(), newName);
|
||||
}
|
||||
createNewEnum(category, enumArray, newName);
|
||||
createMergedEnum(category, enumArray, newName);
|
||||
|
||||
// select new node in tree. Must use invoke later to give the tree a chance to add the
|
||||
// the new node to the tree.
|
||||
@ -130,8 +132,8 @@ public class CreateEnumFromSelectionAction extends DockingAction {
|
||||
@Override
|
||||
public void run() {
|
||||
GTreeNode rootNode = gTree.getViewRoot();
|
||||
gTree.setSelectedNodeByNamePath(new String[] { rootNode.getName(), parentNodeName,
|
||||
newNodeName });
|
||||
gTree.setSelectedNodeByNamePath(
|
||||
new String[] { rootNode.getName(), parentNodeName, newNodeName });
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -168,34 +170,109 @@ public class CreateEnumFromSelectionAction extends DockingAction {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void createNewEnum(Category category, Enum[] enumArray, String newName) {
|
||||
private void createMergedEnum(Category category, Enum[] enumsToMerge, String mergedEnumName) {
|
||||
|
||||
// figure out size of the new enum using the max size of the selected enums
|
||||
int maxEnumSize = computeNewEnumSize(enumsToMerge);
|
||||
|
||||
SourceArchive sourceArchive = category.getDataTypeManager().getLocalSourceArchive();
|
||||
Enum mergedEnum = new EnumDataType(category.getCategoryPath(), mergedEnumName, maxEnumSize,
|
||||
category.getDataTypeManager());
|
||||
|
||||
mergedEnum.setSourceArchive(sourceArchive);
|
||||
|
||||
for (Enum element : enumsToMerge) {
|
||||
mergeEnum(mergedEnum, element);
|
||||
}
|
||||
|
||||
addEnumDataType(category, mergedEnum);
|
||||
|
||||
}
|
||||
|
||||
private void addEnumDataType(Category category, Enum mergedEnum) {
|
||||
int id = category.getDataTypeManager().startTransaction("Create New Enum Data Type");
|
||||
category.getDataTypeManager()
|
||||
.addDataType(mergedEnum, DataTypeConflictHandler.REPLACE_HANDLER);
|
||||
category.getDataTypeManager().endTransaction(id, true);
|
||||
}
|
||||
|
||||
private void mergeEnum(Enum mergedEnum, Enum enumToMerge) {
|
||||
|
||||
for (String name : enumToMerge.getNames()) {
|
||||
|
||||
long valueToAdd = enumToMerge.getValue(name);
|
||||
String comment = "";
|
||||
|
||||
if (isDuplicateEntry(mergedEnum, enumToMerge, name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isConflictingEntry(mergedEnum, enumToMerge, name)) {
|
||||
name = createDeconflictedName(mergedEnum, name);
|
||||
|
||||
comment = "NOTE: Duplicate name with different value";
|
||||
Msg.debug(this,
|
||||
"Merged Enum " + mergedEnum.getName() +
|
||||
" has at least one duplicate named entry with different value than " +
|
||||
"original. Underscore(s) have been appended to name allow addition.");
|
||||
}
|
||||
|
||||
mergedEnum.add(name, valueToAdd, comment);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private String createDeconflictedName(Enum enumm, String name) {
|
||||
|
||||
List<String> existingNames = Arrays.asList(enumm.getNames());
|
||||
while (existingNames.contains(name)) {
|
||||
name = name + "_";
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
private boolean isDuplicateEntry(Enum mergedEnum, Enum enumToMerge, String name) {
|
||||
|
||||
List<String> existingNames = Arrays.asList(mergedEnum.getNames());
|
||||
|
||||
if (!existingNames.contains(name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
long valueToAdd = enumToMerge.getValue(name);
|
||||
long existingValue = mergedEnum.getValue(name);
|
||||
if (valueToAdd == existingValue) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isConflictingEntry(Enum mergedEnum, Enum enumToMerge, String name) {
|
||||
|
||||
List<String> existingNames = Arrays.asList(mergedEnum.getNames());
|
||||
|
||||
if (!existingNames.contains(name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
long valueToAdd = enumToMerge.getValue(name);
|
||||
long existingValue = mergedEnum.getValue(name);
|
||||
if (valueToAdd == existingValue) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// figure out size in bytes of the new enum using the max size of the selected enums
|
||||
private int computeNewEnumSize(Enum[] enumArray) {
|
||||
int maxEnumSize = 1;
|
||||
for (Enum element : enumArray) {
|
||||
if (maxEnumSize < element.getLength()) {
|
||||
maxEnumSize = element.getLength();
|
||||
}
|
||||
}
|
||||
SourceArchive sourceArchive = category.getDataTypeManager().getLocalSourceArchive();
|
||||
Enum dataType =
|
||||
new EnumDataType(category.getCategoryPath(), newName, maxEnumSize,
|
||||
category.getDataTypeManager());
|
||||
|
||||
for (Enum element : enumArray) {
|
||||
String[] names = element.getNames();
|
||||
for (String name : names) {
|
||||
dataType.add(name, element.getValue(name));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
dataType.setSourceArchive(sourceArchive);
|
||||
int id = category.getDataTypeManager().startTransaction("Create New Enum Data Type");
|
||||
category.getDataTypeManager()
|
||||
.addDataType(dataType, DataTypeConflictHandler.REPLACE_HANDLER);
|
||||
category.getDataTypeManager().endTransaction(id, true);
|
||||
|
||||
return maxEnumSize;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -105,6 +105,8 @@ public class CreateEnumFromSelectionTest extends AbstractGhidraHeadedIntegration
|
||||
|
||||
@Test
|
||||
public void testCreateEnumFromSelection() throws Exception {
|
||||
|
||||
//NOTE: This test tests basic create enum from selection
|
||||
|
||||
// make two test enums in the program name folder
|
||||
|
||||
@ -196,6 +198,9 @@ public class CreateEnumFromSelectionTest extends AbstractGhidraHeadedIntegration
|
||||
|
||||
@Test
|
||||
public void testCreateEnumFromSelectionDupe() throws Exception {
|
||||
|
||||
//NOTE: This test tests basic create enum from selection and
|
||||
// tries to make second new enum with duplicate name and verifies that it won't
|
||||
|
||||
// make two test enums in the program name folder
|
||||
|
||||
@ -281,6 +286,115 @@ public class CreateEnumFromSelectionTest extends AbstractGhidraHeadedIntegration
|
||||
assertNotNull(newEnumNode);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateEnumFromSelectionDupeEntryNameOrValue() throws Exception {
|
||||
|
||||
//NOTE: This test tests handing of duplicate entry names and values
|
||||
// duplicate value diff name - add both
|
||||
// duplicate name and value - just add one entry with that combo
|
||||
// duplicate name diff value - add second name with _ appended and a comment to indicate change
|
||||
|
||||
// make two test enums in the program name folder
|
||||
|
||||
Category category = programNode.getCategory();
|
||||
DataTypeManager dataTypeManager = category.getDataTypeManager();
|
||||
|
||||
int id = dataTypeManager.startTransaction("new enum 1");
|
||||
Enum enumm = new EnumDataType("Colors", 1);
|
||||
enumm.add("Red", 0);
|
||||
enumm.add("Green", 0x10);
|
||||
enumm.add("Blue", 0x20);
|
||||
|
||||
category.addDataType(enumm, null);
|
||||
dataTypeManager.endTransaction(id, true);
|
||||
waitForTree();
|
||||
|
||||
int id2 = dataTypeManager.startTransaction("new enum 2");
|
||||
Enum enumm2 = new EnumDataType("MoreColors", 1);
|
||||
enumm2.add("Red", 0); // add dup name same value
|
||||
enumm2.add("Green", 0x5); // add dup name diff value
|
||||
enumm2.add("Black", 0x10); // add dup value diff name
|
||||
enumm2.add("Purple", 0x30);
|
||||
enumm2.add("White", 0x40);
|
||||
enumm2.add("Yellow", 0x50);
|
||||
|
||||
category.addDataType(enumm2, null);
|
||||
dataTypeManager.endTransaction(id2, true);
|
||||
waitForTree();
|
||||
|
||||
program.flushEvents();
|
||||
waitForPostedSwingRunnables();
|
||||
|
||||
DataTypeNode testEnumNode1 = (DataTypeNode) programNode.getChild("Colors");
|
||||
assertNotNull(testEnumNode1);
|
||||
|
||||
DataTypeNode testEnumNode2 = (DataTypeNode) programNode.getChild("MoreColors");
|
||||
assertNotNull(testEnumNode2);
|
||||
|
||||
expandNode(programNode);
|
||||
selectNodes(testEnumNode1, testEnumNode2);
|
||||
waitForTree();
|
||||
|
||||
final DockingActionIf action = getAction(plugin, "Enum from Selection");
|
||||
assertNotNull(action);
|
||||
assertTrue(action.isEnabledForContext(provider.getActionContext(null)));
|
||||
assertTrue(action.isAddToPopup(provider.getActionContext(null)));
|
||||
|
||||
executeOnSwingWithoutBlocking(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
DataTypeTestUtils.performAction(action, tree);
|
||||
}
|
||||
});
|
||||
|
||||
Window window = waitForWindow("Name new ENUM");
|
||||
assertNotNull(window);
|
||||
|
||||
final JTextField tf = findComponent(window, JTextField.class);
|
||||
assertNotNull(tf);
|
||||
|
||||
tf.setText("myNewEnum");
|
||||
pressButtonByText(window, "OK");
|
||||
assertTrue(!window.isShowing());
|
||||
waitForPostedSwingRunnables();
|
||||
waitForTree();
|
||||
|
||||
DataTypeNode newEnumNode = (DataTypeNode) programNode.getChild("myNewEnum");
|
||||
waitForTree();
|
||||
|
||||
assertNotNull(newEnumNode);
|
||||
|
||||
Enum newEnum = (Enum) newEnumNode.getDataType();
|
||||
long values[] = newEnum.getValues();
|
||||
String names[] = newEnum.getNames();
|
||||
|
||||
assertEquals(values.length, 7);
|
||||
assertEquals(names.length, 8);
|
||||
|
||||
|
||||
assertEquals(newEnum.getName(0x00L), "Red");
|
||||
assertEquals(newEnum.getName(0x5L), "Green_");
|
||||
assertEquals(newEnum.getName(0x10L), "Black"); // single query will return first alphabetically
|
||||
assertEquals(newEnum.getName(0x20L), "Blue");
|
||||
assertEquals(newEnum.getName(0x30L), "Purple");
|
||||
assertEquals(newEnum.getName(0x40L), "White");
|
||||
assertEquals(newEnum.getName(0x50L), "Yellow");
|
||||
|
||||
String[] namesfor10 = newEnum.getNames(0x10);
|
||||
assertEquals(namesfor10.length, 2);
|
||||
assertEquals(namesfor10[0], "Black");
|
||||
assertEquals(namesfor10[1], "Green");
|
||||
|
||||
assertEquals(newEnum.getValue("Red"), 0x00L);
|
||||
assertEquals(newEnum.getValue("Green_"), 0x5L);
|
||||
assertEquals(newEnum.getValue("Green"), 0x10L);
|
||||
assertEquals(newEnum.getValue("Black"), 0x10L);
|
||||
assertEquals(newEnum.getValue("Blue"), 0x20L);
|
||||
assertEquals(newEnum.getValue("Purple"), 0x30L);
|
||||
assertEquals(newEnum.getValue("White"), 0x40L);
|
||||
assertEquals(newEnum.getValue("Yellow"), 0x50L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDontCreateEnumFromSingleSelection() throws Exception {
|
||||
|
Loading…
Reference in New Issue
Block a user