mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 09:49:23 +02:00
Merge remote-tracking branch 'origin/GP-1-dragonmacher-dt-filter-updates--SQUASHED'
This commit is contained in:
commit
9a7d3eb93f
11 changed files with 545 additions and 172 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 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());
|
||||
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() {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
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) {
|
||||
this.showPointers = showPointers;
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue