mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 19:42:36 +02:00
GT-2844 - Data Type Preview - fixed bug that cased rendering failure in
table
This commit is contained in:
parent
c4bbff8195
commit
85a1017102
5 changed files with 82 additions and 74 deletions
|
@ -51,6 +51,7 @@ class DataTypePreview implements Preview {
|
||||||
return dt.getRepresentation(mb, new SettingsImpl(), length);
|
return dt.getRepresentation(mb, new SettingsImpl(), length);
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
|
|
||||||
return "ERROR: unable to create preview";
|
return "ERROR: unable to create preview";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,8 +47,9 @@ import ghidra.util.HelpLocation;
|
||||||
import ghidra.util.data.DataTypeParser.AllowedDataTypes;
|
import ghidra.util.data.DataTypeParser.AllowedDataTypes;
|
||||||
import ghidra.util.table.GhidraTable;
|
import ghidra.util.table.GhidraTable;
|
||||||
import ghidra.util.task.SwingUpdateManager;
|
import ghidra.util.task.SwingUpdateManager;
|
||||||
import ghidra.util.task.TaskMonitorAdapter;
|
import ghidra.util.task.TaskMonitor;
|
||||||
import resources.ResourceManager;
|
import resources.ResourceManager;
|
||||||
|
import util.CollectionUtils;
|
||||||
|
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
@PluginInfo(
|
@PluginInfo(
|
||||||
|
@ -56,7 +57,8 @@ import resources.ResourceManager;
|
||||||
packageName = CorePluginPackage.NAME,
|
packageName = CorePluginPackage.NAME,
|
||||||
category = PluginCategoryNames.CODE_VIEWER,
|
category = PluginCategoryNames.CODE_VIEWER,
|
||||||
shortDescription = "Data Type Preview Plugin",
|
shortDescription = "Data Type Preview Plugin",
|
||||||
description = "This plugin provides a preview of bytes at an address based on data types that you choose to view."
|
description = "This plugin provides a preview of bytes at an address based on data types " +
|
||||||
|
"that you choose to view."
|
||||||
)
|
)
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
public class DataTypePreviewPlugin extends ProgramPlugin {
|
public class DataTypePreviewPlugin extends ProgramPlugin {
|
||||||
|
@ -66,10 +68,10 @@ public class DataTypePreviewPlugin extends ProgramPlugin {
|
||||||
private DTPPTable table;
|
private DTPPTable table;
|
||||||
private DTPPScrollPane component;
|
private DTPPScrollPane component;
|
||||||
private Address currentAddress;
|
private Address currentAddress;
|
||||||
private GoToService gotoService;
|
private GoToService goToService;
|
||||||
private DockingAction addAction;
|
private DockingAction addAction;
|
||||||
private DockingAction deleteAction;
|
private DockingAction deleteAction;
|
||||||
private DataTypeManager dataTypeMgr;
|
private DataTypeManager dataTypeManager;
|
||||||
private Program activeProgram;
|
private Program activeProgram;
|
||||||
|
|
||||||
private SwingUpdateManager updateManager = new SwingUpdateManager(650, () -> updatePreview());
|
private SwingUpdateManager updateManager = new SwingUpdateManager(650, () -> updatePreview());
|
||||||
|
@ -83,7 +85,7 @@ public class DataTypePreviewPlugin extends ProgramPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
GoToService getGoToService() {
|
GoToService getGoToService() {
|
||||||
return gotoService;
|
return goToService;
|
||||||
}
|
}
|
||||||
|
|
||||||
DTPPComponentProvider getProvider() {
|
DTPPComponentProvider getProvider() {
|
||||||
|
@ -94,12 +96,12 @@ public class DataTypePreviewPlugin extends ProgramPlugin {
|
||||||
protected void init() {
|
protected void init() {
|
||||||
super.init();
|
super.init();
|
||||||
|
|
||||||
gotoService = tool.getService(GoToService.class);
|
goToService = tool.getService(GoToService.class);
|
||||||
|
|
||||||
model = new DTPPTableModel();
|
model = new DTPPTableModel();
|
||||||
table = new DTPPTable(model);
|
table = new DTPPTable(model);
|
||||||
component = new DTPPScrollPane(table);
|
component = new DTPPScrollPane(table);
|
||||||
dataTypeMgr = new LayeredDataTypeManager();
|
dataTypeManager = new LayeredDataTypeManager();
|
||||||
|
|
||||||
addDataType(new ByteDataType());
|
addDataType(new ByteDataType());
|
||||||
addDataType(new WordDataType());
|
addDataType(new WordDataType());
|
||||||
|
@ -117,6 +119,20 @@ public class DataTypePreviewPlugin extends ProgramPlugin {
|
||||||
createActions();
|
createActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void serviceRemoved(Class<?> interfaceClass, Object service) {
|
||||||
|
if (interfaceClass == GoToService.class) {
|
||||||
|
goToService = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void serviceAdded(Class<?> interfaceClass, Object service) {
|
||||||
|
if (interfaceClass == GoToService.class) {
|
||||||
|
goToService = (GoToService) service;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void dispose() {
|
protected void dispose() {
|
||||||
updateManager.dispose();
|
updateManager.dispose();
|
||||||
|
@ -141,9 +157,9 @@ public class DataTypePreviewPlugin extends ProgramPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateModel() {
|
void updateModel() {
|
||||||
int transactionId = dataTypeMgr.startTransaction("realign");
|
int transactionId = dataTypeManager.startTransaction("realign");
|
||||||
try {
|
try {
|
||||||
Iterator<Composite> allComposites = dataTypeMgr.getAllComposites();
|
Iterator<Composite> allComposites = dataTypeManager.getAllComposites();
|
||||||
while (allComposites.hasNext()) {
|
while (allComposites.hasNext()) {
|
||||||
Composite composite = allComposites.next();
|
Composite composite = allComposites.next();
|
||||||
if (composite.isInternallyAligned()) {
|
if (composite.isInternallyAligned()) {
|
||||||
|
@ -154,7 +170,7 @@ public class DataTypePreviewPlugin extends ProgramPlugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
dataTypeMgr.endTransaction(transactionId, true);
|
dataTypeManager.endTransaction(transactionId, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,9 +220,10 @@ public class DataTypePreviewPlugin extends ProgramPlugin {
|
||||||
@Override
|
@Override
|
||||||
public void readConfigState(SaveState saveState) {
|
public void readConfigState(SaveState saveState) {
|
||||||
String[] names = saveState.getNames();
|
String[] names = saveState.getNames();
|
||||||
if (names == null || names.length == 0) {
|
if (CollectionUtils.isBlank(names)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
BuiltInDataTypeManager builtInMgr = BuiltInDataTypeManager.getDataTypeManager();
|
BuiltInDataTypeManager builtInMgr = BuiltInDataTypeManager.getDataTypeManager();
|
||||||
try {
|
try {
|
||||||
for (String element : names) {
|
for (String element : names) {
|
||||||
|
@ -214,12 +231,9 @@ public class DataTypePreviewPlugin extends ProgramPlugin {
|
||||||
if (path == null) {
|
if (path == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataType dt = builtInMgr.getDataType(new CategoryPath(path), element);
|
DataType dt = builtInMgr.getDataType(new CategoryPath(path), element);
|
||||||
if (dt != null) {
|
addDataType(dt);
|
||||||
if (!model.contains(dt)) {
|
|
||||||
addDataType(dt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
@ -233,9 +247,7 @@ public class DataTypePreviewPlugin extends ProgramPlugin {
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
Preview preview = iter.next();
|
Preview preview = iter.next();
|
||||||
DataType dt = preview.getDataType();
|
DataType dt = preview.getDataType();
|
||||||
if (dt instanceof BuiltIn) {
|
saveState.putString(dt.getName(), dt.getCategoryPath().getPath());
|
||||||
saveState.putString(dt.getName(), dt.getCategoryPath().getPath());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,32 +297,38 @@ public class DataTypePreviewPlugin extends ProgramPlugin {
|
||||||
AllowedDataTypes.FIXED_LENGTH);
|
AllowedDataTypes.FIXED_LENGTH);
|
||||||
tool.showDialog(d, provider);
|
tool.showDialog(d, provider);
|
||||||
DataType dt = d.getUserChosenDataType();
|
DataType dt = d.getUserChosenDataType();
|
||||||
if (dt != null) {
|
addDataType(dt);
|
||||||
addDataType(dt);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void addDataType(DataType dt) {
|
void addDataType(DataType dt) {
|
||||||
int transactionID = dataTypeMgr.startTransaction("Add dataType");
|
|
||||||
|
if (dt == null || model.contains(dt)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int transactionID = dataTypeManager.startTransaction("Add dataType");
|
||||||
try {
|
try {
|
||||||
DataType resolvedDt = dataTypeMgr.resolve(dt, null);
|
DataType resolvedDt = dataTypeManager.resolve(dt, null);
|
||||||
model.add(resolvedDt);
|
model.add(resolvedDt);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
dataTypeMgr.endTransaction(transactionID, true);
|
dataTypeManager.endTransaction(transactionID, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeDataType(DataType dt) {
|
private void removeDataType(DataType dt) {
|
||||||
int transactionID = dataTypeMgr.startTransaction("Remove dataType");
|
int transactionID = dataTypeManager.startTransaction("Remove dataType");
|
||||||
try {
|
try {
|
||||||
model.removeAll(dt);
|
model.removeAll(dt);
|
||||||
dataTypeMgr.remove(dt, null);
|
|
||||||
|
// Note: do not do this, as there may be user-added composites that are based on
|
||||||
|
// the type being removed. For now, let the 'fake' DTM grow forever (this should
|
||||||
|
// never become a problem).
|
||||||
|
// dataTypeManager.remove(dt, null);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
dataTypeMgr.endTransaction(transactionID, true);
|
dataTypeManager.endTransaction(transactionID, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void delete() {
|
private void delete() {
|
||||||
|
@ -431,8 +449,13 @@ public class DataTypePreviewPlugin extends ProgramPlugin {
|
||||||
if (queryString == null) {
|
if (queryString == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
gotoService.goToQuery(currentAddress, new QueryData(queryString, false), null,
|
|
||||||
TaskMonitorAdapter.DUMMY_MONITOR);
|
if (goToService == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
goToService.goToQuery(currentAddress, new QueryData(queryString, false), null,
|
||||||
|
TaskMonitor.DUMMY);
|
||||||
}
|
}
|
||||||
table.handleTableSelection();
|
table.handleTableSelection();
|
||||||
}
|
}
|
||||||
|
@ -442,7 +465,7 @@ public class DataTypePreviewPlugin extends ProgramPlugin {
|
||||||
final static int NAME_COL = 0;
|
final static int NAME_COL = 0;
|
||||||
final static int PREVIEW_COL = 1;
|
final static int PREVIEW_COL = 1;
|
||||||
|
|
||||||
private ArrayList<Preview> data = new ArrayList<>();
|
private List<Preview> data = new ArrayList<>();
|
||||||
|
|
||||||
String getPreviewAt(int row) {
|
String getPreviewAt(int row) {
|
||||||
if (currentProgram == null) {
|
if (currentProgram == null) {
|
||||||
|
@ -530,28 +553,7 @@ public class DataTypePreviewPlugin extends ProgramPlugin {
|
||||||
return removed;
|
return removed;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean removeAll(CategoryPath deletedDataTypePath) {
|
private boolean isValid(DataType dt) {
|
||||||
boolean removed = false;
|
|
||||||
String dtName = deletedDataTypePath.getName();
|
|
||||||
CategoryPath dtParent = deletedDataTypePath.getParent();
|
|
||||||
ArrayList<Preview> clone = new ArrayList<>(data);
|
|
||||||
Iterator<Preview> iter = clone.iterator();
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
Object obj = iter.next();
|
|
||||||
Preview preview = (Preview) obj;
|
|
||||||
DataType dt = preview.getDataType();
|
|
||||||
if (dt.getName().equals(dtName) && dt.getCategoryPath().equals(dtParent)) {
|
|
||||||
data.remove(preview);
|
|
||||||
removed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (removed) {
|
|
||||||
fireTableDataChanged();
|
|
||||||
}
|
|
||||||
return removed;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isValid(DataType dt) {
|
|
||||||
if (dt == null) {
|
if (dt == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -571,7 +573,7 @@ public class DataTypePreviewPlugin extends ProgramPlugin {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean contains(DataType dt) {
|
private boolean contains(DataType dt) {
|
||||||
Iterator<Preview> iter = data.iterator();
|
Iterator<Preview> iter = data.iterator();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
Preview p = iter.next();
|
Preview p = iter.next();
|
||||||
|
@ -677,7 +679,7 @@ public class DataTypePreviewPlugin extends ProgramPlugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class LayeredDataTypeManager extends StandAloneDataTypeManager {
|
private class LayeredDataTypeManager extends StandAloneDataTypeManager {
|
||||||
|
|
||||||
public LayeredDataTypeManager() {
|
public LayeredDataTypeManager() {
|
||||||
super("DataTypePreviewer");
|
super("DataTypePreviewer");
|
||||||
|
|
|
@ -23,6 +23,7 @@ import java.util.Objects;
|
||||||
import javax.swing.SwingConstants;
|
import javax.swing.SwingConstants;
|
||||||
|
|
||||||
import ghidra.util.SystemUtilities;
|
import ghidra.util.SystemUtilities;
|
||||||
|
import util.CollectionUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A builder object that allows clients to launch tasks in the background, with a progress
|
* A builder object that allows clients to launch tasks in the background, with a progress
|
||||||
|
@ -137,7 +138,7 @@ public class TaskBuilder {
|
||||||
* @return this builder
|
* @return this builder
|
||||||
*/
|
*/
|
||||||
public TaskBuilder setStatusTextAlignment(int alignment) {
|
public TaskBuilder setStatusTextAlignment(int alignment) {
|
||||||
boolean isValid = SystemUtilities.isOneOf(alignment, LEADING, CENTER, TRAILING);
|
boolean isValid = CollectionUtils.isOneOf(alignment, LEADING, CENTER, TRAILING);
|
||||||
SystemUtilities.assertTrue(isValid, "Illegal alignment argument: " + alignment);
|
SystemUtilities.assertTrue(isValid, "Illegal alignment argument: " + alignment);
|
||||||
|
|
||||||
this.statusTextAlignment = alignment;
|
this.statusTextAlignment = alignment;
|
||||||
|
|
|
@ -365,6 +365,27 @@ public class CollectionUtils {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given array is null or has 0 length
|
||||||
|
*
|
||||||
|
* @param c the collection to check
|
||||||
|
* @return true if blank
|
||||||
|
*/
|
||||||
|
public static <T> boolean isBlank(Collection<T> c) {
|
||||||
|
return c == null || c.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given array is null or has 0 length
|
||||||
|
*
|
||||||
|
* @param t the items to check
|
||||||
|
* @return true if blank
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <T> boolean isBlank(T... t) {
|
||||||
|
return t == null || t.length == 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Turns the given item into an iterable
|
* Turns the given item into an iterable
|
||||||
* @param t the object from which to create an iterable
|
* @param t the object from which to create an iterable
|
||||||
|
|
|
@ -341,23 +341,6 @@ public class SystemUtilities {
|
||||||
return Objects.equals(o1, o2);
|
return Objects.equals(o1, o2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the given element is equals to one of the provided elements.
|
|
||||||
*
|
|
||||||
* @param o the element to test
|
|
||||||
* @param others the potential matches
|
|
||||||
* @return true if the given element is equals to one of the provided elements.
|
|
||||||
*/
|
|
||||||
@SafeVarargs // we are not using the provided type, so there is no pollution
|
|
||||||
public static <T> boolean isOneOf(T o, T... others) {
|
|
||||||
for (T t : others) {
|
|
||||||
if (o.equals(t)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T extends Comparable<T>> int compareTo(T c1, T c2) {
|
public static <T extends Comparable<T>> int compareTo(T c1, T c2) {
|
||||||
if (c1 == null) {
|
if (c1 == null) {
|
||||||
return c2 == null ? 0 : 1;
|
return c2 == null ? 0 : 1;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue