Merge remote-tracking branch 'origin/GT-3222-dragonmacher-dt-history-issue'

This commit is contained in:
Ryan Kurtz 2019-10-28 11:32:17 -04:00
commit 90854a01a6
18 changed files with 1383 additions and 536 deletions

View File

@ -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

View File

@ -42,7 +42,7 @@ import ghidra.app.plugin.core.datamgr.archive.*;
import ghidra.app.plugin.core.datamgr.tree.*;
import ghidra.app.plugin.core.datamgr.util.DataTypeUtils;
import ghidra.app.util.ToolTipUtils;
import ghidra.app.util.datatype.DataTypeIdUrl;
import ghidra.app.util.datatype.DataTypeUrl;
import ghidra.framework.main.datatree.ArchiveProvider;
import ghidra.framework.main.datatree.VersionControlDataTypeArchiveUndoCheckoutAction;
import ghidra.framework.main.projectdata.actions.*;
@ -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<DataTypeUrl> navigationHistory = new HistoryList<>(15, url -> {
DataType dt = url.getDataType(plugin);
setDataTypeSelected(dt);
});
private MultiActionDockingAction nextAction;
@ -462,39 +463,16 @@ public class DataTypesProvider extends ComponentProviderAdapter {
private DataType locateDataType(HyperlinkEvent event) {
String href = event.getDescription();
DataTypeIdUrl url = null;
DataTypeUrl url = null;
try {
url = new DataTypeIdUrl(href);
url = new DataTypeUrl(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 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() {
@ -551,6 +529,7 @@ public class DataTypesProvider extends ComponentProviderAdapter {
void dispose() {
previewUpdateManager.dispose();
archiveGTree.dispose();
navigationHistory.clear();
}
@Override
@ -862,6 +841,10 @@ public class DataTypesProvider extends ComponentProviderAdapter {
return conflictMode.getHandler();
}
DataTypeManagerPlugin getPlugin() {
return plugin;
}
private DataType getDataTypeFrom(TreePath path) {
if (path == null) {
return null;
@ -877,7 +860,7 @@ public class DataTypesProvider extends ComponentProviderAdapter {
return dt;
}
HistoryList<DataType> getNavigationHistory() {
HistoryList<DataTypeUrl> getNavigationHistory() {
return navigationHistory;
}
@ -899,7 +882,12 @@ public class DataTypesProvider extends ComponentProviderAdapter {
return; // Ignore events from the GTree's housekeeping
}
navigationHistory.add(dt);
// the data type is null when a non-data type node is selected, like a category node
if (dt == null) {
return;
}
navigationHistory.add(new DataTypeUrl(dt));
contextChanged();
}
}

View File

@ -23,6 +23,7 @@ import javax.swing.Icon;
import docking.ActionContext;
import docking.action.*;
import docking.menu.MultiActionDockingAction;
import ghidra.app.util.datatype.DataTypeUrl;
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<DataTypeUrl> history;
public NextPreviousDataTypeAction(DataTypesProvider provider, String owner, boolean isNext) {
super(isNext ? "Next Data Type in History" : "Previous Data Type in History", owner);
@ -65,22 +66,17 @@ class NextPreviousDataTypeAction extends MultiActionDockingAction {
@Override
public void actionPerformed(ActionContext context) {
if (isNext) {
history.goForward();
}
else {
history.goBack();
}
// rely on the individual actions to navigate, as they know them item that is being
// navigated to, allowing them to skip through the list
List<DockingActionIf> actions = getActionList(context);
DockingActionIf action = actions.get(0);
action.actionPerformed(context);
provider.contextChanged();
}
@Override
public boolean isEnabledForContext(ActionContext context) {
if (isNext) {
return history.hasNext();
}
return history.hasPrevious();
return !getActionList(context).isEmpty();
}
@Override
@ -92,19 +88,25 @@ class NextPreviousDataTypeAction extends MultiActionDockingAction {
DataTypeManager lastDtm = null;
List<DockingActionIf> results = new ArrayList<>();
List<DataType> types =
List<DataTypeUrl> types =
isNext ? history.getNextHistoryItems() : history.getPreviousHistoryItems();
for (DataType dt : types) {
for (DataTypeUrl url : types) {
DataType dt = url.getDataType(provider.getPlugin());
if (dt == null) {
// The type may have been removed; maybe an undo happened. Leave the item in
// the list in case a redo is performed
continue;
}
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(url, dt));
lastDtm = dtm;
}
@ -122,8 +124,11 @@ class NextPreviousDataTypeAction extends MultiActionDockingAction {
private class NavigationAction extends DockingAction {
private NavigationAction(DataType dt) {
private DataTypeUrl url;
private NavigationAction(DataTypeUrl url, DataType dt) {
super("DataTypeNavigationAction_" + ++navigationActionIdCount, owner);
this.url = url;
setMenuBarData(new MenuData(new String[] { dt.getDisplayName() }));
setEnabled(true);
@ -132,11 +137,15 @@ class NextPreviousDataTypeAction extends MultiActionDockingAction {
@Override
public void actionPerformed(ActionContext context) {
// note: we use 'goBackTo()' and 'goForwardTo()' since items in the history list
// may not have been added to the multi-action; we have to tell the list
// to skip those items.
if (isNext) {
history.goForward();
history.goForwardTo(url);
}
else {
history.goBack();
history.goBackTo(url);
}
provider.contextChanged();
}

View File

@ -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;
}

View File

@ -1,76 +0,0 @@
/* ###
* 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.util.datatype;
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.util.UniversalID;
/**
* A class to produce and parse URLs of the form:
* <pre>
* datatype:/12345678/12345678
* </pre>
* where the first number is the ID of the {@link DataTypeManager} and the second number is
* the {@link DataType} ID.
*/
public class DataTypeIdUrl {
private static String PROTOCOL = "datatype";
private static Pattern URL_PATTERN = Pattern.compile(PROTOCOL + ":/(\\d+)/(\\d+)");
private UniversalID dataTypeManagerId;
private UniversalID dataTypeId;
public DataTypeIdUrl(DataType dt) {
DataTypeManager dtm = dt.getDataTypeManager();
if (dtm == null) {
Msg.debug(this, "");
}
dataTypeManagerId = dtm.getUniversalID();
dataTypeId = dt.getUniversalID();
}
public DataTypeIdUrl(String url) {
Matcher matcher = URL_PATTERN.matcher(url);
if (!matcher.matches()) {
throw new IllegalArgumentException("Invalid data type URL '" + url + "'");
}
String dtmId = matcher.group(1);
String dtId = matcher.group(2);
dataTypeManagerId = new UniversalID(Long.parseLong(dtmId));
dataTypeId = new UniversalID(Long.parseLong(dtId));
}
public UniversalID getDataTypeManagerId() {
return dataTypeManagerId;
}
public UniversalID getDataTypeId() {
return dataTypeId;
}
@Override
public String toString() {
return PROTOCOL + ":/" + dataTypeManagerId.toString() + '/' + dataTypeId.toString();
}
}

View File

@ -0,0 +1,175 @@
/* ###
* 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.util.datatype;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
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?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 DataTypeUrl {
// see javadoc for format
private static String PROTOCOL = "datatype";
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 DataTypeUrl(DataType dt) {
DataTypeManager dtm = dt.getDataTypeManager();
dataTypeManagerId = Objects.requireNonNull(dtm.getUniversalID());
dataTypeId = dt.getUniversalID();
dataTypeName = Objects.requireNonNull(dt.getName());
}
/**
* 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 DataTypeUrl(String url) throws IllegalArgumentException {
Matcher matcher = URL_PATTERN.matcher(url);
if (!matcher.matches()) {
throw new IllegalArgumentException("Invalid data type URL '" + url + "'");
}
String dtmId = matcher.group(1);
String dtId = matcher.group(2);
dataTypeName = matcher.group(3);
dataTypeManagerId = new UniversalID(Long.parseLong(dtmId));
if (!dtId.isBlank()) {
dataTypeId = new UniversalID(Long.parseLong(dtId));
}
}
public UniversalID getDataTypeManagerId() {
return dataTypeManagerId;
}
public UniversalID getDataTypeId() {
return dataTypeId;
}
public String getDataTypeName() {
return dataTypeName;
}
/**
* 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;
}
DataTypeUrl other = (DataTypeUrl) 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() + "?uid=" +
Objects.toString(dataTypeId, "") + "&name=" + dataTypeName;
}
}

View File

@ -20,7 +20,7 @@ import static ghidra.util.HTMLUtilities.friendlyEncodeHTML;
import java.awt.Color;
import java.util.*;
import ghidra.app.util.datatype.DataTypeIdUrl;
import ghidra.app.util.datatype.DataTypeUrl;
import ghidra.app.util.html.diff.*;
import ghidra.program.model.data.*;
import ghidra.util.HTMLUtilities;
@ -283,7 +283,7 @@ public class CompositeDataTypeHTMLRepresentation extends HTMLDataTypeRepresentat
// Markup the name with info for later hyperlink capability, as needed by the client
//
DataType dt = line.getDataType();
DataTypeIdUrl url = new DataTypeIdUrl(dt);
DataTypeUrl url = new DataTypeUrl(dt);
String wrapped = HTMLUtilities.wrapWithLinkPlaceholder(type, url.toString());
return wrapped;
}

View File

@ -18,7 +18,7 @@ package ghidra.app.util.html;
import java.util.ArrayList;
import java.util.List;
import ghidra.app.util.datatype.DataTypeIdUrl;
import ghidra.app.util.datatype.DataTypeUrl;
import ghidra.app.util.html.diff.DataTypeDiff;
import ghidra.app.util.html.diff.DataTypeDiffBuilder;
import ghidra.program.model.data.*;
@ -185,7 +185,7 @@ public class FunctionDataTypeHTMLRepresentation extends HTMLDataTypeRepresentati
// Markup the name with info for later hyperlink capability, as needed by the client
//
DataType dataType = line.getDataType();
DataTypeIdUrl url = new DataTypeIdUrl(dataType);
DataTypeUrl url = new DataTypeUrl(dataType);
String wrapped = HTMLUtilities.wrapWithLinkPlaceholder(type, url.toString());
return wrapped;
}

View File

@ -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.getViewRoot();

View File

@ -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;
@ -52,12 +53,12 @@ public class DataTypeTestUtils {
}
// copies the default test archive into a local version
static File createArchive(String filename) throws Exception {
public static File createArchive(String filename) throws Exception {
return createLocalArchiveFromExistingArchive(filename, "TestArchive.gdt");
}
// copies the archive from the given filename to a local version
static File copyArchive(String filename) throws Exception {
public static File copyArchive(String filename) throws Exception {
return createLocalArchiveFromExistingArchive(filename, filename);
}
@ -92,8 +93,8 @@ public class DataTypeTestUtils {
return scratchFile;
}
static ArchiveNode openArchive(String archiveDirPath, String archiveName, boolean checkout,
DataTypeManagerPlugin plugin) throws Exception {
public static ArchiveNode openArchive(String archiveDirPath, String archiveName,
boolean checkout, DataTypeManagerPlugin plugin) throws Exception {
File file = new File(archiveDirPath, archiveName);
DataTypeManagerHandler dataTypeManagerHandler = plugin.getDataTypeManagerHandler();
@ -107,7 +108,7 @@ public class DataTypeTestUtils {
return (ArchiveNode) rootNode.getChild(trimFullArchiveName(archiveName));
}
static ArchiveNode openArchive(String archiveName, boolean checkout,
public static ArchiveNode openArchive(String archiveName, boolean checkout,
DataTypeManagerPlugin plugin) throws Exception {
ArchiveNode openArchive = openArchive(archiveName, checkout, false, plugin);
waitForTree(plugin);
@ -127,8 +128,8 @@ public class DataTypeTestUtils {
AbstractGenericTest.waitForPostedSwingRunnables();
}
static ArchiveNode openArchive(String archiveName, boolean checkout, boolean isUserAction,
DataTypeManagerPlugin plugin) throws Exception {
public static ArchiveNode openArchive(String archiveName, boolean checkout,
boolean isUserAction, DataTypeManagerPlugin plugin) throws Exception {
File tempDir = getTempDir();
File file = new File(tempDir, archiveName);
@ -143,23 +144,21 @@ public class DataTypeTestUtils {
return (ArchiveNode) rootNode.getChild(trimFullArchiveName(archiveName));
}
static void closeArchive(final ArchiveNode archiveNode, final boolean deleteFile)
public 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);
}
}
@ -191,8 +190,8 @@ public class DataTypeTestUtils {
* @return The archive node associated with the open archive
* @throws Exception If there is any problem finding or opening the archive for the given name
*/
static ArchiveNode checkOutArchive(String archiveName, final DataTypeManagerPlugin plugin)
throws Exception {
public static ArchiveNode checkOutArchive(String archiveName,
final DataTypeManagerPlugin plugin) throws Exception {
String archiveNodeName = trimFullArchiveName(archiveName);
GTree tree = plugin.getProvider().getGTree();
@ -222,14 +221,14 @@ public class DataTypeTestUtils {
return archiveName;
}
static ArchiveNode createOpenAndCheckoutArchive(String archiveName,
public static ArchiveNode createOpenAndCheckoutArchive(String archiveName,
DataTypeManagerPlugin plugin) throws Exception {
createArchive(archiveName);
return openArchive(archiveName, true, plugin);
}
static ArchiveNode copyOpenAndCheckoutArchive(String archiveName, DataTypeManagerPlugin plugin)
throws Exception {
public static ArchiveNode copyOpenAndCheckoutArchive(String archiveName,
DataTypeManagerPlugin plugin) throws Exception {
copyArchive(archiveName);
return openArchive(archiveName, true, plugin);
}
@ -238,7 +237,8 @@ public class DataTypeTestUtils {
performAction(action, program, tree, true);
}
static void performAction(DockingActionIf action, Program program, GTree tree, boolean wait) {
public static void performAction(DockingActionIf action, Program program, GTree tree,
boolean wait) {
AbstractGenericTest.runSwing(() -> {
ActionContext context =
new DataTypesActionContext(null, program, (DataTypeArchiveGTree) tree, null, true);
@ -266,7 +266,7 @@ public class DataTypeTestUtils {
}
}
static void createCategory(Category parent, String categoryName) throws Exception {
public static void createCategory(Category parent, String categoryName) throws Exception {
DataTypeManager dtm = parent.getDataTypeManager();
int id = dtm.startTransaction("create category");
try {

View File

@ -15,23 +15,24 @@
*/
package ghidra.app.plugin.core.datamgr.util;
import java.net.URL;
import java.util.*;
import org.junit.Before;
import org.junit.Test;
import generic.test.AbstractGenericTest;
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
import ghidra.docking.settings.Settings;
import ghidra.docking.settings.SettingsDefinition;
import ghidra.program.model.data.*;
import generic.test.AbstractGTest;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.DataTypeComparator;
import ghidra.program.model.mem.MemBuffer;
import ghidra.util.*;
import ghidra.util.exception.DuplicateNameException;
import ghidra.program.model.data.TestDoubleDataType;
import ghidra.util.UniversalIdGenerator;
public class DataTypeUtilsTest {
@Before
public void setUp() {
UniversalIdGenerator.initialize();
}
@Test
public void testDataSearch() throws Exception {
@ -43,7 +44,7 @@ public class DataTypeUtilsTest {
final List<DataType> data = new ArrayList<>();
for (String element : TEST_DATA) {
data.add(new DataTypeDummy(element));
data.add(new FakeDataType(element));
}
// sort them how our data will be sorted
@ -110,266 +111,18 @@ public class DataTypeUtilsTest {
List<DataType> actualMatches =
DataTypeUtils.getMatchingSubList(text, text + endChar, sourceData);
AbstractGenericTest.assertListEqualUnordered(null, expectedMatches, actualMatches);
AbstractGTest.assertListEqualUnordered(null, expectedMatches, actualMatches);
}
private class DataTypeDummy implements DataType {
private class FakeDataType extends TestDoubleDataType {
String wrappedString;
UniversalID id;
DataTypeDummy(String wrappedString) {
this.wrappedString = wrappedString;
id = UniversalIdGenerator.nextID();
}
@Override
public String toString() {
return wrappedString;
}
@Override
public DataTypeManager getDataTypeManager() {
return null;
}
@Override
public DataOrganization getDataOrganization() {
throw new UnsupportedOperationException();
}
@Override
public String getDisplayName() {
return "This is a wrapper for: " + wrappedString;
}
@Override
public String getName() {
return wrappedString;
}
@Override
public boolean isNotYetDefined() {
return false;
}
@Override
public boolean isDynamicallySized() {
return false;
FakeDataType(String name) {
super(name);
}
@Override
public String getPathName() {
return "/" + wrappedString;
}
@Override
public SettingsDefinition[] getSettingsDefinitions() {
return null;
}
@Override
public Settings getDefaultSettings() {
return null;
}
@Override
public CategoryPath getCategoryPath() {
return null;
}
@Override
public DataTypePath getDataTypePath() {
return null;
}
@Override
public void setCategoryPath(CategoryPath path) throws DuplicateNameException {
// no-op
}
@Override
public void setName(String name) throws InvalidNameException, DuplicateNameException {
// no-op
}
@Override
public void setNameAndCategory(CategoryPath path, String name)
throws InvalidNameException, DuplicateNameException {
// no-op
}
@Override
public String getMnemonic(Settings settings) {
return null;
}
@Override
public int getLength() {
return 0;
}
@Override
public String getDescription() {
return null;
}
@Override
public void setDescription(String description) throws UnsupportedOperationException {
throw new UnsupportedOperationException(
getClass().getName() + " doesn't allow the description to be changed.");
}
@Override
public URL getDocs() {
return null;
}
@Override
public Object getValue(MemBuffer buf, Settings settings, int length) {
return null;
}
@Override
public Class<?> getValueClass(Settings settings) {
return null;
}
@Override
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
return null;
}
@Override
public boolean isDeleted() {
return false;
}
@Override
public boolean isEquivalent(DataType dt) {
return false;
}
@Override
public void dataTypeSizeChanged(DataType dt) {
// no-op
}
@Override
public void dataTypeDeleted(DataType dt) {
// no-op
}
@Override
public void dataTypeReplaced(DataType oldDt, DataType newDt) {
// no-op
}
@Override
public void setDefaultSettings(Settings settings) {
// no-op
}
@Override
public void addParent(DataType dt) {
// no-op
}
@Override
public void removeParent(DataType dt) {
// no-op
}
@Override
public void dataTypeNameChanged(DataType dt, String oldName) {
// no-op
}
@Override
public DataType[] getParents() {
return null;
}
@Override
public boolean dependsOn(DataType dt) {
return false;
}
@Override
public String getDefaultLabelPrefix() {
return null;
}
@Override
public String getDefaultAbbreviatedLabelPrefix() {
return null;
}
@Override
public String getDefaultLabelPrefix(MemBuffer buf, Settings settings, int len,
DataTypeDisplayOptions options) {
return null;
}
@Override
public String getDefaultOffcutLabelPrefix(MemBuffer buf, Settings settings, int len,
DataTypeDisplayOptions options, int offcutLength) {
return null;
}
@Override
public long getLastChangeTimeInSourceArchive() {
return DataType.NO_SOURCE_SYNC_TIME;
}
@Override
public long getLastChangeTime() {
return DataType.NO_LAST_CHANGE_TIME;
}
@Override
public SourceArchive getSourceArchive() {
return null;
}
@Override
public UniversalID getUniversalID() {
return id;
}
@Override
public void replaceWith(DataType dataType) {
// no-op
}
@Override
public void setLastChangeTime(long lastChangeTime) {
// no-op
}
@Override
public void setLastChangeTimeInSourceArchive(long lastChangeTimeInSourceArchive) {
// no-op
}
@Override
public void setSourceArchive(SourceArchive archive) {
// no-op
}
@Override
public DataType clone(DataTypeManager dtm) {
return this;
}
@Override
public DataType copy(DataTypeManager dtm) {
return this;
}
@Override
public int getAlignment() {
return 1;
return "/" + getName();
}
}
}

View File

@ -0,0 +1,133 @@
/* ###
* 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.services;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Set;
import javax.swing.tree.TreePath;
import ghidra.app.plugin.core.datamgr.archive.Archive;
import ghidra.app.plugin.core.datamgr.archive.DuplicateIdException;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.DataTypeArchive;
import ghidra.util.HelpLocation;
/**
* A stub of the {@link DataTypeManagerService} interface. This can be used to supply a test values
* or to spy on system internals by overriding methods as needed.
*/
public class TestDoubleDataTypeManagerService implements DataTypeManagerService {
@Override
public DataTypeManager[] getDataTypeManagers() {
throw new UnsupportedOperationException();
}
@Override
public List<DataType> getSortedDataTypeList() {
throw new UnsupportedOperationException();
}
@Override
public DataType getDataType(String filterText) {
throw new UnsupportedOperationException();
}
@Override
public DataTypeManager getBuiltInDataTypesManager() {
throw new UnsupportedOperationException();
}
@Override
public List<DataType> getFavorites() {
throw new UnsupportedOperationException();
}
@Override
public void addDataTypeManagerChangeListener(DataTypeManagerChangeListener listener) {
throw new UnsupportedOperationException();
}
@Override
public void removeDataTypeManagerChangeListener(DataTypeManagerChangeListener listener) {
throw new UnsupportedOperationException();
}
@Override
public void setRecentlyUsed(DataType dt) {
throw new UnsupportedOperationException();
}
@Override
public DataType getRecentlyUsed() {
throw new UnsupportedOperationException();
}
@Override
public HelpLocation getEditorHelpLocation(DataType dataType) {
throw new UnsupportedOperationException();
}
@Override
public boolean isEditable(DataType dt) {
throw new UnsupportedOperationException();
}
@Override
public void edit(DataType dt) {
throw new UnsupportedOperationException();
}
@Override
public void closeArchive(DataTypeManager dtm) {
throw new UnsupportedOperationException();
}
@Override
public DataTypeManager openDataTypeArchive(String archiveName)
throws IOException, DuplicateIdException {
throw new UnsupportedOperationException();
}
@Override
public Archive openArchive(DataTypeArchive dataTypeArchive) {
throw new UnsupportedOperationException();
}
@Override
public Archive openArchive(File file, boolean acquireWriteLock)
throws IOException, DuplicateIdException {
throw new UnsupportedOperationException();
}
@Override
public void setDataTypeSelected(DataType dataType) {
throw new UnsupportedOperationException();
}
@Override
public DataType getDataType(TreePath selectedPath) {
throw new UnsupportedOperationException();
}
@Override
public Set<String> getPossibleEquateNames(long value) {
throw new UnsupportedOperationException();
}
}

View File

@ -0,0 +1,279 @@
/* ###
* 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.util.datatype;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import ghidra.app.services.DataTypeManagerService;
import ghidra.app.services.TestDoubleDataTypeManagerService;
import ghidra.program.model.data.*;
import ghidra.util.UniversalID;
import ghidra.util.UniversalIdGenerator;
public class DataTypeUrlTest {
@Before
public void setUp() {
UniversalIdGenerator.initialize();
}
@Test
public void testConstructor_FromDataType() throws Exception {
String name = "string";
FakeDataType dt = new FakeDataType(name);
DataTypeUrl dtUrl = new DataTypeUrl(dt);
assertNotNull(dtUrl.getDataTypeManagerId());
assertNotNull(dtUrl.getDataTypeId());
assertEquals(name, dtUrl.getDataTypeName());
}
@Test
public void testConstructor_FromUrlString_AllDataIncluded() throws Exception {
String dtmId = "3295333330922457057";
String dtId = "3295333330922457056";
String name = "string";
String urlString = "datatype:/" + dtmId + "?uid=" + dtId + "&name=" + name;
DataTypeUrl dtUrl = new DataTypeUrl(urlString);
assertNotNull(dtUrl.getDataTypeManagerId());
assertNotNull(dtUrl.getDataTypeId());
assertEquals(name, dtUrl.getDataTypeName());
}
@Test(expected = IllegalArgumentException.class)
public void testConstructor_FromUrlString_AllDataIncluded_BadDataTypeManagerId()
throws Exception {
String dtmId = "123bad_id123";
String dtId = "3295333330922457056";
String name = "string";
String urlString = "datatype:/" + dtmId + "?uid=" + dtId + "&name=" + name;
new DataTypeUrl(urlString);
}
@Test(expected = IllegalArgumentException.class)
public void testConstructor_FromUrlString_AllDataIncluded_BadDataTypeId() throws Exception {
String dtmId = "3295333330922457057";
String dtId = "bad_id";
String name = "string";
String urlString = "datatype:/" + dtmId + "?uid=" + dtId + "&name=" + name;
new DataTypeUrl(urlString);
}
@Test
public void testConstructor_FromUrlString_NoDataTypeId() throws Exception {
String dtmId = "3295333330922457057";
String dtId = "";
String name = "string";
String urlString = "datatype:/" + dtmId + "?uid=" + dtId + "&name=" + name;
DataTypeUrl dtUrl = new DataTypeUrl(urlString);
assertNotNull(dtUrl.getDataTypeManagerId());
assertNull(dtUrl.getDataTypeId());
assertEquals(name, dtUrl.getDataTypeName());
}
@Test(expected = IllegalArgumentException.class)
public void testConstructor_FromUrlString_NoDataTypeManagerId() throws Exception {
String dtmId = "";
String dtId = "3295333330922457056";
String name = "string";
String urlString = "datatype:/" + dtmId + "?uid=" + dtId + "&name=" + name;
new DataTypeUrl(urlString);
}
@Test(expected = IllegalArgumentException.class)
public void testConstructor_FromUrlString_NoDataTypeName() throws Exception {
String dtmId = "3295333330922457057";
String dtId = "3295333330922457056";
String name = " ";
String urlString = "datatype:/" + dtmId + "?uid=" + dtId + "&name=" + name;
new DataTypeUrl(urlString);
}
@Test
public void testGetDataType() {
String name = "string";
String dtmId = "3295333330922457057";
FakeDataTypeManager manager = new FakeDataTypeManager(dtmId);
FakeDataType dt = new FakeDataType(name, manager);
DataTypeUrl dtUrl = new DataTypeUrl(dt);
DataTypeManagerService service = new FakeDataTypeManagerService(manager);
DataType actualDt = dtUrl.getDataType(service);
assertEquals(dt, actualDt);
}
@Test
public void testGetDataType_ByName() {
String name = "string";
String dtmId = "3295333330922457057";
FakeDataTypeManager manager = new FakeDataTypeManager(dtmId);
FakeDataType dt = new FakeDataType(name, manager);
String dtId = ""; // no id; name only
String urlString = "datatype:/" + dtmId + "?uid=" + dtId + "&name=" + name;
DataTypeUrl dtUrl = new DataTypeUrl(urlString);
DataTypeManagerService service = new FakeDataTypeManagerService(manager);
DataType actualDt = dtUrl.getDataType(service);
assertEquals(dt, actualDt);
}
@Test
public void testEquals() {
String name = "string";
FakeDataType dt = new FakeDataType(name);
DataTypeUrl dtUrl1 = new DataTypeUrl(dt);
DataTypeUrl dtUrl2 = new DataTypeUrl(dt);
assertEquals(dtUrl1, dtUrl2);
FakeDataType otherDt = new FakeDataType("otherType");
DataTypeUrl otherDtUrl = new DataTypeUrl(otherDt);
assertNotEquals(dtUrl1, otherDtUrl);
}
@Test
public void testHashCode() {
String name = "string";
FakeDataType dt = new FakeDataType(name);
DataTypeUrl dtUrl1 = new DataTypeUrl(dt);
DataTypeUrl dtUrl2 = new DataTypeUrl(dt);
assertEquals(dtUrl1.hashCode(), dtUrl2.hashCode());
FakeDataType otherDt = new FakeDataType("otherType");
DataTypeUrl otherDtUrl = new DataTypeUrl(otherDt);
assertNotEquals(dtUrl1.hashCode(), otherDtUrl.hashCode());
}
@Test
public void testToString() {
String dtmId = "3295333330922457057";
String dtId = "3295333330922457056";
String name = "string";
String urlString = "datatype:/" + dtmId + "?uid=" + dtId + "&name=" + name;
DataTypeUrl dtUrl = new DataTypeUrl(urlString);
assertEquals(urlString, dtUrl.toString());
}
//==================================================================================================
// Inner Classes
//==================================================================================================
private class FakeDataType extends TestDoubleDataType {
private DataTypeManager manager = new FakeDataTypeManager();
FakeDataType(String name) {
super(name);
}
FakeDataType(String name, FakeDataTypeManager manager) {
super(name);
this.manager = manager;
manager.addDataType(this);
}
@Override
public DataTypeManager getDataTypeManager() {
return manager;
}
}
private class FakeDataTypeManager extends TestDoubleDataTypeManager {
private UniversalID id;
private List<DataType> types = new ArrayList<>();
FakeDataTypeManager() {
id = UniversalIdGenerator.nextID();
}
FakeDataTypeManager(String idString) {
id = new UniversalID(Long.parseLong(idString));
}
void addDataType(DataType dt) {
types.add(dt);
}
@Override
public UniversalID getUniversalID() {
return id;
}
@Override
public DataType getDataType(DataTypePath path) {
for (DataType dt : types) {
if (dt.getName().equals(path.getDataTypeName())) {
return dt;
}
}
return null;
}
@Override
public DataType findDataTypeForID(UniversalID datatypeID) {
for (DataType dt : types) {
if (dt.getUniversalID().equals(datatypeID)) {
return dt;
}
}
return null;
}
}
private class FakeDataTypeManagerService extends TestDoubleDataTypeManagerService {
private DataTypeManager manager;
FakeDataTypeManagerService(DataTypeManager manager) {
this.manager = manager;
}
@Override
public DataTypeManager[] getDataTypeManagers() {
return new DataTypeManager[] { manager };
}
}
}

View File

@ -82,6 +82,10 @@ public class HistoryList<T> {
* True signals that this list will allow duplicate entries. False signals to not only not
* 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
*
@ -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;
}
@ -172,6 +175,18 @@ public class HistoryList<T> {
broadcast(t);
}
/**
* Performs a {@link #goBack()} until the given item becomes the current item. This is
* useful if you wish to go backward to a specific item in the list.
*
* @param t the item
*/
public void goBackTo(T t) {
while (!getCurrentHistoryItem().equals(t) && hasPrevious()) {
goBack();
}
}
/**
* Moves this history list's current item pointer forward one and then calls the user-provided
* callback to signal the newly selected item.
@ -187,6 +202,18 @@ public class HistoryList<T> {
broadcast(t);
}
/**
* Performs a {@link #goForward()} until the given item becomes the current item. This is
* useful if you wish to go forward to a specific item in the list.
*
* @param t the item
*/
public void goForwardTo(T t) {
while (!getCurrentHistoryItem().equals(t) && hasNext()) {
goForward();
}
}
/**
* Returns the item currently pointed to within the list of items. When an item is
* added, this will be that item. Otherwise, it will be the last item navigated.
@ -217,7 +244,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
*/

View File

@ -15,7 +15,7 @@
*/
package util;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.util.LinkedList;
@ -425,6 +425,32 @@ public class HistoryListTest {
assertNextItems();
}
@Test
public void testBackToItem() {
addHistory(A);
addHistory(B);
addHistory(C);
historyList.goBackTo(A);
assertCurrentItem(A);
}
@Test
public void testForwardToItem() {
addHistory(A);
addHistory(B);
addHistory(C);
goBack();
goBack();
goBack();
assertCurrentItem(A);
historyList.goForwardTo(C);
assertCurrentItem(C);
}
//==================================================================================================
// Private Methods
//==================================================================================================

View File

@ -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,16 +108,15 @@ 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(),
saveFile.getName(), newUniversalId.getValue(), TaskMonitorAdapter.DUMMY_MONITOR);
packedDB = ((PackedDBHandle) dbHandle).saveAs("DTArchive", saveFile.getParentFile(),
saveFile.getName(), newUniversalId.getValue(), TaskMonitorAdapter.DUMMY_MONITOR);
file = resourceSaveFile;
updateRootCategoryName(resourceSaveFile, getRootCategory());
}
@ -134,9 +133,8 @@ public class FileDataTypeManager extends StandAloneDataTypeManager implements
ResourceFile resourceSaveFile = new ResourceFile(saveFile);
validateFilename(resourceSaveFile);
try {
packedDB =
((PackedDBHandle) dbHandle).saveAs("DTArchive", saveFile.getParentFile(),
saveFile.getName(), TaskMonitorAdapter.DUMMY_MONITOR);
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();
}
}

View File

@ -0,0 +1,288 @@
/* ###
* 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.program.model.data;
import java.net.URL;
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
import ghidra.docking.settings.Settings;
import ghidra.docking.settings.SettingsDefinition;
import ghidra.program.model.mem.MemBuffer;
import ghidra.util.*;
import ghidra.util.exception.DuplicateNameException;
/**
* A stub of the {@link DataType} interface. This can be used to supply a test values
* or to spy on system internals by overriding methods as needed.
*/
public class TestDoubleDataType implements DataType {
private UniversalID id;
private String name;
public TestDoubleDataType(String name) {
this.name = name;
this.id = UniversalIdGenerator.nextID();
}
@Override
public String toString() {
return name;
}
@Override
public boolean isDynamicallySized() {
throw new UnsupportedOperationException();
}
@Override
public boolean isNotYetDefined() {
throw new UnsupportedOperationException();
}
@Override
public SettingsDefinition[] getSettingsDefinitions() {
throw new UnsupportedOperationException();
}
@Override
public Settings getDefaultSettings() {
throw new UnsupportedOperationException();
}
@Override
public DataType clone(DataTypeManager dtm) {
throw new UnsupportedOperationException();
}
@Override
public DataType copy(DataTypeManager dtm) {
throw new UnsupportedOperationException();
}
@Override
public CategoryPath getCategoryPath() {
throw new UnsupportedOperationException();
}
@Override
public DataTypePath getDataTypePath() {
throw new UnsupportedOperationException();
}
@Override
public void setCategoryPath(CategoryPath path) throws DuplicateNameException {
throw new UnsupportedOperationException();
}
@Override
public DataTypeManager getDataTypeManager() {
throw new UnsupportedOperationException();
}
@Override
public String getDisplayName() {
return "Test double data type '" + getName() + "'";
}
@Override
public String getName() {
return name;
}
@Override
public String getPathName() {
throw new UnsupportedOperationException();
}
@Override
public void setName(String name) throws InvalidNameException, DuplicateNameException {
throw new UnsupportedOperationException();
}
@Override
public void setNameAndCategory(CategoryPath path, String name)
throws InvalidNameException, DuplicateNameException {
throw new UnsupportedOperationException();
}
@Override
public String getMnemonic(Settings settings) {
throw new UnsupportedOperationException();
}
@Override
public int getLength() {
throw new UnsupportedOperationException();
}
@Override
public String getDescription() {
throw new UnsupportedOperationException();
}
@Override
public void setDescription(String description) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public URL getDocs() {
throw new UnsupportedOperationException();
}
@Override
public Object getValue(MemBuffer buf, Settings settings, int length) {
throw new UnsupportedOperationException();
}
@Override
public Class<?> getValueClass(Settings settings) {
throw new UnsupportedOperationException();
}
@Override
public String getDefaultLabelPrefix() {
throw new UnsupportedOperationException();
}
@Override
public String getDefaultAbbreviatedLabelPrefix() {
throw new UnsupportedOperationException();
}
@Override
public String getDefaultLabelPrefix(MemBuffer buf, Settings settings, int len,
DataTypeDisplayOptions options) {
throw new UnsupportedOperationException();
}
@Override
public String getDefaultOffcutLabelPrefix(MemBuffer buf, Settings settings, int len,
DataTypeDisplayOptions options, int offcutOffset) {
throw new UnsupportedOperationException();
}
@Override
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
throw new UnsupportedOperationException();
}
@Override
public boolean isDeleted() {
throw new UnsupportedOperationException();
}
@Override
public boolean isEquivalent(DataType dt) {
throw new UnsupportedOperationException();
}
@Override
public void dataTypeSizeChanged(DataType dt) {
throw new UnsupportedOperationException();
}
@Override
public void dataTypeDeleted(DataType dt) {
throw new UnsupportedOperationException();
}
@Override
public void dataTypeReplaced(DataType oldDt, DataType newDt) {
throw new UnsupportedOperationException();
}
@Override
public void setDefaultSettings(Settings settings) {
throw new UnsupportedOperationException();
}
@Override
public void addParent(DataType dt) {
throw new UnsupportedOperationException();
}
@Override
public void removeParent(DataType dt) {
throw new UnsupportedOperationException();
}
@Override
public void dataTypeNameChanged(DataType dt, String oldName) {
throw new UnsupportedOperationException();
}
@Override
public DataType[] getParents() {
throw new UnsupportedOperationException();
}
@Override
public int getAlignment() {
throw new UnsupportedOperationException();
}
@Override
public boolean dependsOn(DataType dt) {
throw new UnsupportedOperationException();
}
@Override
public SourceArchive getSourceArchive() {
throw new UnsupportedOperationException();
}
@Override
public void setSourceArchive(SourceArchive archive) {
throw new UnsupportedOperationException();
}
@Override
public long getLastChangeTime() {
throw new UnsupportedOperationException();
}
@Override
public long getLastChangeTimeInSourceArchive() {
throw new UnsupportedOperationException();
}
@Override
public UniversalID getUniversalID() {
return id;
}
@Override
public void replaceWith(DataType dataType) {
throw new UnsupportedOperationException();
}
@Override
public void setLastChangeTime(long lastChangeTime) {
throw new UnsupportedOperationException();
}
@Override
public void setLastChangeTimeInSourceArchive(long lastChangeTimeInSourceArchive) {
throw new UnsupportedOperationException();
}
@Override
public DataOrganization getDataOrganization() {
throw new UnsupportedOperationException();
}
}

View File

@ -0,0 +1,342 @@
/* ###
* 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.program.model.data;
import java.util.*;
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
import ghidra.util.*;
import ghidra.util.task.TaskMonitor;
/**
* A stub of the {@link DataTypeManager} interface. This can be used to supply a test values
* or to spy on system internals by overriding methods as needed.
*/
public class TestDoubleDataTypeManager implements DataTypeManager {
private UniversalID id;
public TestDoubleDataTypeManager() {
this.id = UniversalIdGenerator.nextID();
}
@Override
public UniversalID getUniversalID() {
return id;
}
@Override
public boolean containsCategory(CategoryPath path) {
throw new UnsupportedOperationException();
}
@Override
public String getUniqueName(CategoryPath path, String baseName) {
throw new UnsupportedOperationException();
}
@Override
public DataType resolve(DataType dataType, DataTypeConflictHandler handler) {
throw new UnsupportedOperationException();
}
@Override
public DataType addDataType(DataType dataType, DataTypeConflictHandler handler) {
throw new UnsupportedOperationException();
}
@Override
public Iterator<DataType> getAllDataTypes() {
throw new UnsupportedOperationException();
}
@Override
public void getAllDataTypes(List<DataType> list) {
throw new UnsupportedOperationException();
}
@Override
public Iterator<Structure> getAllStructures() {
throw new UnsupportedOperationException();
}
@Override
public Iterator<Composite> getAllComposites() {
throw new UnsupportedOperationException();
}
@Override
public void findDataTypes(String name, List<DataType> list) {
throw new UnsupportedOperationException();
}
@Override
public void findDataTypes(String name, List<DataType> list, boolean caseSensitive,
TaskMonitor monitor) {
throw new UnsupportedOperationException();
}
@Override
public DataType replaceDataType(DataType existingDt, DataType replacementDt,
boolean updateCategoryPath) throws DataTypeDependencyException {
throw new UnsupportedOperationException();
}
@Override
public DataType getDataType(String dataTypePath) {
throw new UnsupportedOperationException();
}
@Override
public DataType findDataType(String dataTypePath) {
throw new UnsupportedOperationException();
}
@Override
public DataType getDataType(DataTypePath dataTypePath) {
throw new UnsupportedOperationException();
}
@Override
public long getResolvedID(DataType dt) {
throw new UnsupportedOperationException();
}
@Override
public long getID(DataType dt) {
throw new UnsupportedOperationException();
}
@Override
public DataType getDataType(long dataTypeID) {
throw new UnsupportedOperationException();
}
@Override
public Category getCategory(long categoryID) {
throw new UnsupportedOperationException();
}
@Override
public Category getCategory(CategoryPath path) {
throw new UnsupportedOperationException();
}
@Override
public void dataTypeChanged(DataType dataType) {
throw new UnsupportedOperationException();
}
@Override
public void addDataTypeManagerListener(DataTypeManagerChangeListener l) {
throw new UnsupportedOperationException();
}
@Override
public void removeDataTypeManagerListener(DataTypeManagerChangeListener l) {
throw new UnsupportedOperationException();
}
@Override
public void addInvalidatedListener(InvalidatedListener listener) {
throw new UnsupportedOperationException();
}
@Override
public void removeInvalidatedListener(InvalidatedListener listener) {
throw new UnsupportedOperationException();
}
@Override
public boolean remove(DataType dataType, TaskMonitor monitor) {
throw new UnsupportedOperationException();
}
@Override
public boolean contains(DataType dataType) {
throw new UnsupportedOperationException();
}
@Override
public Category createCategory(CategoryPath path) {
throw new UnsupportedOperationException();
}
@Override
public DataType getDataType(CategoryPath path, String name) {
throw new UnsupportedOperationException();
}
@Override
public String getName() {
throw new UnsupportedOperationException();
}
@Override
public void setName(String name) throws InvalidNameException {
throw new UnsupportedOperationException();
}
@Override
public int startTransaction(String description) {
throw new UnsupportedOperationException();
}
@Override
public boolean isUpdatable() {
throw new UnsupportedOperationException();
}
@Override
public void endTransaction(int transactionID, boolean commit) {
throw new UnsupportedOperationException();
}
@Override
public void flushEvents() {
throw new UnsupportedOperationException();
}
@Override
public void close() {
throw new UnsupportedOperationException();
}
@Override
public Pointer getPointer(DataType datatype) {
throw new UnsupportedOperationException();
}
@Override
public Pointer getPointer(DataType datatype, int size) {
throw new UnsupportedOperationException();
}
@Override
public Category getRootCategory() {
throw new UnsupportedOperationException();
}
@Override
public boolean isFavorite(DataType datatype) {
throw new UnsupportedOperationException();
}
@Override
public void setFavorite(DataType datatype, boolean isFavorite) {
throw new UnsupportedOperationException();
}
@Override
public List<DataType> getFavorites() {
throw new UnsupportedOperationException();
}
@Override
public int getCategoryCount() {
throw new UnsupportedOperationException();
}
@Override
public int getDataTypeCount(boolean includePointersAndArrays) {
throw new UnsupportedOperationException();
}
@Override
public void findEnumValueNames(long value, Set<String> enumValueNames) {
throw new UnsupportedOperationException();
}
@Override
public DataType getDataType(SourceArchive sourceArchive, UniversalID datatypeID) {
throw new UnsupportedOperationException();
}
@Override
public DataType findDataTypeForID(UniversalID datatypeID) {
throw new UnsupportedOperationException();
}
@Override
public long getLastChangeTimeForMyManager() {
throw new UnsupportedOperationException();
}
@Override
public SourceArchive getSourceArchive(UniversalID sourceID) {
throw new UnsupportedOperationException();
}
@Override
public ArchiveType getType() {
throw new UnsupportedOperationException();
}
@Override
public List<DataType> getDataTypes(SourceArchive sourceArchive) {
throw new UnsupportedOperationException();
}
@Override
public SourceArchive getLocalSourceArchive() {
throw new UnsupportedOperationException();
}
@Override
public void associateDataTypeWithArchive(DataType datatype, SourceArchive archive) {
throw new UnsupportedOperationException();
}
@Override
public void disassociate(DataType datatype) {
throw new UnsupportedOperationException();
}
@Override
public boolean updateSourceArchiveName(String archiveFileID, String name) {
throw new UnsupportedOperationException();
}
@Override
public boolean updateSourceArchiveName(UniversalID sourceID, String name) {
throw new UnsupportedOperationException();
}
@Override
public DataOrganization getDataOrganization() {
throw new UnsupportedOperationException();
}
@Override
public List<SourceArchive> getSourceArchives() {
throw new UnsupportedOperationException();
}
@Override
public void removeSourceArchive(SourceArchive sourceArchive) {
throw new UnsupportedOperationException();
}
@Override
public SourceArchive resolveSourceArchive(SourceArchive sourceArchive) {
throw new UnsupportedOperationException();
}
@Override
public Set<DataType> getDataTypesContaining(DataType dataType) {
throw new UnsupportedOperationException();
}
}