Merge remote-tracking branch 'origin/GP-1-dragonmacher-dt-filter-updates--SQUASHED'

This commit is contained in:
ghidra1 2025-05-08 17:48:06 -04:00
commit 9a7d3eb93f
11 changed files with 545 additions and 172 deletions

View file

@ -202,7 +202,7 @@ public class BookmarkPlugin extends ProgramPlugin implements PopupActionProvider
*/
public void filterBookmarks() {
FilterDialog d = new FilterDialog(provider, currentProgram);
tool.showDialog(d, provider);
tool.showDialog(d, provider.getComponent());
provider.contextChanged();
}
@ -282,9 +282,7 @@ public class BookmarkPlugin extends ProgramPlugin implements PopupActionProvider
}
private void disposeAllBookmarkers() {
Iterator<BookmarkNavigator> it = bookmarkNavigators.values().iterator();
while (it.hasNext()) {
BookmarkNavigator nav = it.next();
for (BookmarkNavigator nav : bookmarkNavigators.values()) {
nav.dispose();
}
bookmarkNavigators.clear();
@ -624,9 +622,8 @@ public class BookmarkPlugin extends ProgramPlugin implements PopupActionProvider
types.add(type);
}
else {
Iterator<String> it = bookmarkNavigators.keySet().iterator();
while (it.hasNext()) {
types.add(it.next());
for (String element : bookmarkNavigators.keySet()) {
types.add(element);
}
}
updateMgr.update();
@ -655,9 +652,7 @@ public class BookmarkPlugin extends ProgramPlugin implements PopupActionProvider
running = true;
}
try {
Iterator<String> it = myTypes.iterator();
while (it.hasNext()) {
String type = it.next();
for (String type : myTypes) {
updateNav(type);
}
}

View file

@ -57,7 +57,7 @@ public class DtFilterAction extends DockingAction {
DataTypesProvider provider = (DataTypesProvider) context.getComponentProvider();
DtFilterState currentFilterState = provider.getFilterState();
DtFilterDialog dialog = new DtFilterDialog(currentFilterState);
plugin.getTool().showDialog(dialog);
plugin.getTool().showDialog(dialog, provider.getComponent());
// if not cancelled
if (dialog.isCancelled()) {

View file

@ -22,8 +22,6 @@ import javax.swing.Icon;
import docking.widgets.tree.GTreeNode;
import ghidra.app.plugin.core.datamgr.util.DataTypeUtils;
import ghidra.program.model.data.*;
import ghidra.program.model.data.Enum;
import ghidra.program.model.listing.Function;
import ghidra.util.*;
import ghidra.util.exception.AssertException;
import ghidra.util.exception.DuplicateNameException;
@ -61,7 +59,7 @@ public class CategoryNode extends DataTypeTreeNode {
}
for (DataType dataType : dataTypes) {
if (!isFilteredType(dataType)) {
if (passesFilters(dataType)) {
list.add(new DataTypeNode(dataType));
}
}
@ -71,33 +69,8 @@ public class CategoryNode extends DataTypeTreeNode {
return list;
}
private boolean isFilteredType(DataType dataType) {
if (!filterState.isShowArrays() && dataType instanceof Array) {
return true;
}
if (!filterState.isShowPointers() && (dataType instanceof Pointer) &&
!(dataType.getDataTypeManager() instanceof BuiltInDataTypeManager)) {
return true;
}
if (!filterState.isShowEnums() && (dataType instanceof Enum)) {
return true;
}
if (!filterState.isShowFunctions() && (dataType instanceof Function)) {
return true;
}
if (!filterState.isShowStructures() && (dataType instanceof Structure)) {
return true;
}
if (!filterState.isShowUnions() && (dataType instanceof Union)) {
return true;
}
return false;
private boolean passesFilters(DataType dataType) {
return filterState.passesFilters(dataType);
}
@Override
@ -212,7 +185,7 @@ public class CategoryNode extends DataTypeTreeNode {
return;
}
if (isFilteredType(dataType)) {
if (!passesFilters(dataType)) {
return;
}

View file

@ -15,25 +15,29 @@
*/
package ghidra.app.plugin.core.datamgr.tree;
import javax.swing.JPanel;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.util.List;
import javax.swing.*;
import docking.DialogComponentProvider;
import docking.widgets.button.GButton;
import docking.widgets.checkbox.GCheckBox;
import ghidra.app.util.HelpTopics;
import ghidra.util.HelpLocation;
import ghidra.util.layout.PairLayout;
/**
* Data Types provider dialog to allow users to change the types that are filtered.
*/
public class DtFilterDialog extends DialogComponentProvider {
private GCheckBox arraysCheckBox = new GCheckBox("Show Arrays");
private GCheckBox enumsCheckBox = new GCheckBox("Show Enums");
private GCheckBox functionsCheckBox = new GCheckBox("Show Functions");
private GCheckBox pointersCheckBox = new GCheckBox("Show Pointers");
private GCheckBox structuresCheckBox = new GCheckBox("Show Structures");
private GCheckBox unionsCheckBox = new GCheckBox("Show Unions");
private TypeComponent arraysComponent = new TypeComponent("Arrays");
private TypeComponent enumsComponent = new TypeComponent("Enums");
private TypeComponent functionsComponent = new TypeComponent("Functions");
private TypeComponent pointersComponent = new TypeComponent("Pointers");
private TypeComponent structuresComponent = new TypeComponent("Structures");
private TypeComponent unionsComponent = new TypeComponent("Unions");
private DtFilterState filterState;
private boolean isCancelled;
@ -47,7 +51,7 @@ public class DtFilterDialog extends DialogComponentProvider {
addOKButton();
addCancelButton();
setHelpLocation(new HelpLocation(HelpTopics.DATA_MANAGER, "Set Filter"));
setHelpLocation(new HelpLocation(HelpTopics.DATA_MANAGER, "Show Filter"));
initCheckBoxes();
setRememberSize(false);
@ -70,39 +74,136 @@ public class DtFilterDialog extends DialogComponentProvider {
public DtFilterState getFilterState() {
DtFilterState newState = new DtFilterState();
newState.setShowArrays(arraysCheckBox.isSelected());
newState.setShowEnums(enumsCheckBox.isSelected());
newState.setShowFunctions(functionsCheckBox.isSelected());
newState.setShowPointers(pointersCheckBox.isSelected());
newState.setShowStructures(structuresCheckBox.isSelected());
newState.setShowUnions(unionsCheckBox.isSelected());
newState.setArraysFilter(arraysComponent.getFilter());
newState.setEnumsFilter(enumsComponent.getFilter());
newState.setFunctionsFilter(functionsComponent.getFilter());
newState.setPointersFilter(pointersComponent.getFilter());
newState.setStructuresFilter(structuresComponent.getFilter());
newState.setUnionsFilter(unionsComponent.getFilter());
return newState;
}
private JPanel buildWorkPanel() {
JPanel panel = new JPanel(new PairLayout(5, 10));
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(0, 2));
panel.add(arraysCheckBox);
panel.add(enumsCheckBox);
panel.add(functionsCheckBox);
panel.add(pointersCheckBox);
panel.add(structuresCheckBox);
panel.add(unionsCheckBox);
JLabel l1 = new JLabel("<html><b>Show");
l1.setHorizontalAlignment(SwingConstants.LEFT);
panel.add(l1);
JLabel l2 = new JLabel("<html><b>Include Typedefs");
l2.setHorizontalAlignment(SwingConstants.CENTER);
panel.add(l2);
panel.add(arraysComponent.getLeft());
panel.add(arraysComponent.getRight());
panel.add(enumsComponent.getLeft());
panel.add(enumsComponent.getRight());
panel.add(functionsComponent.getLeft());
panel.add(functionsComponent.getRight());
panel.add(pointersComponent.getLeft());
panel.add(pointersComponent.getRight());
panel.add(structuresComponent.getLeft());
panel.add(structuresComponent.getRight());
panel.add(unionsComponent.getLeft());
panel.add(unionsComponent.getRight());
GButton selectAll = new GButton("Select All");
GButton deselectAll = new GButton("Deselect All");
selectAll.addActionListener(e -> {
allButtons().forEach(b -> b.setSelected(true));
});
deselectAll.addActionListener(e -> {
allButtons().forEach(b -> b.setSelected(false));
});
// spacer above buttons
panel.add(Box.createRigidArea(new Dimension(10, 10)));
panel.add(Box.createRigidArea(new Dimension(10, 10)));
JPanel p1 = new JPanel();
p1.setLayout(new BoxLayout(p1, BoxLayout.LINE_AXIS));
p1.add(Box.createHorizontalGlue());
p1.add(selectAll);
p1.add(Box.createHorizontalGlue());
JPanel p2 = new JPanel();
p2.setLayout(new BoxLayout(p2, BoxLayout.LINE_AXIS));
p2.add(Box.createHorizontalGlue());
p2.add(deselectAll);
p2.add(Box.createHorizontalGlue());
panel.add(p1);
panel.add(p2);
return panel;
}
private List<AbstractButton> allButtons() {
//@formatter:off
return List.of(
arraysComponent.typeCb,
arraysComponent.typeDefCb,
enumsComponent.typeCb,
enumsComponent.typeDefCb,
functionsComponent.typeCb,
functionsComponent.typeDefCb,
pointersComponent.typeCb,
pointersComponent.typeDefCb,
structuresComponent.typeCb,
structuresComponent.typeDefCb,
unionsComponent.typeCb,
unionsComponent.typeDefCb
);
//@formatter:on
}
private void initCheckBoxes() {
arraysCheckBox.setSelected(filterState.isShowArrays());
enumsCheckBox.setSelected(filterState.isShowEnums());
functionsCheckBox.setSelected(filterState.isShowFunctions());
pointersCheckBox.setSelected(filterState.isShowPointers());
structuresCheckBox.setSelected(filterState.isShowStructures());
unionsCheckBox.setSelected(filterState.isShowUnions());
arraysComponent.init(filterState.getArraysFilter());
enumsComponent.init(filterState.getEnumsFilter());
functionsComponent.init(filterState.getFunctionsFilter());
pointersComponent.init(filterState.getPointersFilter());
structuresComponent.init(filterState.getStructuresFilter());
unionsComponent.init(filterState.getUnionsFilter());
}
private class TypeComponent {
private String type;
private GCheckBox typeCb;
private GCheckBox typeDefCb;
TypeComponent(String type) {
this.type = type;
this.typeCb = new GCheckBox(type);
this.typeDefCb = new GCheckBox();
this.typeDefCb.setName(type + "Typedefs");
}
JComponent getLeft() {
return typeCb;
}
JComponent getRight() {
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS));
panel.add(Box.createHorizontalGlue());
panel.add(typeDefCb);
panel.add(Box.createHorizontalGlue());
return panel;
}
void init(DtTypeFilter typeFilter) {
typeCb.setSelected(typeFilter.isTypeActive());
typeDefCb.setSelected(typeFilter.isTypeDefActive());
}
DtTypeFilter getFilter() {
DtTypeFilter filter = new DtTypeFilter(type);
filter.setTypeActive(typeCb.isSelected());
filter.setTypeDefActive(typeDefCb.isSelected());
return filter;
}
}
}

View file

@ -17,7 +17,11 @@ package ghidra.app.plugin.core.datamgr.tree;
import java.util.Objects;
import ghidra.app.plugin.core.datamgr.util.DataTypeUtils;
import ghidra.framework.options.SaveState;
import ghidra.program.model.data.*;
import ghidra.program.model.data.Enum;
import ghidra.program.model.listing.Function;
/**
* A simple object to store various filter settings for the data type provider.
@ -26,118 +30,178 @@ public class DtFilterState {
private static final String XML_NAME = "DATA_TYPES_FILTER";
private boolean showArrays = false;
private boolean showEnums = true;
private boolean showFunctions = true;
private boolean showStructures = true;
private boolean showTypedefs = true;
private boolean showPointers = false;
private boolean showUnions = true;
private DtTypeFilter arraysFilter = new DtTypeFilter("Arrays");
private DtTypeFilter enumsFilter = new DtTypeFilter("Enums");
private DtTypeFilter functionsFilter = new DtTypeFilter("Functions");
private DtTypeFilter structuresFilter = new DtTypeFilter("Structures");
private DtTypeFilter pointersFilter = new DtTypeFilter("Pointers");
private DtTypeFilter unionsFilter = new DtTypeFilter("Unions");
public DtFilterState() {
// these types are off by default, since users typically are not working with them
arraysFilter.setTypeActive(false);
pointersFilter.setTypeActive(false);
}
public DtFilterState copy() {
DtFilterState filterState = new DtFilterState();
filterState.setShowArrays(showArrays);
filterState.setShowEnums(showEnums);
filterState.setShowFunctions(showFunctions);
filterState.setShowStructures(showStructures);
filterState.setShowTypedefs(showTypedefs);
filterState.setShowPointers(showPointers);
filterState.setShowUnions(showUnions);
filterState.arraysFilter = arraysFilter.copy();
filterState.enumsFilter = enumsFilter.copy();
filterState.functionsFilter = functionsFilter.copy();
filterState.structuresFilter = structuresFilter.copy();
filterState.pointersFilter = pointersFilter.copy();
filterState.unionsFilter = unionsFilter.copy();
return filterState;
}
public boolean isShowPointers() {
return showPointers;
public boolean isShowArrays() {
return arraysFilter.isTypeActive();
}
public void setShowPointers(boolean showPointers) {
this.showPointers = showPointers;
public DtTypeFilter getArraysFilter() {
return arraysFilter;
}
public boolean isShowStructures() {
return showStructures;
}
public void setShowStructures(boolean showStructures) {
this.showStructures = showStructures;
}
public boolean isShowTypedefs() {
return showStructures;
}
public void setShowTypedefs(boolean showTypedefs) {
this.showTypedefs = showTypedefs;
public void setArraysFilter(DtTypeFilter filter) {
this.arraysFilter = filter;
}
public boolean isShowEnums() {
return showEnums;
return enumsFilter.isTypeActive();
}
public void setShowEnums(boolean showEnums) {
this.showEnums = showEnums;
public DtTypeFilter getEnumsFilter() {
return enumsFilter;
}
public void setEnumsFilter(DtTypeFilter filter) {
this.enumsFilter = filter;
}
public boolean isShowFunctions() {
return showFunctions;
return functionsFilter.isTypeActive();
}
public void setShowFunctions(boolean showFunctions) {
this.showFunctions = showFunctions;
public DtTypeFilter getFunctionsFilter() {
return functionsFilter;
}
public void setFunctionsFilter(DtTypeFilter filter) {
this.functionsFilter = filter;
}
public boolean isShowPointers() {
return pointersFilter.isTypeActive();
}
public DtTypeFilter getPointersFilter() {
return pointersFilter;
}
public void setPointersFilter(DtTypeFilter filter) {
this.pointersFilter = filter;
}
public boolean isShowStructures() {
return structuresFilter.isTypeActive();
}
public DtTypeFilter getStructuresFilter() {
return structuresFilter;
}
public void setStructuresFilter(DtTypeFilter filter) {
this.structuresFilter = filter;
}
public boolean isShowUnions() {
return showUnions;
return unionsFilter.isTypeActive();
}
public void setShowUnions(boolean showUnions) {
this.showUnions = showUnions;
public DtTypeFilter getUnionsFilter() {
return unionsFilter;
}
public boolean isShowArrays() {
return showArrays;
public void setUnionsFilter(DtTypeFilter filter) {
this.unionsFilter = filter;
}
public void setShowArrays(boolean showArrays) {
this.showArrays = showArrays;
public boolean passesFilters(DataType dt) {
DataTypeManager dtm = dt.getDataTypeManager();
if (dtm instanceof BuiltInDataTypeManager) {
// never filter built-in types here; users can filter them using the text filter
return true;
}
public void setshowPointers(boolean showPointers) {
this.showPointers = showPointers;
DataType baseDt = DataTypeUtils.getBaseDataType(dt);
if (dt instanceof Array) {
return passes(arraysFilter, dt, baseDt);
}
if (dt instanceof Pointer) {
return passes(pointersFilter, dt, baseDt);
}
if (baseDt instanceof Enum) {
return passes(enumsFilter, dt, baseDt);
}
if (baseDt instanceof Function) {
return passes(functionsFilter, dt, baseDt);
}
if (baseDt instanceof Structure) {
return passes(structuresFilter, dt, baseDt);
}
if (baseDt instanceof Union) {
return passes(unionsFilter, dt, baseDt);
}
return true;
}
private boolean passes(DtTypeFilter filter, DataType dt, DataType baseDt) {
if (filter.isTypeActive()) {
return true;
}
if (filter.isTypeDefActive() && dt instanceof TypeDef) {
return true;
}
return false;
}
public void save(SaveState parentSaveState) {
SaveState saveState = new SaveState(XML_NAME);
saveState.putBoolean("SHOW_ARRAYS", showArrays);
saveState.putBoolean("SHOW_ENUMS", showEnums);
saveState.putBoolean("SHOW_FUNCTIONS", showFunctions);
saveState.putBoolean("SHOW_POINTERS", showPointers);
saveState.putBoolean("SHOW_STRUCTURES", showStructures);
saveState.putBoolean("SHOW_TYPEDEFS", showTypedefs);
saveState.putBoolean("SHOW_UNIONS", showUnions);
SaveState ss = new SaveState(XML_NAME);
ss.putSaveState(arraysFilter.getName(), arraysFilter.save());
ss.putSaveState(enumsFilter.getName(), enumsFilter.save());
ss.putSaveState(functionsFilter.getName(), functionsFilter.save());
ss.putSaveState(pointersFilter.getName(), pointersFilter.save());
ss.putSaveState(structuresFilter.getName(), structuresFilter.save());
ss.putSaveState(unionsFilter.getName(), unionsFilter.save());
parentSaveState.putSaveState(XML_NAME, saveState);
parentSaveState.putSaveState(XML_NAME, ss);
}
public void restore(SaveState parentSaveState) {
parentSaveState.getSaveState(XML_NAME);
SaveState saveState = new SaveState();
SaveState ss = parentSaveState.getSaveState(XML_NAME);
showArrays = saveState.getBoolean("SHOW_ARRAYS", false);
showEnums = saveState.getBoolean("SHOW_ENUMS", true);
showFunctions = saveState.getBoolean("SHOW_FUNCTIONS", true);
showPointers = saveState.getBoolean("SHOW_POINTERS", false);
showStructures = saveState.getBoolean("SHOW_STRUCTURES", true);
showTypedefs = saveState.getBoolean("SHOW_TYPEDEFS", true);
showUnions = saveState.getBoolean("SHOW_UNIONS", true);
arraysFilter = DtTypeFilter.restore("Arrays", ss.getSaveState("Arrays"));
enumsFilter = DtTypeFilter.restore("Enums", ss.getSaveState("Enums"));
functionsFilter = DtTypeFilter.restore("Functions", ss.getSaveState("Functions"));
pointersFilter = DtTypeFilter.restore("Pointers", ss.getSaveState("Pointers"));
structuresFilter = DtTypeFilter.restore("Structures", ss.getSaveState("Structures"));
unionsFilter = DtTypeFilter.restore("Unions", ss.getSaveState("Unions"));
}
@Override
public int hashCode() {
return Objects.hash(showArrays, showEnums, showFunctions, showPointers, showStructures,
showTypedefs, showUnions);
return Objects.hash(arraysFilter, enumsFilter, functionsFilter, pointersFilter,
structuresFilter, unionsFilter);
}
@Override
@ -152,10 +216,12 @@ public class DtFilterState {
return false;
}
DtFilterState other = (DtFilterState) obj;
return showArrays == other.showArrays && showEnums == other.showEnums &&
showFunctions == other.showFunctions && showPointers == other.showPointers &&
showStructures == other.showStructures && showTypedefs == other.showTypedefs &&
showUnions == other.showUnions;
return Objects.equals(arraysFilter, other.arraysFilter) &&
Objects.equals(enumsFilter, other.enumsFilter) &&
Objects.equals(functionsFilter, other.functionsFilter) &&
Objects.equals(pointersFilter, other.pointersFilter) &&
Objects.equals(structuresFilter, other.structuresFilter) &&
Objects.equals(unionsFilter, other.unionsFilter);
}
}

View file

@ -0,0 +1,111 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.plugin.core.datamgr.tree;
import java.util.Objects;
import generic.json.Json;
import ghidra.framework.options.SaveState;
/**
* A class that holds enabled state for a type and related typedefs.
*/
public class DtTypeFilter {
private static final String IS_TYPE_ACTIVE_KEY = "IS_TYPE_ACTIVE";
private static final String IS_TYPE_DEF_ACTIVE_KEY = "IS_TYPE_DEF_ACTIVE";
private String name;
private boolean isTypeActive = true;
private boolean isTypeDefActive = true;
static DtTypeFilter restore(String typeName, SaveState ss) {
if (ss == null) {
return new DtTypeFilter(typeName);
}
return new DtTypeFilter(ss);
}
DtTypeFilter(String name) {
this.name = name;
}
private DtTypeFilter(SaveState ss) {
name = ss.getName();
isTypeActive = ss.getBoolean(IS_TYPE_ACTIVE_KEY, true);
isTypeDefActive = ss.getBoolean(IS_TYPE_DEF_ACTIVE_KEY, true);
}
SaveState save() {
SaveState ss = new SaveState(name);
ss.putBoolean(IS_TYPE_ACTIVE_KEY, isTypeActive);
ss.putBoolean(IS_TYPE_DEF_ACTIVE_KEY, isTypeDefActive);
return ss;
}
DtTypeFilter copy() {
DtTypeFilter filter = new DtTypeFilter(name);
filter.isTypeActive = isTypeActive;
filter.isTypeDefActive = isTypeDefActive;
return filter;
}
public String getName() {
return name;
}
public boolean isTypeActive() {
return isTypeActive;
}
public boolean isTypeDefActive() {
return isTypeDefActive;
}
public void setTypeActive(boolean b) {
this.isTypeActive = b;
}
public void setTypeDefActive(boolean b) {
this.isTypeDefActive = b;
}
@Override
public String toString() {
return Json.toString(this);
}
@Override
public int hashCode() {
return Objects.hash(isTypeActive, isTypeDefActive, name);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
DtTypeFilter other = (DtTypeFilter) obj;
return isTypeActive == other.isTypeActive && isTypeDefActive == other.isTypeDefActive &&
Objects.equals(name, other.name);
}
}

View file

@ -166,6 +166,14 @@ public class DataTypeManagerPluginTest extends AbstractGhidraHeadedIntegrationTe
myStruct.setCategoryPath(cat2Path);
builder.addDataType(myStruct);
TypedefDataType typeDefMyStruct = new TypedefDataType("TypeDefToMyStruct", myStruct);
builder.addDataType(typeDefMyStruct);
Pointer16DataType ptr16 = new Pointer16DataType(new CharDataType());
builder.addDataType(ptr16);
ArrayDataType charDt = new ArrayDataType(new CharDataType(), 10);
builder.addDataType(charDt);
return builder.getProgram();
}
@ -912,20 +920,51 @@ public class DataTypeManagerPluginTest extends AbstractGhidraHeadedIntegrationTe
}
@Test
public void testFilter() {
public void testFilter_DefaultFilter() {
DtFilterState filterState = provider.getFilterState();
assertFalse(filterState.getArraysFilter().isTypeActive());
assertFalse(filterState.getPointersFilter().isTypeActive());
DataTypeManager[] dtms = plugin.getDataTypeManagers();
for (DataTypeManager dtm : dtms) {
if (dtm instanceof BuiltInDataTypeManager) {
assertAllTypesInTree(dtm);
}
else {
assertNoArrays(dtm);
assertNoPointers(dtm);
}
}
}
@Test
public void testFilter_Structures() {
assertStructures(true);
assertType("TypeDefToMyStruct", true);
// press the filter button
DockingActionIf action = getAction(plugin, "Show Filter");
performAction(action, provider, false);
assertStructures(true);
DtFilterDialog dialog = waitForDialogComponent(DtFilterDialog.class);
setToggleButtonSelected(dialog.getComponent(), "Show Structures", false);
setToggleButtonSelected(dialog.getComponent(), "Structures", false);
pressButtonByText(dialog, "OK");
waitForTree();
assertStructures(false);
assertType("TypeDefToMyStruct", true);
// Now also turn off typedefs
performAction(action, provider, false);
dialog = waitForDialogComponent(DtFilterDialog.class);
setToggleButtonSelected(dialog.getComponent(), "StructuresTypedefs", false);
pressButtonByText(dialog, "OK");
waitForTree();
assertStructures(false);
assertType("TypeDefToMyStruct", false);
}
@Test
@ -935,7 +974,7 @@ public class DataTypeManagerPluginTest extends AbstractGhidraHeadedIntegrationTe
// press the filter button
DtFilterDialog mainDialog = showFilterDialog(provider);
boolean isShowingStructures = false;
updateFilter(mainDialog, "Show Structures", isShowingStructures);
updateFilter(mainDialog, "Structures", isShowingStructures);
//
// Launch a new data types provider window to verify it has the same settings as the main
@ -954,7 +993,7 @@ public class DataTypeManagerPluginTest extends AbstractGhidraHeadedIntegrationTe
// now change the new provider's filter for a different option and then make sure that the
// main provider is not changed
updateFilter(otherFilterDialog, "Show Functions", false);
updateFilter(otherFilterDialog, "Functions", false);
DtFilterState mainFilterState = runSwing(() -> provider.getFilterState());
DtFilterState otherFilterState = runSwing(() -> otherProvider.getFilterState());
@ -967,11 +1006,11 @@ public class DataTypeManagerPluginTest extends AbstractGhidraHeadedIntegrationTe
public void testSaveRestoreFilterStates() throws Exception {
DtFilterDialog dialog = showFilterDialog(provider);
boolean isShowingEnums = getFilterState(dialog, "Show Enums");
boolean isShowingUnions = getFilterState(dialog, "Show Unions");
boolean isShowingEnums = getFilterState(dialog, "Enums");
boolean isShowingUnions = getFilterState(dialog, "Unions");
setToggleButtonSelected(dialog.getComponent(), "Show Enums", !isShowingEnums);
setToggleButtonSelected(dialog.getComponent(), "Show Unions", !isShowingUnions);
setToggleButtonSelected(dialog.getComponent(), "Enums", !isShowingEnums);
setToggleButtonSelected(dialog.getComponent(), "Unions", !isShowingUnions);
pressButtonByText(dialog, "OK");
waitForSwing();
@ -988,6 +1027,88 @@ public class DataTypeManagerPluginTest extends AbstractGhidraHeadedIntegrationTe
// Private methods
//==================================================================================================
private void assertNoArrays(DataTypeManager dtm) {
Map<String, DataTypeNode> nodesByName = getNodes(dtm);
Collection<DataTypeNode> values = nodesByName.values();
for (DataTypeNode node : values) {
DataType dt = node.getDataType();
assertTrue("Found an array in '%s'".formatted(dtm.getName()),
!(dt instanceof Array));
}
}
private void assertNoPointers(DataTypeManager dtm) {
Map<String, DataTypeNode> nodesByName = getNodes(dtm);
Collection<DataTypeNode> values = nodesByName.values();
for (DataTypeNode node : values) {
DataType dt = node.getDataType();
assertTrue("Found a pointer in '%s'".formatted(dtm.getName()),
!(dt instanceof Pointer));
}
}
private void assertAllTypesInTree(DataTypeManager dtm) {
Iterator<DataType> types = dtm.getAllDataTypes();
Map<String, DataTypeNode> nodesByName = getNodes(dtm);
for (DataType dt : CollectionUtils.asIterable(types)) {
assertNotNull(
"Node not found for type '%s' in dtm '%s'".formatted(dt.getName(), dtm.getName()),
nodesByName.get(dt.getName()));
}
}
private Map<String, DataTypeNode> getNodes(DataTypeManager dtm) {
DataTypeArchiveGTree gTree = provider.getGTree();
GTreeNode rootNode = gTree.getViewRoot();
GTreeNode dtmNode = rootNode.getChild(dtm.getName());
assertNotNull(dtmNode);
expandNode(dtmNode);
Map<String, DataTypeNode> nodesByName = new HashMap<>();
Iterator<GTreeNode> it = dtmNode.iterator(true);
for (GTreeNode node : CollectionUtils.asIterable(it)) {
if (!(node instanceof DataTypeNode)) {
continue;
}
DataTypeNode dtNode = (DataTypeNode) node;
DataType dt = dtNode.getDataType();
nodesByName.put(dt.getName(), dtNode);
}
return nodesByName;
}
private void assertType(String name, boolean isShowing) {
DataType dt = getTypeFromTree(name);
if (isShowing) {
assertNotNull("Data type not found: '%s'", dt);
}
else {
assertNull(dt);
}
}
private DataType getTypeFromTree(String name) {
DataTypeArchiveGTree gTree = provider.getGTree();
GTreeNode rootNode = gTree.getViewRoot();
Iterator<GTreeNode> it = rootNode.iterator(true);
for (GTreeNode node : CollectionUtils.asIterable(it)) {
if (!(node instanceof DataTypeNode)) {
continue;
}
DataTypeNode dtNode = (DataTypeNode) node;
DataType dt = dtNode.getDataType();
String dtName = dt.getName();
if (dtName.equals(name)) {
return dt;
}
}
return null;
}
private boolean getFilterState(DtFilterDialog dialog, String optionName) {
return isToggleButttonSelected(dialog.getComponent(), optionName);
}
@ -1265,7 +1386,7 @@ public class DataTypeManagerPluginTest extends AbstractGhidraHeadedIntegrationTe
performAction(action, provider, false);
DtFilterDialog dialog = waitForDialogComponent(DtFilterDialog.class);
setToggleButtonSelected(dialog.getComponent(), "Show Pointers", true);
setToggleButtonSelected(dialog.getComponent(), "Pointers", true);
pressButtonByText(dialog, "OK");
waitForTree();
}

View file

@ -383,7 +383,8 @@ public class GoToAddressLabelPluginTest extends AbstractGhidraHeadedIntegrationT
// The default space and 'Test Overlay 1' each have an address for 1002000. The
// 'Test Overlay 2' does not. So, put the cursor there.
String name = overlay2Block.getName();
assertTrue(cbPlugin.goTo(new ProgramLocation(program, addr(name + "::1003000"))));
ProgramLocation location = new ProgramLocation(program, addr(name + "::1003000"));
assertTrue(cbPlugin.goTo(location));
showDialog();
setText("1002000");

View file

@ -494,9 +494,7 @@ public class GProperties {
*/
public Element saveToXml() {
Element root = new Element(propertiesName);
Iterator<String> iter = map.keySet().iterator();
while (iter.hasNext()) {
String key = iter.next();
for (String key : map.keySet()) {
Object value = map.get(key);
Element elem = createElement(key, value);
root.addContent(elem);
@ -638,9 +636,7 @@ public class GProperties {
JsonObject types = new JsonObject();
JsonObject values = new JsonObject();
JsonObject enumClasses = new JsonObject();
Iterator<String> iter = map.keySet().iterator();
while (iter.hasNext()) {
String key = iter.next();
for (String key : map.keySet()) {
Object value = map.get(key);
if (value == null) {
types.addProperty(key, "null");
@ -835,15 +831,22 @@ public class GProperties {
}
/**
* Return the names of the properties in this GProperties.
* @return the names of the properties in this GProperties.
* Returns the name of this GProperties
* @return the name of this GProperties
*/
public String getName() {
return propertiesName;
}
/**
* Return the names of the properties in this GProperties
* @return the names of the properties in this GProperties
*/
public String[] getNames() {
String[] names = new String[map.size()];
int idx = 0;
Iterator<String> iter = map.keySet().iterator();
while (iter.hasNext()) {
names[idx] = iter.next();
for (String element : map.keySet()) {
names[idx] = element;
++idx;
}
return names;

View file

@ -114,6 +114,7 @@ public class SaveState extends XmlProperties {
return getAsType(name, null, SaveState.class);
}
@Override
protected void processElement(Element element) {
String tag = element.getName();

View file

@ -69,6 +69,7 @@ public interface FunctionDefinition extends DataType, FunctionSignature {
* @deprecated Use of {@link GenericCallingConvention} is deprecated since arbitrary calling
* convention names are now supported. {@link #setCallingConvention(String)} should be used.
*/
@Deprecated
public void setGenericCallingConvention(GenericCallingConvention genericCallingConvention);
/**