mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
GT-3222 - Fixed bugs in Data Type navigation that caused failure after
opening and archive for edit
This commit is contained in:
parent
591ed4de31
commit
0b532431cd
9 changed files with 172 additions and 176 deletions
|
@ -205,9 +205,9 @@ public class DataTypeManagerPlugin extends ProgramPlugin
|
|||
}
|
||||
|
||||
/**
|
||||
* Add project pathname to recently opened list.
|
||||
* @param projectName
|
||||
* @param pathname
|
||||
* Add project archive name to recently opened list
|
||||
* @param projectName the project name
|
||||
* @param pathname the pathname
|
||||
*/
|
||||
public void addRecentlyOpenedProjectArchive(String projectName, String pathname) {
|
||||
String projectPathname = DataTypeManagerHandler.getProjectPathname(projectName, pathname);
|
||||
|
@ -239,8 +239,8 @@ public class DataTypeManagerPlugin extends ProgramPlugin
|
|||
|
||||
/**
|
||||
* Get a project archive file by project name and pathname
|
||||
* @param projectName
|
||||
* @param pathname
|
||||
* @param projectName the project name
|
||||
* @param pathname the project pathname
|
||||
* @return project archive domain file or null if it does not exist
|
||||
* or can not be found (e.g., projectName is not the active project)
|
||||
*/
|
||||
|
@ -272,10 +272,6 @@ public class DataTypeManagerPlugin extends ProgramPlugin
|
|||
dataTypeManagerHandler.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells the Plugin to read its data-independant (preferences)
|
||||
* properties from the input stream.
|
||||
*/
|
||||
@Override
|
||||
public void readConfigState(SaveState saveState) {
|
||||
dataTypeManagerHandler.restore(saveState);
|
||||
|
@ -311,10 +307,6 @@ public class DataTypeManagerPlugin extends ProgramPlugin
|
|||
dataTypePropertyManager.programClosed(program);
|
||||
}
|
||||
|
||||
/**
|
||||
* Program was opened.
|
||||
* @param program
|
||||
*/
|
||||
@Override
|
||||
protected void programActivated(Program program) {
|
||||
program.addListener(this);
|
||||
|
@ -574,7 +566,6 @@ public class DataTypeManagerPlugin extends ProgramPlugin
|
|||
openDialog.addOkActionListener(listener);
|
||||
}
|
||||
tool.showDialog(openDialog);
|
||||
// updateActions();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -83,7 +83,8 @@ public class DataTypesProvider extends ComponentProviderAdapter {
|
|||
private HelpLocation helpLocation;
|
||||
private DataTypeManagerPlugin plugin;
|
||||
|
||||
private HistoryList<DataType> navigationHistory = new HistoryList<>(15, dt -> {
|
||||
private HistoryList<DataTypeIdUrl> navigationHistory = new HistoryList<>(15, url -> {
|
||||
DataType dt = url.getDataType(plugin);
|
||||
setDataTypeSelected(dt);
|
||||
});
|
||||
private MultiActionDockingAction nextAction;
|
||||
|
@ -465,35 +466,12 @@ public class DataTypesProvider extends ComponentProviderAdapter {
|
|||
try {
|
||||
url = new DataTypeIdUrl(href);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
Msg.debug(this, "Could not parse Data Type ID URL '" + href + "'");
|
||||
catch (IllegalArgumentException e) {
|
||||
Msg.debug(this, "Could not parse Data Type ID URL '" + href + "'", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
DataTypeManager manager = getManager(url);
|
||||
if (manager == null) {
|
||||
// this shouldn't be possible, unless the url is old and the manager has been closed
|
||||
Msg.debug(this, "Could not find data type for " + event.getDescription());
|
||||
return null;
|
||||
}
|
||||
|
||||
DataType dt = manager.findDataTypeForID(url.getDataTypeId());
|
||||
return dt;
|
||||
}
|
||||
|
||||
private DataTypeManager getManager(DataTypeIdUrl url) {
|
||||
UniversalID id = url.getDataTypeManagerId();
|
||||
return getManager(id);
|
||||
}
|
||||
|
||||
private DataTypeManager getManager(UniversalID id) {
|
||||
DataTypeManager[] mgs = plugin.getDataTypeManagers();
|
||||
for (DataTypeManager dtm : mgs) {
|
||||
if (dtm.getUniversalID().equals(id)) {
|
||||
return dtm;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return url.getDataType(plugin);
|
||||
}
|
||||
|
||||
private void updatePreviewPane() {
|
||||
|
@ -550,6 +528,7 @@ public class DataTypesProvider extends ComponentProviderAdapter {
|
|||
void dispose() {
|
||||
previewUpdateManager.dispose();
|
||||
archiveGTree.dispose();
|
||||
navigationHistory.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -861,6 +840,10 @@ public class DataTypesProvider extends ComponentProviderAdapter {
|
|||
return conflictMode.getHandler();
|
||||
}
|
||||
|
||||
DataTypeManagerPlugin getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
private DataType getDataTypeFrom(TreePath path) {
|
||||
if (path == null) {
|
||||
return null;
|
||||
|
@ -876,7 +859,7 @@ public class DataTypesProvider extends ComponentProviderAdapter {
|
|||
return dt;
|
||||
}
|
||||
|
||||
HistoryList<DataType> getNavigationHistory() {
|
||||
HistoryList<DataTypeIdUrl> getNavigationHistory() {
|
||||
return navigationHistory;
|
||||
}
|
||||
|
||||
|
@ -898,7 +881,11 @@ public class DataTypesProvider extends ComponentProviderAdapter {
|
|||
return; // Ignore events from the GTree's housekeeping
|
||||
}
|
||||
|
||||
navigationHistory.add(dt);
|
||||
if (dt == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
navigationHistory.add(new DataTypeIdUrl(dt));
|
||||
contextChanged();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import javax.swing.Icon;
|
|||
import docking.ActionContext;
|
||||
import docking.action.*;
|
||||
import docking.menu.MultiActionDockingAction;
|
||||
import ghidra.app.util.datatype.DataTypeIdUrl;
|
||||
import ghidra.base.actions.HorizontalRuleAction;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
|
@ -38,7 +39,7 @@ class NextPreviousDataTypeAction extends MultiActionDockingAction {
|
|||
private boolean isNext;
|
||||
private String owner;
|
||||
private DataTypesProvider provider;
|
||||
private HistoryList<DataType> history;
|
||||
private HistoryList<DataTypeIdUrl> history;
|
||||
|
||||
public NextPreviousDataTypeAction(DataTypesProvider provider, String owner, boolean isNext) {
|
||||
super(isNext ? "Next Data Type in History" : "Previous Data Type in History", owner);
|
||||
|
@ -92,19 +93,19 @@ class NextPreviousDataTypeAction extends MultiActionDockingAction {
|
|||
|
||||
DataTypeManager lastDtm = null;
|
||||
List<DockingActionIf> results = new ArrayList<>();
|
||||
List<DataType> types =
|
||||
List<DataTypeIdUrl> types =
|
||||
isNext ? history.getNextHistoryItems() : history.getPreviousHistoryItems();
|
||||
|
||||
for (DataType dt : types) {
|
||||
for (DataTypeIdUrl url : types) {
|
||||
|
||||
DataType dt = url.getDataType(provider.getPlugin());
|
||||
DataTypeManager dtm = dt.getDataTypeManager();
|
||||
|
||||
if (dtm != lastDtm && !results.isEmpty()) {
|
||||
// add a separator to show the user they are navigating across managers
|
||||
results.add(createHorizontalRule(lastDtm, dtm));
|
||||
}
|
||||
|
||||
results.add(new NavigationAction(dt));
|
||||
results.add(new NavigationAction(dt.getDisplayName()));
|
||||
lastDtm = dtm;
|
||||
}
|
||||
|
||||
|
@ -122,10 +123,10 @@ class NextPreviousDataTypeAction extends MultiActionDockingAction {
|
|||
|
||||
private class NavigationAction extends DockingAction {
|
||||
|
||||
private NavigationAction(DataType dt) {
|
||||
private NavigationAction(String dtDisplayName) {
|
||||
super("DataTypeNavigationAction_" + ++navigationActionIdCount, owner);
|
||||
|
||||
setMenuBarData(new MenuData(new String[] { dt.getDisplayName() }));
|
||||
setMenuBarData(new MenuData(new String[] { dtDisplayName }));
|
||||
setEnabled(true);
|
||||
setHelpLocation(new HelpLocation("DataTypeManagerPlugin", "Navigation_Actions"));
|
||||
}
|
||||
|
|
|
@ -223,7 +223,7 @@ public class ArchiveNode extends CategoryNode {
|
|||
return null;
|
||||
}
|
||||
|
||||
CategoryNode node = findCategoryNode(parentCategory);
|
||||
CategoryNode node = findCategoryNode(parentCategory, loadChildren);
|
||||
if (node == null) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -15,40 +15,52 @@
|
|||
*/
|
||||
package ghidra.app.util.datatype;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.app.services.DataTypeManagerService;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.UniversalID;
|
||||
|
||||
/**
|
||||
* A class to produce and parse URLs of the form:
|
||||
* <pre>
|
||||
* datatype:/12345678/12345678
|
||||
* datatype:/12345678?uid=12345678&name=Bob
|
||||
* </pre>
|
||||
* where the first number is the ID of the {@link DataTypeManager} and the second number is
|
||||
* the {@link DataType} ID.
|
||||
*/
|
||||
public class DataTypeIdUrl {
|
||||
|
||||
// see javadoc for format
|
||||
private static String PROTOCOL = "datatype";
|
||||
private static Pattern URL_PATTERN = Pattern.compile(PROTOCOL + ":/(\\d+)/(\\d+)");
|
||||
private static Pattern URL_PATTERN =
|
||||
Pattern.compile(PROTOCOL + ":/(\\d+)\\?uid=(\\d*)&name=(\\w+)");
|
||||
|
||||
private UniversalID dataTypeManagerId;
|
||||
private UniversalID dataTypeId;
|
||||
private String dataTypeName;
|
||||
|
||||
/**
|
||||
* Constructs a url from the given data type
|
||||
* @param dt the data type; cannot be null
|
||||
*/
|
||||
public DataTypeIdUrl(DataType dt) {
|
||||
DataTypeManager dtm = dt.getDataTypeManager();
|
||||
if (dtm == null) {
|
||||
Msg.debug(this, "");
|
||||
}
|
||||
dataTypeManagerId = dtm.getUniversalID();
|
||||
dataTypeManagerId = Objects.requireNonNull(dtm.getUniversalID());
|
||||
dataTypeId = dt.getUniversalID();
|
||||
dataTypeName = Objects.requireNonNull(dt.getName());
|
||||
}
|
||||
|
||||
public DataTypeIdUrl(String url) {
|
||||
/**
|
||||
* Constructs a url from the given url string
|
||||
*
|
||||
* @param url the url
|
||||
* @throws IllegalArgumentException if the url does not match the expected {@link #URL_PATTERN}
|
||||
* or if there is an issue parsing the id within the given url
|
||||
*/
|
||||
public DataTypeIdUrl(String url) throws IllegalArgumentException {
|
||||
|
||||
Matcher matcher = URL_PATTERN.matcher(url);
|
||||
if (!matcher.matches()) {
|
||||
|
@ -57,9 +69,22 @@ public class DataTypeIdUrl {
|
|||
|
||||
String dtmId = matcher.group(1);
|
||||
String dtId = matcher.group(2);
|
||||
|
||||
try {
|
||||
dataTypeManagerId = new UniversalID(Long.parseLong(dtmId));
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException("Exception parsing Data Type Manager ID: ", e);
|
||||
}
|
||||
|
||||
try {
|
||||
dataTypeId = new UniversalID(Long.parseLong(dtId));
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException("Exception parsing Data Type ID: ", e);
|
||||
}
|
||||
dataTypeName = matcher.group(3);
|
||||
}
|
||||
|
||||
public UniversalID getDataTypeManagerId() {
|
||||
return dataTypeManagerId;
|
||||
|
@ -69,8 +94,86 @@ public class DataTypeIdUrl {
|
|||
return dataTypeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the given service and its {@link DataTypeManager}s to find the data type
|
||||
* represented by this url
|
||||
*
|
||||
* @param service the service
|
||||
* @return the data type; null if there was an error restoring the type, such as if the
|
||||
* parent {@link DataTypeManager} has been closed
|
||||
*/
|
||||
public DataType getDataType(DataTypeManagerService service) {
|
||||
|
||||
DataTypeManager manager = findManager(service);
|
||||
if (manager == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (dataTypeId == null) {
|
||||
// The ID will be null for built-in types. In that case, the name will not be
|
||||
// null. Further, built-in types live at the root, so we can just ask for the
|
||||
// type by name.
|
||||
return manager.getDataType(new DataTypePath(CategoryPath.ROOT, dataTypeName));
|
||||
}
|
||||
|
||||
DataType dt = manager.findDataTypeForID(dataTypeId);
|
||||
return dt;
|
||||
}
|
||||
|
||||
private DataTypeManager findManager(DataTypeManagerService service) {
|
||||
return getManagerById(service);
|
||||
}
|
||||
|
||||
private DataTypeManager getManagerById(DataTypeManagerService service) {
|
||||
DataTypeManager[] mgs = service.getDataTypeManagers();
|
||||
for (DataTypeManager dtm : mgs) {
|
||||
if (dtm.getUniversalID().equals(dataTypeManagerId)) {
|
||||
return dtm;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((dataTypeId == null) ? 0 : dataTypeId.hashCode());
|
||||
result = prime * result + ((dataTypeManagerId == null) ? 0 : dataTypeManagerId.hashCode());
|
||||
result = prime * result + ((dataTypeName == null) ? 0 : dataTypeName.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DataTypeIdUrl other = (DataTypeIdUrl) obj;
|
||||
if (!Objects.equals(dataTypeId, other.dataTypeId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Objects.equals(dataTypeManagerId, other.dataTypeManagerId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Objects.equals(dataTypeName, other.dataTypeName)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return PROTOCOL + ":/" + dataTypeManagerId.toString() + '/' + dataTypeId.toString();
|
||||
return PROTOCOL + ":/" + dataTypeManagerId.toString() + "?uid=" +
|
||||
Objects.toString(dataTypeId, "") + "&name=" + dataTypeName;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package ghidra.app.plugin.core.datamgr;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.startsWith;
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.awt.Container;
|
||||
|
@ -24,7 +24,8 @@ import java.awt.event.KeyEvent;
|
|||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
|
@ -39,10 +40,6 @@ import docking.action.DockingActionIf;
|
|||
import docking.action.ToggleDockingActionIf;
|
||||
import docking.actions.KeyBindingUtils;
|
||||
import docking.widgets.OptionDialog;
|
||||
import docking.widgets.combobox.GhidraComboBox;
|
||||
import docking.widgets.dialogs.InputWithChoicesDialog;
|
||||
import docking.widgets.fieldpanel.support.Highlight;
|
||||
import docking.widgets.table.threaded.ThreadedTableModel;
|
||||
import docking.widgets.tree.GTreeNode;
|
||||
import ghidra.app.context.ProgramActionContext;
|
||||
import ghidra.app.plugin.core.datamgr.actions.CreateTypeDefDialog;
|
||||
|
@ -50,23 +47,15 @@ import ghidra.app.plugin.core.datamgr.archive.Archive;
|
|||
import ghidra.app.plugin.core.datamgr.archive.DataTypeManagerHandler;
|
||||
import ghidra.app.plugin.core.datamgr.tree.*;
|
||||
import ghidra.app.plugin.core.function.EditFunctionSignatureDialog;
|
||||
import ghidra.app.plugin.core.navigation.locationreferences.LocationReferencesPlugin;
|
||||
import ghidra.app.plugin.core.navigation.locationreferences.LocationReferencesProvider;
|
||||
import ghidra.app.plugin.core.programtree.ProgramTreePlugin;
|
||||
import ghidra.app.services.CodeViewerService;
|
||||
import ghidra.app.services.ProgramManager;
|
||||
import ghidra.app.util.HighlightProvider;
|
||||
import ghidra.app.util.datatype.DataTypeSelectionEditor;
|
||||
import ghidra.app.util.viewer.field.*;
|
||||
import ghidra.app.util.viewer.format.FormatManager;
|
||||
import ghidra.framework.plugintool.Plugin;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.database.ProgramBuilder;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
import ghidra.program.database.data.ProgramDataTypeManager;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.test.*;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.classfinder.ClassFilter;
|
||||
|
@ -856,85 +845,6 @@ public class DataTypeManagerPluginTest extends AbstractGhidraHeadedIntegrationTe
|
|||
return builtinNode;
|
||||
}
|
||||
|
||||
private void findReferencesToField(String choice) {
|
||||
DockingActionIf searchAction = getAction(plugin, "Find Uses of Field");
|
||||
assertTrue(searchAction.isEnabledForContext(treeContext));
|
||||
DataTypeTestUtils.performAction(searchAction, tree, false);
|
||||
|
||||
InputWithChoicesDialog d = waitForDialogComponent(InputWithChoicesDialog.class);
|
||||
@SuppressWarnings("unchecked")
|
||||
GhidraComboBox<String> combo = (GhidraComboBox<String>) getInstanceField("combo", d);
|
||||
setComboBoxSelection(combo, choice);
|
||||
pressButtonByText(d, "OK");
|
||||
|
||||
waitForSearchResults();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private LocationReferencesProvider getLocationReferencesProvider() {
|
||||
LocationReferencesPlugin locationRefsPlugin =
|
||||
getPlugin(tool, LocationReferencesPlugin.class);
|
||||
|
||||
List<LocationReferencesProvider> providerList =
|
||||
(List<LocationReferencesProvider>) getInstanceField("providerList", locationRefsPlugin);
|
||||
if (providerList.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
return providerList.get(0);
|
||||
}
|
||||
|
||||
private ThreadedTableModel<?, ?> getTableModel() {
|
||||
|
||||
waitForCondition(() -> getLocationReferencesProvider() != null);
|
||||
|
||||
LocationReferencesProvider refsProvider = getLocationReferencesProvider();
|
||||
Object referencesPanel = getInstanceField("referencesPanel", refsProvider);
|
||||
return (ThreadedTableModel<?, ?>) getInstanceField("tableModel", referencesPanel);
|
||||
}
|
||||
|
||||
private void waitForSearchResults() {
|
||||
ThreadedTableModel<?, ?> model = getTableModel();
|
||||
waitForTableModel(model);
|
||||
}
|
||||
|
||||
private HighlightProvider getHighlightProvider() {
|
||||
CodeViewerService service = tool.getService(CodeViewerService.class);
|
||||
FormatManager fm = (FormatManager) getInstanceField("formatMgr", service);
|
||||
return (HighlightProvider) getInstanceField("highlightProvider", fm);
|
||||
}
|
||||
|
||||
private void assertOperandHighlight(String rep, Address addr) {
|
||||
assertHighlight(OperandFieldFactory.class, rep, addr);
|
||||
}
|
||||
|
||||
private void assertFieldNameHighlight(String rep, Address addr) {
|
||||
assertHighlight(FieldNameFieldFactory.class, rep, addr);
|
||||
}
|
||||
|
||||
private void assertHighlight(Class<? extends FieldFactory> clazz, String rep, Address addr) {
|
||||
Listing listing = program.getListing();
|
||||
CodeUnit cu = listing.getCodeUnitContaining(addr);
|
||||
if (cu instanceof Data) {
|
||||
Data data = (Data) cu;
|
||||
Address minAddress = data.getMinAddress();
|
||||
long offset = addr.subtract(minAddress);
|
||||
if (offset != 0) {
|
||||
Data subData = data.getComponentAt((int) offset);
|
||||
cu = subData;
|
||||
}
|
||||
}
|
||||
HighlightProvider highlighter = getHighlightProvider();
|
||||
Highlight[] highlights = highlighter.getHighlights(rep, cu, clazz, -1);
|
||||
assertNotNull(highlights);
|
||||
assertTrue(highlights.length != 0);
|
||||
}
|
||||
|
||||
private Address addr(long offset) {
|
||||
AddressFactory addrMap = program.getAddressFactory();
|
||||
AddressSpace space = addrMap.getDefaultAddressSpace();
|
||||
return space.getAddress(offset);
|
||||
}
|
||||
|
||||
private void assertSingleFilterMatch(String[] path) {
|
||||
GTreeNode rootNode = tree.getRootNode();
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ import ghidra.app.plugin.core.datamgr.tree.DataTypeArchiveGTree;
|
|||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.Swing;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import utilities.util.FileUtilities;
|
||||
|
||||
|
@ -146,20 +147,18 @@ public class DataTypeTestUtils {
|
|||
static void closeArchive(final ArchiveNode archiveNode, final boolean deleteFile)
|
||||
throws Exception {
|
||||
|
||||
final Exception[] container = new Exception[1];
|
||||
|
||||
SwingUtilities.invokeAndWait(() -> {
|
||||
Exception exception = Swing.runNow(() -> {
|
||||
try {
|
||||
doCloseArchive(archiveNode, deleteFile);
|
||||
return null;
|
||||
}
|
||||
catch (Exception e) {
|
||||
container[0] = e;
|
||||
return e;
|
||||
}
|
||||
});
|
||||
|
||||
if (container[0] != null) {
|
||||
throw new RuntimeException("Exception closing archive on Swing thread!: ",
|
||||
container[0]);
|
||||
if (exception != null) {
|
||||
throw new RuntimeException("Exception closing archive on Swing thread!: ", exception);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -83,6 +83,10 @@ public class HistoryList<T> {
|
|||
* allow duplicates, but to also move the position of an item if it is re-added to the
|
||||
* list.
|
||||
*
|
||||
* <p>For correct behavior when not allowing duplicates, ensure you have defined an
|
||||
* <code>equals</code> method to work as you expect. If two different items are considered
|
||||
* equal, then this class will only remove the duplicate if the equals method returns true.
|
||||
*
|
||||
* <p>The default is false
|
||||
*
|
||||
* @param allowDuplicates true to allow duplicates
|
||||
|
@ -162,7 +166,6 @@ public class HistoryList<T> {
|
|||
* <p>No action is taken if the current pointer is already at the beginning of the list.
|
||||
*/
|
||||
public void goBack() {
|
||||
|
||||
if (historyIndex == 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -217,7 +220,7 @@ public class HistoryList<T> {
|
|||
|
||||
/**
|
||||
* Get all items in the history that come after the current history item. They are
|
||||
* returned in navigation order, as traversed if {@link #goForward() is called.
|
||||
* returned in navigation order, as traversed if {@link #goForward()} is called.
|
||||
*
|
||||
* @return the items
|
||||
*/
|
||||
|
|
|
@ -31,8 +31,8 @@ import ghidra.util.task.TaskMonitorAdapter;
|
|||
* DataTypeManager for a file. Can import categories from a file, or export
|
||||
* categories to a packed database.
|
||||
*/
|
||||
public class FileDataTypeManager extends StandAloneDataTypeManager implements
|
||||
FileArchiveBasedDataTypeManager {
|
||||
public class FileDataTypeManager extends StandAloneDataTypeManager
|
||||
implements FileArchiveBasedDataTypeManager {
|
||||
|
||||
public final static String EXTENSION = "gdt"; // Ghidra Data Types
|
||||
/**
|
||||
|
@ -108,15 +108,14 @@ public class FileDataTypeManager extends StandAloneDataTypeManager implements
|
|||
* @param outputFilename filename for output
|
||||
* @param databaseId new databaseId
|
||||
*/
|
||||
public void saveAs(File saveFile, UniversalID newUniversalId) throws DuplicateFileException,
|
||||
IOException {
|
||||
public void saveAs(File saveFile, UniversalID newUniversalId)
|
||||
throws DuplicateFileException, IOException {
|
||||
ResourceFile resourceSaveFile = new ResourceFile(saveFile);
|
||||
// TODO: this should really be a package method and not public!
|
||||
validateFilename(resourceSaveFile);
|
||||
try {
|
||||
universalID = newUniversalId;
|
||||
packedDB =
|
||||
((PackedDBHandle) dbHandle).saveAs("DTArchive", saveFile.getParentFile(),
|
||||
packedDB = ((PackedDBHandle) dbHandle).saveAs("DTArchive", saveFile.getParentFile(),
|
||||
saveFile.getName(), newUniversalId.getValue(), TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
file = resourceSaveFile;
|
||||
updateRootCategoryName(resourceSaveFile, getRootCategory());
|
||||
|
@ -134,8 +133,7 @@ public class FileDataTypeManager extends StandAloneDataTypeManager implements
|
|||
ResourceFile resourceSaveFile = new ResourceFile(saveFile);
|
||||
validateFilename(resourceSaveFile);
|
||||
try {
|
||||
packedDB =
|
||||
((PackedDBHandle) dbHandle).saveAs("DTArchive", saveFile.getParentFile(),
|
||||
packedDB = ((PackedDBHandle) dbHandle).saveAs("DTArchive", saveFile.getParentFile(),
|
||||
saveFile.getName(), TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
file = resourceSaveFile;
|
||||
updateRootCategoryName(resourceSaveFile, getRootCategory());
|
||||
|
@ -268,4 +266,8 @@ public class FileDataTypeManager extends StandAloneDataTypeManager implements
|
|||
return ArchiveType.FILE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + " - " + getName();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue