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

View file

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

View file

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

View file

@ -15,25 +15,29 @@
*/ */
package ghidra.app.plugin.core.datamgr.tree; 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.DialogComponentProvider;
import docking.widgets.button.GButton;
import docking.widgets.checkbox.GCheckBox; import docking.widgets.checkbox.GCheckBox;
import ghidra.app.util.HelpTopics; import ghidra.app.util.HelpTopics;
import ghidra.util.HelpLocation; import ghidra.util.HelpLocation;
import ghidra.util.layout.PairLayout;
/** /**
* Data Types provider dialog to allow users to change the types that are filtered. * Data Types provider dialog to allow users to change the types that are filtered.
*/ */
public class DtFilterDialog extends DialogComponentProvider { public class DtFilterDialog extends DialogComponentProvider {
private GCheckBox arraysCheckBox = new GCheckBox("Show Arrays"); private TypeComponent arraysComponent = new TypeComponent("Arrays");
private GCheckBox enumsCheckBox = new GCheckBox("Show Enums"); private TypeComponent enumsComponent = new TypeComponent("Enums");
private GCheckBox functionsCheckBox = new GCheckBox("Show Functions"); private TypeComponent functionsComponent = new TypeComponent("Functions");
private GCheckBox pointersCheckBox = new GCheckBox("Show Pointers"); private TypeComponent pointersComponent = new TypeComponent("Pointers");
private GCheckBox structuresCheckBox = new GCheckBox("Show Structures"); private TypeComponent structuresComponent = new TypeComponent("Structures");
private GCheckBox unionsCheckBox = new GCheckBox("Show Unions"); private TypeComponent unionsComponent = new TypeComponent("Unions");
private DtFilterState filterState; private DtFilterState filterState;
private boolean isCancelled; private boolean isCancelled;
@ -47,7 +51,7 @@ public class DtFilterDialog extends DialogComponentProvider {
addOKButton(); addOKButton();
addCancelButton(); addCancelButton();
setHelpLocation(new HelpLocation(HelpTopics.DATA_MANAGER, "Set Filter")); setHelpLocation(new HelpLocation(HelpTopics.DATA_MANAGER, "Show Filter"));
initCheckBoxes(); initCheckBoxes();
setRememberSize(false); setRememberSize(false);
@ -70,39 +74,136 @@ public class DtFilterDialog extends DialogComponentProvider {
public DtFilterState getFilterState() { public DtFilterState getFilterState() {
DtFilterState newState = new DtFilterState(); DtFilterState newState = new DtFilterState();
newState.setArraysFilter(arraysComponent.getFilter());
newState.setShowArrays(arraysCheckBox.isSelected()); newState.setEnumsFilter(enumsComponent.getFilter());
newState.setShowEnums(enumsCheckBox.isSelected()); newState.setFunctionsFilter(functionsComponent.getFilter());
newState.setShowFunctions(functionsCheckBox.isSelected()); newState.setPointersFilter(pointersComponent.getFilter());
newState.setShowPointers(pointersCheckBox.isSelected()); newState.setStructuresFilter(structuresComponent.getFilter());
newState.setShowStructures(structuresCheckBox.isSelected()); newState.setUnionsFilter(unionsComponent.getFilter());
newState.setShowUnions(unionsCheckBox.isSelected());
return newState; return newState;
} }
private JPanel buildWorkPanel() { private JPanel buildWorkPanel() {
JPanel panel = new JPanel(new PairLayout(5, 10)); JPanel panel = new JPanel();
panel.setLayout(new GridLayout(0, 2));
panel.add(arraysCheckBox); JLabel l1 = new JLabel("<html><b>Show");
panel.add(enumsCheckBox); l1.setHorizontalAlignment(SwingConstants.LEFT);
panel.add(functionsCheckBox); panel.add(l1);
panel.add(pointersCheckBox);
panel.add(structuresCheckBox); JLabel l2 = new JLabel("<html><b>Include Typedefs");
panel.add(unionsCheckBox); 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; return panel;
} }
private void initCheckBoxes() { private List<AbstractButton> allButtons() {
//@formatter:off
arraysCheckBox.setSelected(filterState.isShowArrays()); return List.of(
enumsCheckBox.setSelected(filterState.isShowEnums()); arraysComponent.typeCb,
functionsCheckBox.setSelected(filterState.isShowFunctions()); arraysComponent.typeDefCb,
pointersCheckBox.setSelected(filterState.isShowPointers()); enumsComponent.typeCb,
structuresCheckBox.setSelected(filterState.isShowStructures()); enumsComponent.typeDefCb,
unionsCheckBox.setSelected(filterState.isShowUnions()); functionsComponent.typeCb,
functionsComponent.typeDefCb,
pointersComponent.typeCb,
pointersComponent.typeDefCb,
structuresComponent.typeCb,
structuresComponent.typeDefCb,
unionsComponent.typeCb,
unionsComponent.typeDefCb
);
//@formatter:on
} }
private void initCheckBoxes() {
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 java.util.Objects;
import ghidra.app.plugin.core.datamgr.util.DataTypeUtils;
import ghidra.framework.options.SaveState; 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. * 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 static final String XML_NAME = "DATA_TYPES_FILTER";
private boolean showArrays = false; private DtTypeFilter arraysFilter = new DtTypeFilter("Arrays");
private boolean showEnums = true; private DtTypeFilter enumsFilter = new DtTypeFilter("Enums");
private boolean showFunctions = true; private DtTypeFilter functionsFilter = new DtTypeFilter("Functions");
private boolean showStructures = true; private DtTypeFilter structuresFilter = new DtTypeFilter("Structures");
private boolean showTypedefs = true; private DtTypeFilter pointersFilter = new DtTypeFilter("Pointers");
private boolean showPointers = false; private DtTypeFilter unionsFilter = new DtTypeFilter("Unions");
private boolean showUnions = true;
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() { public DtFilterState copy() {
DtFilterState filterState = new DtFilterState(); DtFilterState filterState = new DtFilterState();
filterState.setShowArrays(showArrays); filterState.arraysFilter = arraysFilter.copy();
filterState.setShowEnums(showEnums); filterState.enumsFilter = enumsFilter.copy();
filterState.setShowFunctions(showFunctions); filterState.functionsFilter = functionsFilter.copy();
filterState.setShowStructures(showStructures); filterState.structuresFilter = structuresFilter.copy();
filterState.setShowTypedefs(showTypedefs); filterState.pointersFilter = pointersFilter.copy();
filterState.setShowPointers(showPointers); filterState.unionsFilter = unionsFilter.copy();
filterState.setShowUnions(showUnions);
return filterState; return filterState;
} }
public boolean isShowPointers() { public boolean isShowArrays() {
return showPointers; return arraysFilter.isTypeActive();
} }
public void setShowPointers(boolean showPointers) { public DtTypeFilter getArraysFilter() {
this.showPointers = showPointers; return arraysFilter;
} }
public boolean isShowStructures() { public void setArraysFilter(DtTypeFilter filter) {
return showStructures; this.arraysFilter = filter;
}
public void setShowStructures(boolean showStructures) {
this.showStructures = showStructures;
}
public boolean isShowTypedefs() {
return showStructures;
}
public void setShowTypedefs(boolean showTypedefs) {
this.showTypedefs = showTypedefs;
} }
public boolean isShowEnums() { public boolean isShowEnums() {
return showEnums; return enumsFilter.isTypeActive();
} }
public void setShowEnums(boolean showEnums) { public DtTypeFilter getEnumsFilter() {
this.showEnums = showEnums; return enumsFilter;
}
public void setEnumsFilter(DtTypeFilter filter) {
this.enumsFilter = filter;
} }
public boolean isShowFunctions() { public boolean isShowFunctions() {
return showFunctions; return functionsFilter.isTypeActive();
} }
public void setShowFunctions(boolean showFunctions) { public DtTypeFilter getFunctionsFilter() {
this.showFunctions = showFunctions; 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() { public boolean isShowUnions() {
return showUnions; return unionsFilter.isTypeActive();
} }
public void setShowUnions(boolean showUnions) { public DtTypeFilter getUnionsFilter() {
this.showUnions = showUnions; return unionsFilter;
} }
public boolean isShowArrays() { public void setUnionsFilter(DtTypeFilter filter) {
return showArrays; this.unionsFilter = filter;
} }
public void setShowArrays(boolean showArrays) { public boolean passesFilters(DataType dt) {
this.showArrays = showArrays;
DataTypeManager dtm = dt.getDataTypeManager();
if (dtm instanceof BuiltInDataTypeManager) {
// never filter built-in types here; users can filter them using the text filter
return true;
}
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;
} }
public void setshowPointers(boolean showPointers) { private boolean passes(DtTypeFilter filter, DataType dt, DataType baseDt) {
this.showPointers = showPointers; if (filter.isTypeActive()) {
return true;
}
if (filter.isTypeDefActive() && dt instanceof TypeDef) {
return true;
}
return false;
} }
public void save(SaveState parentSaveState) { public void save(SaveState parentSaveState) {
SaveState saveState = new SaveState(XML_NAME); SaveState ss = new SaveState(XML_NAME);
saveState.putBoolean("SHOW_ARRAYS", showArrays); ss.putSaveState(arraysFilter.getName(), arraysFilter.save());
saveState.putBoolean("SHOW_ENUMS", showEnums); ss.putSaveState(enumsFilter.getName(), enumsFilter.save());
saveState.putBoolean("SHOW_FUNCTIONS", showFunctions); ss.putSaveState(functionsFilter.getName(), functionsFilter.save());
saveState.putBoolean("SHOW_POINTERS", showPointers); ss.putSaveState(pointersFilter.getName(), pointersFilter.save());
saveState.putBoolean("SHOW_STRUCTURES", showStructures); ss.putSaveState(structuresFilter.getName(), structuresFilter.save());
saveState.putBoolean("SHOW_TYPEDEFS", showTypedefs); ss.putSaveState(unionsFilter.getName(), unionsFilter.save());
saveState.putBoolean("SHOW_UNIONS", showUnions);
parentSaveState.putSaveState(XML_NAME, saveState); parentSaveState.putSaveState(XML_NAME, ss);
} }
public void restore(SaveState parentSaveState) { public void restore(SaveState parentSaveState) {
parentSaveState.getSaveState(XML_NAME); SaveState ss = parentSaveState.getSaveState(XML_NAME);
SaveState saveState = new SaveState();
showArrays = saveState.getBoolean("SHOW_ARRAYS", false); arraysFilter = DtTypeFilter.restore("Arrays", ss.getSaveState("Arrays"));
showEnums = saveState.getBoolean("SHOW_ENUMS", true); enumsFilter = DtTypeFilter.restore("Enums", ss.getSaveState("Enums"));
showFunctions = saveState.getBoolean("SHOW_FUNCTIONS", true); functionsFilter = DtTypeFilter.restore("Functions", ss.getSaveState("Functions"));
showPointers = saveState.getBoolean("SHOW_POINTERS", false); pointersFilter = DtTypeFilter.restore("Pointers", ss.getSaveState("Pointers"));
showStructures = saveState.getBoolean("SHOW_STRUCTURES", true); structuresFilter = DtTypeFilter.restore("Structures", ss.getSaveState("Structures"));
showTypedefs = saveState.getBoolean("SHOW_TYPEDEFS", true); unionsFilter = DtTypeFilter.restore("Unions", ss.getSaveState("Unions"));
showUnions = saveState.getBoolean("SHOW_UNIONS", true);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(showArrays, showEnums, showFunctions, showPointers, showStructures, return Objects.hash(arraysFilter, enumsFilter, functionsFilter, pointersFilter,
showTypedefs, showUnions); structuresFilter, unionsFilter);
} }
@Override @Override
@ -152,10 +216,12 @@ public class DtFilterState {
return false; return false;
} }
DtFilterState other = (DtFilterState) obj; DtFilterState other = (DtFilterState) obj;
return showArrays == other.showArrays && showEnums == other.showEnums && return Objects.equals(arraysFilter, other.arraysFilter) &&
showFunctions == other.showFunctions && showPointers == other.showPointers && Objects.equals(enumsFilter, other.enumsFilter) &&
showStructures == other.showStructures && showTypedefs == other.showTypedefs && Objects.equals(functionsFilter, other.functionsFilter) &&
showUnions == other.showUnions; 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); myStruct.setCategoryPath(cat2Path);
builder.addDataType(myStruct); 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(); return builder.getProgram();
} }
@ -912,20 +920,51 @@ public class DataTypeManagerPluginTest extends AbstractGhidraHeadedIntegrationTe
} }
@Test @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 // press the filter button
DockingActionIf action = getAction(plugin, "Show Filter"); DockingActionIf action = getAction(plugin, "Show Filter");
performAction(action, provider, false); performAction(action, provider, false);
assertStructures(true);
DtFilterDialog dialog = waitForDialogComponent(DtFilterDialog.class); DtFilterDialog dialog = waitForDialogComponent(DtFilterDialog.class);
setToggleButtonSelected(dialog.getComponent(), "Show Structures", false); setToggleButtonSelected(dialog.getComponent(), "Structures", false);
pressButtonByText(dialog, "OK"); pressButtonByText(dialog, "OK");
waitForTree(); waitForTree();
assertStructures(false); 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 @Test
@ -935,7 +974,7 @@ public class DataTypeManagerPluginTest extends AbstractGhidraHeadedIntegrationTe
// press the filter button // press the filter button
DtFilterDialog mainDialog = showFilterDialog(provider); DtFilterDialog mainDialog = showFilterDialog(provider);
boolean isShowingStructures = false; 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 // 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 // now change the new provider's filter for a different option and then make sure that the
// main provider is not changed // main provider is not changed
updateFilter(otherFilterDialog, "Show Functions", false); updateFilter(otherFilterDialog, "Functions", false);
DtFilterState mainFilterState = runSwing(() -> provider.getFilterState()); DtFilterState mainFilterState = runSwing(() -> provider.getFilterState());
DtFilterState otherFilterState = runSwing(() -> otherProvider.getFilterState()); DtFilterState otherFilterState = runSwing(() -> otherProvider.getFilterState());
@ -967,11 +1006,11 @@ public class DataTypeManagerPluginTest extends AbstractGhidraHeadedIntegrationTe
public void testSaveRestoreFilterStates() throws Exception { public void testSaveRestoreFilterStates() throws Exception {
DtFilterDialog dialog = showFilterDialog(provider); DtFilterDialog dialog = showFilterDialog(provider);
boolean isShowingEnums = getFilterState(dialog, "Show Enums"); boolean isShowingEnums = getFilterState(dialog, "Enums");
boolean isShowingUnions = getFilterState(dialog, "Show Unions"); boolean isShowingUnions = getFilterState(dialog, "Unions");
setToggleButtonSelected(dialog.getComponent(), "Show Enums", !isShowingEnums); setToggleButtonSelected(dialog.getComponent(), "Enums", !isShowingEnums);
setToggleButtonSelected(dialog.getComponent(), "Show Unions", !isShowingUnions); setToggleButtonSelected(dialog.getComponent(), "Unions", !isShowingUnions);
pressButtonByText(dialog, "OK"); pressButtonByText(dialog, "OK");
waitForSwing(); waitForSwing();
@ -988,6 +1027,88 @@ public class DataTypeManagerPluginTest extends AbstractGhidraHeadedIntegrationTe
// Private methods // 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) { private boolean getFilterState(DtFilterDialog dialog, String optionName) {
return isToggleButttonSelected(dialog.getComponent(), optionName); return isToggleButttonSelected(dialog.getComponent(), optionName);
} }
@ -1265,7 +1386,7 @@ public class DataTypeManagerPluginTest extends AbstractGhidraHeadedIntegrationTe
performAction(action, provider, false); performAction(action, provider, false);
DtFilterDialog dialog = waitForDialogComponent(DtFilterDialog.class); DtFilterDialog dialog = waitForDialogComponent(DtFilterDialog.class);
setToggleButtonSelected(dialog.getComponent(), "Show Pointers", true); setToggleButtonSelected(dialog.getComponent(), "Pointers", true);
pressButtonByText(dialog, "OK"); pressButtonByText(dialog, "OK");
waitForTree(); 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 // The default space and 'Test Overlay 1' each have an address for 1002000. The
// 'Test Overlay 2' does not. So, put the cursor there. // 'Test Overlay 2' does not. So, put the cursor there.
String name = overlay2Block.getName(); 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(); showDialog();
setText("1002000"); setText("1002000");

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -494,9 +494,7 @@ public class GProperties {
*/ */
public Element saveToXml() { public Element saveToXml() {
Element root = new Element(propertiesName); Element root = new Element(propertiesName);
Iterator<String> iter = map.keySet().iterator(); for (String key : map.keySet()) {
while (iter.hasNext()) {
String key = iter.next();
Object value = map.get(key); Object value = map.get(key);
Element elem = createElement(key, value); Element elem = createElement(key, value);
root.addContent(elem); root.addContent(elem);
@ -638,9 +636,7 @@ public class GProperties {
JsonObject types = new JsonObject(); JsonObject types = new JsonObject();
JsonObject values = new JsonObject(); JsonObject values = new JsonObject();
JsonObject enumClasses = new JsonObject(); JsonObject enumClasses = new JsonObject();
Iterator<String> iter = map.keySet().iterator(); for (String key : map.keySet()) {
while (iter.hasNext()) {
String key = iter.next();
Object value = map.get(key); Object value = map.get(key);
if (value == null) { if (value == null) {
types.addProperty(key, "null"); types.addProperty(key, "null");
@ -835,15 +831,22 @@ public class GProperties {
} }
/** /**
* Return the names of the properties in this GProperties. * Returns the name of this GProperties
* @return the names of the properties in 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() { public String[] getNames() {
String[] names = new String[map.size()]; String[] names = new String[map.size()];
int idx = 0; int idx = 0;
Iterator<String> iter = map.keySet().iterator(); for (String element : map.keySet()) {
while (iter.hasNext()) { names[idx] = element;
names[idx] = iter.next();
++idx; ++idx;
} }
return names; return names;

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -114,6 +114,7 @@ public class SaveState extends XmlProperties {
return getAsType(name, null, SaveState.class); return getAsType(name, null, SaveState.class);
} }
@Override
protected void processElement(Element element) { protected void processElement(Element element) {
String tag = element.getName(); 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 * @deprecated Use of {@link GenericCallingConvention} is deprecated since arbitrary calling
* convention names are now supported. {@link #setCallingConvention(String)} should be used. * convention names are now supported. {@link #setCallingConvention(String)} should be used.
*/ */
@Deprecated
public void setGenericCallingConvention(GenericCallingConvention genericCallingConvention); public void setGenericCallingConvention(GenericCallingConvention genericCallingConvention);
/** /**