mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
Merge remote-tracking branch 'origin/GP-3344_dev747368_applydataarchives_choice--SQUASHED'
This commit is contained in:
commit
5396d68128
14 changed files with 828 additions and 247 deletions
|
@ -15,18 +15,28 @@
|
|||
*/
|
||||
package ghidra.app.plugin.core.analysis;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import docking.options.editor.FileChooserEditor;
|
||||
import docking.options.editor.StringWithChoicesEditor;
|
||||
import generic.jar.ResourceFile;
|
||||
import ghidra.app.cmd.function.ApplyFunctionDataTypesCmd;
|
||||
import ghidra.app.plugin.core.datamgr.util.DataTypeArchiveUtility;
|
||||
import ghidra.app.services.*;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.framework.Application;
|
||||
import ghidra.framework.model.*;
|
||||
import ghidra.framework.options.OptionType;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.FileDataTypeManager;
|
||||
import ghidra.program.model.listing.DataTypeArchive;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.VersionException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
|
@ -35,12 +45,36 @@ public class ApplyDataArchiveAnalyzer extends AbstractAnalyzer {
|
|||
private static final String DESCRIPTION =
|
||||
"Apply known data type archives based on program information.";
|
||||
|
||||
protected static final String OPTION_NAME_CREATE_BOOKMARKS = "Create Analysis Bookmarks";
|
||||
private static final String OPTION_DESCRIPTION_CREATE_BOOKMARKS =
|
||||
"If checked, an analysis bookmark will be created at each symbol address " +
|
||||
"where multiple function definitions were found and not applied.";
|
||||
private static final String OPTION_NAME_CREATE_BOOKMARKS = "Create Analysis Bookmarks";
|
||||
private static final String OPTION_DESCRIPTION_CREATE_BOOKMARKS = """
|
||||
If checked, an analysis bookmark will be created at each symbol address \
|
||||
where multiple function definitions were found and not applied.""";
|
||||
private static final boolean OPTION_DEFAULT_CREATE_BOOKMARKS_ENABLED = true;
|
||||
|
||||
private static final String OPTION_NAME_ARCHIVE_CHOOSER = "Archive Chooser";
|
||||
private static final String OPTION_DESCRIPTION_ARCHIVE_CHOOSER =
|
||||
"Specifies the data type archive to apply";
|
||||
|
||||
private static final String OPTION_NAME_GDT_FILEPATH = "GDT User File Archive Path";
|
||||
private static final String OPTION_DESCRIPTION_GDT_FILEPATH = """
|
||||
Path to a user-supplied data type archive .gdt file, \
|
||||
only valid when 'Archive Chooser' is '[User-File-Archive]'""";
|
||||
|
||||
private static final String OPTION_NAME_PROJECT_PATH = "User Project Archive Path";
|
||||
private static final String OPTION_DESCRIPTION_PROJECT_PATH = """
|
||||
Path to a user-supplied data type archive located in the project, \
|
||||
only valid when 'Archive Chooser' is '[User-Project-Archive]'""";
|
||||
|
||||
private static final String CHOOSER_AUTO_DETECT = "[Auto-Detect]";
|
||||
private static final String CHOOSER_USER_FILE_ARCHIVE = "[User-File-Archive]";
|
||||
private static final String CHOOSER_USER_PROJECT_ARCHIVE = "[User-Project-Archive]";
|
||||
|
||||
private boolean createBookmarksEnabled = OPTION_DEFAULT_CREATE_BOOKMARKS_ENABLED;
|
||||
private String archiveChooser = CHOOSER_AUTO_DETECT;
|
||||
private File userGdtFileArchive;
|
||||
private String userProjectArchive;
|
||||
private Map<String, ResourceFile> builtinGDTs = getBuiltInGdts();
|
||||
private DataTypeManagerService dtmService;
|
||||
|
||||
public ApplyDataArchiveAnalyzer() {
|
||||
super(NAME, DESCRIPTION, AnalyzerType.BYTE_ANALYZER);
|
||||
|
@ -50,52 +84,24 @@ public class ApplyDataArchiveAnalyzer extends AbstractAnalyzer {
|
|||
|
||||
@Override
|
||||
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log) {
|
||||
AutoAnalysisManager mgr = AutoAnalysisManager.getAnalysisManager(program);
|
||||
DataTypeManagerService service = mgr.getDataTypeManagerService();
|
||||
dtmService = AutoAnalysisManager.getAnalysisManager(program).getDataTypeManagerService();
|
||||
|
||||
// pick the archives to apply
|
||||
List<String> archiveList = DataTypeArchiveUtility.getArchiveList(program);
|
||||
List<DataTypeManager> managerList = new ArrayList<>();
|
||||
monitor.initialize(archiveList.size());
|
||||
// pick the archives to apply, typically 0 or 1
|
||||
List<DataTypeManager> managerList = getDataTypeArchives(program, log, monitor);
|
||||
|
||||
// apply the archive restricted to the address set
|
||||
for (String archiveName : archiveList) {
|
||||
if (monitor.isCancelled()) {
|
||||
break;
|
||||
}
|
||||
DataTypeManager dtm = null;
|
||||
try {
|
||||
dtm = service.openDataTypeArchive(archiveName);
|
||||
if (dtm == null) {
|
||||
log.appendMsg("Apply Data Archives",
|
||||
"Failed to locate data type archive: " + archiveName);
|
||||
}
|
||||
else {
|
||||
managerList.add(dtm);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
Throwable cause = e.getCause();
|
||||
if (cause instanceof VersionException) {
|
||||
log.appendMsg("Apply Data Archives",
|
||||
"Unable to open archive " + archiveName + ": " + cause.toString());
|
||||
}
|
||||
else {
|
||||
String msg = e.getMessage();
|
||||
if (msg == null) {
|
||||
msg = e.toString();
|
||||
}
|
||||
log.appendMsg("Apply Data Archives",
|
||||
"Unexpected Error opening archive " + archiveName + ": " + msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!managerList.isEmpty()) {
|
||||
monitor.setMessage("Applying Function Signatures...");
|
||||
|
||||
// TODO: SourceType of imported is not exactly right here.
|
||||
// This isn't imported. Need to add some other sourceType, like SecondaryInfo
|
||||
ApplyFunctionDataTypesCmd cmd = new ApplyFunctionDataTypesCmd(managerList, set,
|
||||
SourceType.IMPORTED, false, createBookmarksEnabled);
|
||||
cmd.applyTo(program, monitor);
|
||||
|
||||
for (DataTypeManager dtm : managerList) {
|
||||
Msg.info(this, "Applied data type archive: %s".formatted(dtm.getName()));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -103,12 +109,177 @@ public class ApplyDataArchiveAnalyzer extends AbstractAnalyzer {
|
|||
public void registerOptions(Options options, Program program) {
|
||||
options.registerOption(OPTION_NAME_CREATE_BOOKMARKS, createBookmarksEnabled, null,
|
||||
OPTION_DESCRIPTION_CREATE_BOOKMARKS);
|
||||
|
||||
List<String> chooserList = new ArrayList<>();
|
||||
chooserList.add(CHOOSER_AUTO_DETECT);
|
||||
chooserList.add(CHOOSER_USER_FILE_ARCHIVE);
|
||||
chooserList.add(CHOOSER_USER_PROJECT_ARCHIVE);
|
||||
chooserList.addAll(builtinGDTs.keySet());
|
||||
|
||||
options.registerOption(OPTION_NAME_ARCHIVE_CHOOSER, OptionType.STRING_TYPE,
|
||||
CHOOSER_AUTO_DETECT, null, OPTION_DESCRIPTION_ARCHIVE_CHOOSER,
|
||||
new StringWithChoicesEditor(chooserList));
|
||||
|
||||
options.registerOption(OPTION_NAME_GDT_FILEPATH, OptionType.FILE_TYPE, null, null,
|
||||
OPTION_DESCRIPTION_GDT_FILEPATH,
|
||||
new FileChooserEditor(FileDataTypeManager.GDT_FILEFILTER));
|
||||
options.registerOption(OPTION_NAME_PROJECT_PATH, OptionType.STRING_TYPE, null, null,
|
||||
OPTION_DESCRIPTION_PROJECT_PATH, new ProjectPathChooserEditor(
|
||||
"Choose Data Type Archive", DATATYPEARCHIVE_PROJECT_FILTER));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void optionsChanged(Options options, Program program) {
|
||||
createBookmarksEnabled =
|
||||
options.getBoolean(OPTION_NAME_CREATE_BOOKMARKS, createBookmarksEnabled);
|
||||
archiveChooser = options.getString(OPTION_NAME_ARCHIVE_CHOOSER, archiveChooser);
|
||||
userGdtFileArchive = options.getFile(OPTION_NAME_GDT_FILEPATH, userGdtFileArchive);
|
||||
userProjectArchive = options.getString(OPTION_NAME_PROJECT_PATH, userProjectArchive);
|
||||
}
|
||||
|
||||
private List<DataTypeManager> getDataTypeArchives(Program program, MessageLog log,
|
||||
TaskMonitor monitor) {
|
||||
switch (archiveChooser) {
|
||||
case CHOOSER_AUTO_DETECT:
|
||||
return getAutoDTMs(program, log, monitor);
|
||||
case CHOOSER_USER_FILE_ARCHIVE:
|
||||
return openUserFileArchive(userGdtFileArchive, log);
|
||||
case CHOOSER_USER_PROJECT_ARCHIVE:
|
||||
return openUserProjectArchive(userProjectArchive, program, log, monitor);
|
||||
default:
|
||||
return openBuiltinGDT(archiveChooser, log);
|
||||
}
|
||||
}
|
||||
|
||||
private List<DataTypeManager> getAutoDTMs(Program program, MessageLog log,
|
||||
TaskMonitor monitor) {
|
||||
List<String> archiveList = DataTypeArchiveUtility.getArchiveList(program);
|
||||
List<DataTypeManager> result = new ArrayList<>();
|
||||
monitor.initialize(archiveList.size());
|
||||
|
||||
for (String archiveName : archiveList) {
|
||||
if (monitor.isCancelled()) {
|
||||
break;
|
||||
}
|
||||
try {
|
||||
DataTypeManager dtm = dtmService.openDataTypeArchive(archiveName);
|
||||
if (dtm == null) {
|
||||
log.appendMsg("Apply Data Archives",
|
||||
"Failed to locate data type archive: " + archiveName);
|
||||
}
|
||||
else {
|
||||
result.add(dtm);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
Throwable cause = e.getCause();
|
||||
if (cause instanceof VersionException) {
|
||||
log.appendMsg("Apply Data Archives",
|
||||
"Unable to open archive %s: %s".formatted(archiveName, cause.toString()));
|
||||
}
|
||||
else {
|
||||
String msg = Objects.requireNonNullElse(e.getMessage(), e.toString());
|
||||
log.appendMsg("Apply Data Archives",
|
||||
"Unexpected Error opening archive %s: %s".formatted(archiveName, msg));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<DataTypeManager> openBuiltinGDT(String gdtName, MessageLog log) {
|
||||
// opens a gdt that was included in the ghidra distro, not the 'built-in' dtm.
|
||||
|
||||
ResourceFile gdtFile = builtinGDTs.get(gdtName);
|
||||
if (gdtFile == null) {
|
||||
log.appendMsg("Unknown built-in archive: %s".formatted(gdtName));
|
||||
return List.of();
|
||||
}
|
||||
try {
|
||||
return List.of(dtmService.openArchive(gdtFile, false));
|
||||
}
|
||||
catch (Exception e) {
|
||||
Throwable cause = e.getCause();
|
||||
if (cause instanceof VersionException) {
|
||||
log.appendMsg("Apply Data Archives",
|
||||
"Unable to open archive %s: %s".formatted(gdtName, cause.toString()));
|
||||
}
|
||||
else {
|
||||
String msg = Objects.requireNonNullElse(e.getMessage(), e.toString());
|
||||
log.appendMsg("Apply Data Archives",
|
||||
"Unexpected Error opening archive %s: %s".formatted(gdtName, msg));
|
||||
}
|
||||
}
|
||||
return List.of();
|
||||
}
|
||||
|
||||
private List<DataTypeManager> openUserFileArchive(File gdtFile, MessageLog log) {
|
||||
if (gdtFile == null) {
|
||||
return List.of();
|
||||
}
|
||||
if (!gdtFile.isFile()) {
|
||||
log.appendMsg("Missing archive: %s".formatted(gdtFile));
|
||||
return List.of();
|
||||
}
|
||||
try {
|
||||
return List.of(dtmService.openArchive(new ResourceFile(gdtFile), false));
|
||||
}
|
||||
catch (Exception e) {
|
||||
Throwable cause = e.getCause();
|
||||
if (cause instanceof VersionException) {
|
||||
log.appendMsg("Apply Data Archives",
|
||||
"Unable to open archive %s: %s".formatted(gdtFile, cause.toString()));
|
||||
}
|
||||
else {
|
||||
String msg = Objects.requireNonNullElse(e.getMessage(), e.toString());
|
||||
log.appendMsg("Apply Data Archives",
|
||||
"Unexpected Error opening archive %s: %s".formatted(gdtFile, msg));
|
||||
}
|
||||
}
|
||||
return List.of();
|
||||
}
|
||||
|
||||
private List<DataTypeManager> openUserProjectArchive(String filename, Program program,
|
||||
MessageLog log, TaskMonitor monitor) {
|
||||
if (filename == null || filename.isBlank()) {
|
||||
return List.of();
|
||||
}
|
||||
ProjectData projectData = program.getDomainFile().getParent().getProjectData();
|
||||
DomainFile gdtDomainFile = projectData.getFile(filename);
|
||||
if (gdtDomainFile == null) {
|
||||
log.appendMsg("Missing project archive: %s".formatted(filename));
|
||||
return List.of();
|
||||
}
|
||||
if (!DataTypeArchive.class.isAssignableFrom(gdtDomainFile.getDomainObjectClass())) {
|
||||
log.appendMsg("Bad project file type: %s".formatted(filename));
|
||||
return List.of();
|
||||
}
|
||||
|
||||
try {
|
||||
return List.of(dtmService.openArchive(gdtDomainFile, monitor));
|
||||
}
|
||||
catch (Exception e) {
|
||||
Throwable cause = e.getCause();
|
||||
if (cause instanceof VersionException) {
|
||||
log.appendMsg("Apply Data Archives",
|
||||
"Unable to open project archive %s: %s".formatted(filename, cause.toString()));
|
||||
}
|
||||
else {
|
||||
String msg = Objects.requireNonNullElse(e.getMessage(), e.toString());
|
||||
log.appendMsg("Apply Data Archives",
|
||||
"Unexpected Error opening project archive %s: %s".formatted(filename, msg));
|
||||
}
|
||||
}
|
||||
return List.of();
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------
|
||||
|
||||
private static Map<String, ResourceFile> getBuiltInGdts() {
|
||||
return Application.findFilesByExtensionInApplication(".gdt")
|
||||
.stream()
|
||||
.collect(Collectors.toMap(f -> f.getName(), f -> f));
|
||||
}
|
||||
|
||||
private static final DomainFileFilter DATATYPEARCHIVE_PROJECT_FILTER =
|
||||
df -> DataTypeArchive.class.isAssignableFrom(df.getDomainObjectClass());
|
||||
}
|
||||
|
|
|
@ -15,116 +15,27 @@
|
|||
*/
|
||||
package ghidra.app.plugin.core.analysis;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import generic.jar.ResourceFile;
|
||||
import ghidra.app.plugin.core.datamgr.archive.*;
|
||||
import ghidra.app.plugin.core.datamgr.util.DataTypeArchiveUtility;
|
||||
import ghidra.app.plugin.core.datamgr.archive.BuiltInSourceArchive;
|
||||
import ghidra.app.plugin.core.datamgr.archive.DefaultDataTypeArchiveService;
|
||||
import ghidra.app.plugin.core.datamgr.util.DataTypeComparator;
|
||||
import ghidra.app.services.DataTypeManagerService;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.DataTypeArchive;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.DataTypeManagerChangeListener;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.UniversalID;
|
||||
|
||||
// FIXME!! TESTING
|
||||
public class DefaultDataTypeManagerService implements DataTypeManagerService {
|
||||
|
||||
private Map<String, FileDataTypeManager> archiveMap = new HashMap<>();
|
||||
private DataTypeManager builtInDataTypesManager = BuiltInDataTypeManager.getDataTypeManager();
|
||||
|
||||
void dispose() {
|
||||
for (FileDataTypeManager dtfm : archiveMap.values()) {
|
||||
dtfm.close();
|
||||
}
|
||||
archiveMap.clear();
|
||||
}
|
||||
public class DefaultDataTypeManagerService extends DefaultDataTypeArchiveService
|
||||
implements DataTypeManagerService {
|
||||
|
||||
// TODO: This implementation needs to be consolidated with the tool-based service in
|
||||
// favor of a single static data type manager service used by both the tool and
|
||||
// headless scenarios
|
||||
|
||||
private FileDataTypeManager findOpenFileArchiveWithID(UniversalID universalID) {
|
||||
if (universalID == null) {
|
||||
return null;
|
||||
}
|
||||
for (FileDataTypeManager dtm : archiveMap.values()) {
|
||||
if (universalID.equals(dtm.getUniversalID()) && !dtm.isClosed()) {
|
||||
return dtm;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized DataTypeManager openDataTypeArchive(String archiveName)
|
||||
throws IOException, DuplicateIdException {
|
||||
|
||||
if (archiveMap.containsKey(archiveName)) {
|
||||
FileDataTypeManager dtm = archiveMap.get(archiveName);
|
||||
if (!dtm.isClosed()) {
|
||||
return dtm;
|
||||
}
|
||||
archiveMap.remove(archiveName);
|
||||
}
|
||||
|
||||
ResourceFile archiveFile = DataTypeArchiveUtility.findArchiveFile(archiveName);
|
||||
if (archiveFile == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
FileDataTypeManager fileDtm = FileDataTypeManager.openFileArchive(archiveFile, false);
|
||||
|
||||
FileDataTypeManager existingDtm = findOpenFileArchiveWithID(fileDtm.getUniversalID());
|
||||
if (existingDtm != null) {
|
||||
fileDtm.close();
|
||||
throw new DuplicateIdException(fileDtm.getName(), existingDtm.getName());
|
||||
}
|
||||
|
||||
archiveMap.put(archiveName, fileDtm);
|
||||
|
||||
return fileDtm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeArchive(DataTypeManager dtm) {
|
||||
|
||||
String archiveName = null;
|
||||
Set<Entry<String, FileDataTypeManager>> entries = archiveMap.entrySet();
|
||||
for (Entry<String, FileDataTypeManager> entry : entries) {
|
||||
FileDataTypeManager manager = entry.getValue();
|
||||
if (manager.equals(dtm)) {
|
||||
archiveName = entry.getKey();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (archiveName != null) {
|
||||
FileDataTypeManager manager = archiveMap.get(archiveName);
|
||||
archiveMap.remove(archiveName);
|
||||
manager.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeManager[] getDataTypeManagers() {
|
||||
ArrayList<FileDataTypeManager> dtmList = new ArrayList<>();
|
||||
for (FileDataTypeManager dtm : archiveMap.values()) {
|
||||
if (!dtm.isClosed()) {
|
||||
dtmList.add(dtm);
|
||||
}
|
||||
}
|
||||
DataTypeManager[] managers = new DataTypeManager[dtmList.size()];
|
||||
dtmList.toArray(managers);
|
||||
return managers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HelpLocation getEditorHelpLocation(DataType dataType) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
@ -145,11 +56,6 @@ public class DefaultDataTypeManagerService implements DataTypeManagerService {
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeManager getBuiltInDataTypesManager() {
|
||||
return builtInDataTypesManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType getDataType(String filterText) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
@ -206,14 +112,4 @@ public class DefaultDataTypeManagerService implements DataTypeManagerService {
|
|||
public Set<String> getPossibleEquateNames(long value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Archive openArchive(File file, boolean acquireWriteLock) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Archive openArchive(DataTypeArchive dataTypeArchive) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.plugin.core.analysis;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.beans.PropertyEditorSupport;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import docking.widgets.button.BrowseButton;
|
||||
import ghidra.framework.main.DataTreeDialog;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.framework.model.DomainFileFilter;
|
||||
|
||||
/**
|
||||
* Bean editor to show a text field and a browse button to bring
|
||||
* up a Domain File Chooser dialog. The path of the chosen domain file is returned as
|
||||
* a String value.
|
||||
*/
|
||||
public class ProjectPathChooserEditor extends PropertyEditorSupport {
|
||||
|
||||
private final static int NUMBER_OF_COLUMNS = 20;
|
||||
private JTextField textField = new JTextField(NUMBER_OF_COLUMNS);
|
||||
private MouseListener otherMouseListener;
|
||||
private String title;
|
||||
private DomainFileFilter filter;
|
||||
|
||||
public ProjectPathChooserEditor() {
|
||||
this(null, null);
|
||||
}
|
||||
|
||||
public ProjectPathChooserEditor(String title, DomainFileFilter filter) {
|
||||
this.title = title;
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAsText() {
|
||||
return textField.getText().trim();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
String text = getAsText();
|
||||
if (StringUtils.isBlank(text)) {
|
||||
return null;
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAsText(String text) throws IllegalArgumentException {
|
||||
if (text == null || text.trim().isEmpty()) {
|
||||
text = "";
|
||||
}
|
||||
|
||||
textField.setText(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Object value) {
|
||||
if (value == null) {
|
||||
setAsText("");
|
||||
}
|
||||
else if (value instanceof String s) {
|
||||
setAsText(s);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsCustomEditor() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getCustomEditor() {
|
||||
return new ProjectFileChooserPanel();
|
||||
}
|
||||
|
||||
void setMouseListener(MouseListener listener) {
|
||||
this.otherMouseListener = listener;
|
||||
}
|
||||
|
||||
private class ProjectFileChooserPanel extends JPanel {
|
||||
private JButton browseButton;
|
||||
|
||||
private ProjectFileChooserPanel() {
|
||||
BoxLayout bl = new BoxLayout(this, BoxLayout.X_AXIS);
|
||||
setLayout(bl);
|
||||
|
||||
browseButton = new BrowseButton();
|
||||
|
||||
add(textField);
|
||||
add(Box.createHorizontalStrut(5));
|
||||
add(browseButton);
|
||||
setBorder(BorderFactory.createEmptyBorder());
|
||||
textField.addActionListener(e -> ProjectPathChooserEditor.this.firePropertyChange());
|
||||
textField.getDocument().addDocumentListener(new TextListener());
|
||||
|
||||
browseButton.addActionListener(e -> displayFileChooser());
|
||||
if (otherMouseListener != null) {
|
||||
textField.addMouseListener(otherMouseListener);
|
||||
browseButton.addMouseListener(otherMouseListener);
|
||||
}
|
||||
}
|
||||
|
||||
private void displayFileChooser() {
|
||||
AtomicReference<String> result = new AtomicReference<>();
|
||||
DataTreeDialog dataTreeDialog =
|
||||
new DataTreeDialog(this, title, DataTreeDialog.OPEN, filter);
|
||||
dataTreeDialog.addOkActionListener(e -> {
|
||||
dataTreeDialog.close();
|
||||
DomainFile df = dataTreeDialog.getDomainFile();
|
||||
result.set(df != null ? df.getPathname() : null);
|
||||
});
|
||||
dataTreeDialog.showComponent();
|
||||
|
||||
String newPath = result.get();
|
||||
if (newPath != null) {
|
||||
textField.setText(newPath);
|
||||
ProjectPathChooserEditor.this.firePropertyChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class TextListener implements DocumentListener {
|
||||
|
||||
@Override
|
||||
public void changedUpdate(DocumentEvent e) {
|
||||
ProjectPathChooserEditor.this.firePropertyChange();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
ProjectPathChooserEditor.this.firePropertyChange();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeUpdate(DocumentEvent e) {
|
||||
ProjectPathChooserEditor.this.firePropertyChange();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -45,8 +45,7 @@ import ghidra.app.plugin.core.datamgr.editor.DataTypeEditorManager;
|
|||
import ghidra.app.plugin.core.datamgr.tree.ArchiveNode;
|
||||
import ghidra.app.plugin.core.datamgr.util.DataDropOnBrowserHandler;
|
||||
import ghidra.app.plugin.core.datamgr.util.DataTypeChooserDialog;
|
||||
import ghidra.app.services.CodeViewerService;
|
||||
import ghidra.app.services.DataTypeManagerService;
|
||||
import ghidra.app.services.*;
|
||||
import ghidra.app.util.HelpTopics;
|
||||
import ghidra.framework.Application;
|
||||
import ghidra.framework.main.OpenVersionedFileDialog;
|
||||
|
@ -62,7 +61,10 @@ import ghidra.program.model.listing.DataTypeArchive;
|
|||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.datastruct.LRUMap;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.VersionException;
|
||||
import ghidra.util.task.TaskLauncher;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* Plugin to pop up the dialog to manage data types in the program
|
||||
|
@ -78,11 +80,12 @@ import ghidra.util.task.TaskLauncher;
|
|||
description = "Provides the window for managing and categorizing dataTypes. " +
|
||||
"The datatype display shows all built-in datatypes, datatypes in the " +
|
||||
"current program, and datatypes in all open archives.",
|
||||
servicesProvided = { DataTypeManagerService.class }
|
||||
servicesProvided = { DataTypeManagerService.class, DataTypeArchiveService.class }
|
||||
)
|
||||
//@formatter:on
|
||||
public class DataTypeManagerPlugin extends ProgramPlugin
|
||||
implements DomainObjectListener, DataTypeManagerService, PopupActionProvider {
|
||||
implements DomainObjectListener, DataTypeManagerService, DataTypeArchiveService,
|
||||
PopupActionProvider {
|
||||
|
||||
private static final String EXTENSIONS_PATH_PREFIX = Path.GHIDRA_HOME + "/Extensions";
|
||||
|
||||
|
@ -557,6 +560,20 @@ public class DataTypeManagerPlugin extends ProgramPlugin
|
|||
return dataTypeManagerHandler.openArchive(archiveName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeManager openArchive(ResourceFile file, boolean acquireWriteLock)
|
||||
throws IOException, DuplicateIdException {
|
||||
Archive archive = openArchive(file.getFile(true), acquireWriteLock);
|
||||
return archive.getDataTypeManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeManager openArchive(DomainFile domainFile, TaskMonitor monitor)
|
||||
throws VersionException, CancelledException, IOException, DuplicateIdException {
|
||||
DataTypeArchive archive = openArchive(domainFile);
|
||||
return archive.getDataTypeManager();
|
||||
}
|
||||
|
||||
public List<Archive> getAllArchives() {
|
||||
return dataTypeManagerHandler.getAllArchives();
|
||||
}
|
||||
|
|
|
@ -36,7 +36,6 @@ import ghidra.framework.GenericRunInfo;
|
|||
import ghidra.framework.preferences.Preferences;
|
||||
import ghidra.program.model.data.FileDataTypeManager;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.filechooser.ExtensionFileFilter;
|
||||
|
||||
public class OpenArchiveAction extends DockingAction {
|
||||
|
||||
|
@ -59,8 +58,7 @@ public class OpenArchiveAction extends DockingAction {
|
|||
GhidraFileChooser fileChooser = new GhidraFileChooser(tree);
|
||||
|
||||
File archiveDirectory = getArchiveDirectory();
|
||||
fileChooser.setFileFilter(new ExtensionFileFilter(
|
||||
new String[] { FileDataTypeManager.EXTENSION }, "Ghidra Data Type Files"));
|
||||
fileChooser.setFileFilter(FileDataTypeManager.GDT_FILEFILTER);
|
||||
fileChooser.setCurrentDirectory(archiveDirectory);
|
||||
fileChooser.setApproveButtonText("Open DataType Archive File");
|
||||
fileChooser.setApproveButtonToolTipText("Open DataType Archive File");
|
||||
|
|
|
@ -0,0 +1,231 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.plugin.core.datamgr.archive;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import generic.jar.ResourceFile;
|
||||
import ghidra.app.plugin.core.datamgr.util.DataTypeArchiveUtility;
|
||||
import ghidra.app.services.DataTypeArchiveService;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.program.database.data.ProgramDataTypeManager;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.DataTypeArchive;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.UniversalID;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.VersionException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* Simple, non-ui implementation of the {@link DataTypeArchiveService} interface.
|
||||
*/
|
||||
public class DefaultDataTypeArchiveService implements DataTypeArchiveService {
|
||||
protected record DataTypeManagerInfo(ResourceFile file, DomainObject domainObject, String name,
|
||||
DataTypeManager dtm) {
|
||||
public boolean isClosed() {
|
||||
return dtm instanceof FileDataTypeManager fdtm
|
||||
? fdtm.isClosed()
|
||||
: false;
|
||||
}
|
||||
}
|
||||
|
||||
protected Map<UniversalID, DataTypeManagerInfo> openDTMs = new HashMap<>();
|
||||
protected BuiltInDataTypeManager builtInDataTypesManager;
|
||||
|
||||
public DefaultDataTypeArchiveService() {
|
||||
this.builtInDataTypesManager = BuiltInDataTypeManager.getDataTypeManager();
|
||||
}
|
||||
|
||||
public synchronized void dispose() {
|
||||
for (DataTypeManagerInfo dtmInfo : new ArrayList<>(openDTMs.values())) {
|
||||
closeDTM(dtmInfo); // mutates openDTMs map
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeManager getBuiltInDataTypesManager() {
|
||||
return builtInDataTypesManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeManager[] getDataTypeManagers() {
|
||||
List<DataTypeManager> dtmList = openDTMs.values()
|
||||
.stream()
|
||||
.filter(dtmInfo -> !dtmInfo.isClosed())
|
||||
.map(dtmInfo -> dtmInfo.dtm())
|
||||
.collect(Collectors.toList());
|
||||
return dtmList.toArray(DataTypeManager[]::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void closeArchive(DataTypeManager dtm) {
|
||||
if (dtm instanceof BuiltInDataTypeManager) {
|
||||
Msg.info(this, "Cannot close the built-in Data Type Manager");
|
||||
return;
|
||||
}
|
||||
|
||||
if (dtm instanceof ProgramDataTypeManager) {
|
||||
Msg.info(this, "Cannot close the Program's Data Type Manager");
|
||||
return;
|
||||
}
|
||||
|
||||
DataTypeManagerInfo dtmInfo = openDTMs.get(dtm.getUniversalID());
|
||||
if (dtmInfo == null) {
|
||||
Msg.info(this, "Unable close archive; archive not open: '%s'".formatted(dtm.getName()));
|
||||
return;
|
||||
}
|
||||
|
||||
beforeCloseDataTypeManager(dtmInfo);
|
||||
openDTMs.remove(dtm.getUniversalID());
|
||||
|
||||
if (dtmInfo.domainObject != null) {
|
||||
dtmInfo.domainObject.release(this);
|
||||
}
|
||||
dtmInfo.dtm.close();
|
||||
|
||||
afterCloseDataTypeManager(dtmInfo);
|
||||
}
|
||||
|
||||
@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 DataTypeManager openDataTypeArchive(String archiveName)
|
||||
throws IOException, DuplicateIdException {
|
||||
ResourceFile file = DataTypeArchiveUtility.findArchiveFile(archiveName);
|
||||
if (file != null) {
|
||||
return openArchive(file, false);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized DataTypeManager openArchive(DomainFile domainFile, TaskMonitor monitor)
|
||||
throws VersionException, CancelledException, IOException, DuplicateIdException {
|
||||
|
||||
if (!DataTypeArchive.class.isAssignableFrom(domainFile.getDomainObjectClass())) {
|
||||
throw new IOException("Unable to open domain file: '%s', not a data type archive"
|
||||
.formatted(domainFile.getName()));
|
||||
}
|
||||
|
||||
DataTypeManagerInfo dtmInfo = getOpenDTMInfo(domainFile);
|
||||
if (dtmInfo == null) {
|
||||
DataTypeArchive dta = openDomainFile(domainFile, monitor);
|
||||
DataTypeManager dtm = dta.getDataTypeManager();
|
||||
dtmInfo = addDTM(new DataTypeManagerInfo(null, dta, domainFile.getPathname(), dtm));
|
||||
}
|
||||
|
||||
return dtmInfo.dtm;
|
||||
}
|
||||
|
||||
protected DataTypeArchive openDomainFile(DomainFile domainFile, TaskMonitor monitor)
|
||||
throws VersionException, CancelledException, IOException {
|
||||
DataTypeArchive dta =
|
||||
(DataTypeArchive) domainFile.getDomainObject(this, false, false, monitor);
|
||||
return dta;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized DataTypeManager openArchive(ResourceFile file, boolean acquireWriteLock)
|
||||
throws IOException, DuplicateIdException {
|
||||
|
||||
file = file.getCanonicalFile();
|
||||
DataTypeManagerInfo dtmInfo = getOpenDTMInfo(file);
|
||||
if (dtmInfo == null) {
|
||||
FileDataTypeManager fileDTM =
|
||||
FileDataTypeManager.openFileArchive(file, acquireWriteLock);
|
||||
|
||||
dtmInfo = addDTM(new DataTypeManagerInfo(file, null, file.getName(), fileDTM));
|
||||
}
|
||||
return dtmInfo.dtm;
|
||||
}
|
||||
|
||||
protected DataTypeManagerInfo addDTM(DataTypeManagerInfo dtmInfo) throws DuplicateIdException {
|
||||
DataTypeManagerInfo existingDTM = openDTMs.get(dtmInfo.dtm.getUniversalID());
|
||||
if (existingDTM != null) {
|
||||
dtmInfo.dtm.close();
|
||||
throw new DuplicateIdException(dtmInfo.name(), existingDTM.name());
|
||||
}
|
||||
openDTMs.put(dtmInfo.dtm.getUniversalID(), dtmInfo);
|
||||
afterAddDataTypeManager(dtmInfo);
|
||||
return dtmInfo;
|
||||
}
|
||||
|
||||
protected void closeDTM(DataTypeManagerInfo dtmInfo) {
|
||||
beforeCloseDataTypeManager(dtmInfo);
|
||||
openDTMs.remove(dtmInfo.dtm.getUniversalID());
|
||||
|
||||
if (dtmInfo.domainObject != null) {
|
||||
dtmInfo.domainObject.release(this);
|
||||
}
|
||||
dtmInfo.dtm.close();
|
||||
|
||||
afterCloseDataTypeManager(dtmInfo);
|
||||
}
|
||||
|
||||
private DataTypeManagerInfo getOpenDTMInfo(ResourceFile file) {
|
||||
for (DataTypeManagerInfo dtmInfo : openDTMs.values()) {
|
||||
if (dtmInfo.file != null && dtmInfo.file.equals(file)) {
|
||||
if (dtmInfo.isClosed()) {
|
||||
openDTMs.remove(dtmInfo.dtm.getUniversalID());
|
||||
return null;
|
||||
}
|
||||
return dtmInfo;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private DataTypeManagerInfo getOpenDTMInfo(DomainFile projectFile) {
|
||||
for (DataTypeManagerInfo dtmInfo : openDTMs.values()) {
|
||||
if (dtmInfo.domainObject != null &&
|
||||
dtmInfo.domainObject.getDomainFile().equals(projectFile)) {
|
||||
if (dtmInfo.isClosed()) {
|
||||
openDTMs.remove(dtmInfo.dtm.getUniversalID());
|
||||
return null;
|
||||
}
|
||||
return dtmInfo;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void afterAddDataTypeManager(DataTypeManagerInfo dtmInfo) {
|
||||
// override as needed
|
||||
}
|
||||
|
||||
protected void afterCloseDataTypeManager(DataTypeManagerInfo dtmInfo) {
|
||||
// override as needed
|
||||
}
|
||||
|
||||
protected void beforeCloseDataTypeManager(DataTypeManagerInfo dtmInfo) {
|
||||
// override as needed
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
/* ###
|
||||
* 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 generic.jar.ResourceFile;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.archive.Archive;
|
||||
import ghidra.app.plugin.core.datamgr.archive.DuplicateIdException;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.framework.plugintool.ServiceInfo;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.listing.DataTypeArchive;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.VersionException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* A service that manages a set of data type archives, allowing re-use of already open
|
||||
* archives.
|
||||
*/
|
||||
//@formatter:off
|
||||
@ServiceInfo(
|
||||
defaultProvider = DataTypeManagerPlugin.class,
|
||||
description = "Service to manipulate the set of active Data Type Managers"
|
||||
)
|
||||
//@formatter:on
|
||||
public interface DataTypeArchiveService {
|
||||
|
||||
/**
|
||||
* Get the data type manager that has all of the built in types.
|
||||
* @return data type manager for built in data types
|
||||
*/
|
||||
public DataTypeManager getBuiltInDataTypesManager();
|
||||
|
||||
/**
|
||||
* Gets the open data type managers.
|
||||
*
|
||||
* @return the open data type managers.
|
||||
*/
|
||||
public DataTypeManager[] getDataTypeManagers();
|
||||
|
||||
/**
|
||||
* Closes the archive for the given {@link DataTypeManager}. This will ignore request to
|
||||
* close the open Program's manager and the built-in manager.
|
||||
*
|
||||
* @param dtm the data type manager of the archive to close
|
||||
*/
|
||||
public void closeArchive(DataTypeManager dtm);
|
||||
|
||||
/**
|
||||
* Opens a data type archive that was built into the Ghidra installation.
|
||||
* <p>
|
||||
* NOTE: This is predicated upon all archive files having a unique name within the installation.
|
||||
* <p>
|
||||
* Any path prefix specified may prevent the file from opening (or reopening) correctly.
|
||||
*
|
||||
* @param archiveName archive file name (i.e., "generic_C_lib")
|
||||
* @return the data type archive or null if an archive with the specified name
|
||||
* can not be found.
|
||||
* @throws IOException if an i/o error occurs opening the data type archive
|
||||
* @throws DuplicateIdException if another archive with the same ID is already open
|
||||
*/
|
||||
public DataTypeManager openDataTypeArchive(String archiveName)
|
||||
throws IOException, DuplicateIdException;
|
||||
|
||||
/**
|
||||
* Opens the specified gdt (file based) data type archive.
|
||||
*
|
||||
* @param file gdt file
|
||||
* @param acquireWriteLock true if write lock should be acquired (i.e., open for update)
|
||||
* @return the data type archive
|
||||
* @throws IOException if an i/o error occurs opening the data type archive
|
||||
* @throws DuplicateIdException if another archive with the same ID is already open
|
||||
*/
|
||||
public DataTypeManager openArchive(ResourceFile file, boolean acquireWriteLock)
|
||||
throws IOException, DuplicateIdException;
|
||||
|
||||
/**
|
||||
* Opens the specified project-located data type archive.
|
||||
*
|
||||
* @param domainFile archive file located in the current project
|
||||
* @param monitor {@link TaskMonitor} to display progess during the opening
|
||||
* @return the data type archive
|
||||
* @throws IOException if an i/o error occurs opening the data type archive
|
||||
* @throws DuplicateIdException if another archive with the same ID is already open
|
||||
* @throws VersionException
|
||||
* @throws CancelledException
|
||||
*/
|
||||
public DataTypeManager openArchive(DomainFile domainFile, TaskMonitor monitor)
|
||||
throws VersionException, CancelledException, IOException, DuplicateIdException;
|
||||
|
||||
/**
|
||||
* A method to open an Archive for the given, pre-existing DataTypeArchive (like one that
|
||||
* was opened during the import process.
|
||||
*
|
||||
* @param dataTypeArchive the archive from which to create an Archive
|
||||
* @return an Archive based upon the given DataTypeArchive
|
||||
*/
|
||||
@Deprecated
|
||||
public Archive openArchive(DataTypeArchive dataTypeArchive);
|
||||
|
||||
/**
|
||||
* A method to open an Archive for the given, pre-existing archive file (*.gdt)
|
||||
*
|
||||
* @param file data type archive file
|
||||
* @param acquireWriteLock true if write lock should be acquired (i.e., open for update)
|
||||
* @return an Archive based upon the given archive files
|
||||
* @throws IOException if an i/o error occurs opening the data type archive
|
||||
* @throws DuplicateIdException if another archive with the same ID is already open
|
||||
*/
|
||||
@Deprecated
|
||||
public Archive openArchive(File file, boolean acquireWriteLock)
|
||||
throws IOException, DuplicateIdException;
|
||||
|
||||
|
||||
}
|
|
@ -15,19 +15,15 @@
|
|||
*/
|
||||
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.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.archive.Archive;
|
||||
import ghidra.app.plugin.core.datamgr.archive.DuplicateIdException;
|
||||
import ghidra.framework.plugintool.ServiceInfo;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.DataTypeArchive;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.DataTypeManagerChangeListener;
|
||||
import ghidra.util.HelpLocation;
|
||||
|
||||
/**
|
||||
|
@ -35,14 +31,13 @@ import ghidra.util.HelpLocation;
|
|||
* "favorites." Favorites will show up on the popup menu for creating
|
||||
* data and defining function return types and parameters.
|
||||
*/
|
||||
@ServiceInfo(defaultProvider = DataTypeManagerPlugin.class, description = "Service to provide list of cycle groups and data types identified as 'Favorites.'")
|
||||
public interface DataTypeManagerService extends DataTypeQueryService {
|
||||
|
||||
/**
|
||||
* Get the data type manager that has all of the built in types.
|
||||
* @return data type manager for built in data types
|
||||
*/
|
||||
public DataTypeManager getBuiltInDataTypesManager();
|
||||
//@formatter:off
|
||||
@ServiceInfo(
|
||||
defaultProvider = DataTypeManagerPlugin.class,
|
||||
description = "Service to provide list of cycle groups and data types identified as 'Favorites.'"
|
||||
)
|
||||
//@formatter:on
|
||||
public interface DataTypeManagerService extends DataTypeQueryService, DataTypeArchiveService {
|
||||
|
||||
/**
|
||||
* Get the data types marked as favorites that will show up on
|
||||
|
@ -101,48 +96,6 @@ public interface DataTypeManagerService extends DataTypeQueryService {
|
|||
*/
|
||||
public void edit(DataType dt);
|
||||
|
||||
/**
|
||||
* Closes the archive for the given {@link DataTypeManager}. This will ignore request to
|
||||
* close the open Program's manager and the built-in manager.
|
||||
*
|
||||
* @param dtm the data type manager of the archive to close
|
||||
*/
|
||||
public void closeArchive(DataTypeManager dtm);
|
||||
|
||||
/**
|
||||
* Opens the specified data type archive contained within the Ghidra installation.
|
||||
* NOTE: This is predicated upon all archive files having a unique name within the installation.
|
||||
* Any path prefix specified may prevent the file from opening (or reopening) correctly.
|
||||
* @param archiveName archive file name (i.e., "generic_C_lib")
|
||||
* @return the data type archive or null if an archive with the specified name
|
||||
* can not be found.
|
||||
* @throws IOException if an i/o error occurs opening the data type archive
|
||||
* @throws DuplicateIdException if another archive with the same ID is already open
|
||||
*/
|
||||
public DataTypeManager openDataTypeArchive(String archiveName)
|
||||
throws IOException, DuplicateIdException;
|
||||
|
||||
/**
|
||||
* A method to open an Archive for the given, pre-existing DataTypeArchive (like one that
|
||||
* was opened during the import process.
|
||||
*
|
||||
* @param dataTypeArchive the archive from which to create an Archive
|
||||
* @return an Archive based upon the given DataTypeArchive
|
||||
*/
|
||||
public Archive openArchive(DataTypeArchive dataTypeArchive);
|
||||
|
||||
/**
|
||||
* A method to open an Archive for the given, pre-existing archive file (*.gdt)
|
||||
*
|
||||
* @param file data type archive file
|
||||
* @param acquireWriteLock true if write lock should be acquired (i.e., open for update)
|
||||
* @return an Archive based upon the given archive files
|
||||
* @throws IOException if an i/o error occurs opening the data type archive
|
||||
* @throws DuplicateIdException if another archive with the same ID is already open
|
||||
*/
|
||||
public Archive openArchive(File file, boolean acquireWriteLock)
|
||||
throws IOException, DuplicateIdException;
|
||||
|
||||
/**
|
||||
* Selects the given data type in the display of data types. A null <code>dataType</code>
|
||||
* value will clear the current selection.
|
||||
|
|
|
@ -18,7 +18,6 @@ package ghidra.app.services;
|
|||
import java.util.List;
|
||||
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
|
||||
/**
|
||||
* Simplified datatype service interface to provide query capabilities
|
||||
|
@ -26,13 +25,6 @@ import ghidra.program.model.data.DataTypeManager;
|
|||
*/
|
||||
public interface DataTypeQueryService {
|
||||
|
||||
/**
|
||||
* Gets the open data type managers.
|
||||
*
|
||||
* @return the open data type managers.
|
||||
*/
|
||||
public DataTypeManager[] getDataTypeManagers();
|
||||
|
||||
/**
|
||||
* Gets the sorted list of all datatypes known by this service via it's owned DataTypeManagers.
|
||||
* This method can be called frequently, as the underlying data is indexed and only updated
|
||||
|
|
|
@ -18,8 +18,6 @@ package ghidra.app.util.parser;
|
|||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.help.UnsupportedOperationException;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ghidra.app.services.DataTypeQueryService;
|
||||
|
@ -348,11 +346,6 @@ public class FunctionSignatureParser {
|
|||
dtCache.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeManager[] getDataTypeManagers() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DataType> getSortedDataTypeList() {
|
||||
return service.getSortedDataTypeList();
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
*/
|
||||
package help.screenshot;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.geom.GeneralPath;
|
||||
|
@ -45,7 +46,6 @@ import docking.widgets.fieldpanel.support.FieldLocation;
|
|||
import docking.widgets.table.*;
|
||||
import docking.widgets.table.threaded.ThreadedTableModel;
|
||||
import docking.widgets.tree.GTree;
|
||||
import generic.jar.ResourceFile;
|
||||
import generic.test.AbstractGenericTest;
|
||||
import generic.theme.GThemeDefaults.Colors;
|
||||
import generic.theme.GThemeDefaults.Colors.Java;
|
||||
|
@ -138,9 +138,8 @@ public abstract class AbstractScreenShotGenerator extends AbstractGhidraHeadedIn
|
|||
public void loadProgram() throws Exception {
|
||||
loadProgram("WinHelloCPP.exe");
|
||||
|
||||
ResourceFile file = TestEnv.findProvidedDataTypeArchive("windows_vs12_32.gdt");
|
||||
DataTypeManagerService dtm = tool.getService(DataTypeManagerService.class);
|
||||
dtm.openArchive(file.getFile(false), false);
|
||||
DataTypeManagerService dtms = tool.getService(DataTypeManagerService.class);
|
||||
dtms.openDataTypeArchive("windows_vs12_32.gdt");
|
||||
}
|
||||
|
||||
public void closeNonProgramArchives() {
|
||||
|
|
|
@ -22,11 +22,16 @@ import java.util.Set;
|
|||
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import generic.jar.ResourceFile;
|
||||
import ghidra.app.plugin.core.datamgr.archive.Archive;
|
||||
import ghidra.app.plugin.core.datamgr.archive.DuplicateIdException;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.DataTypeArchive;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.VersionException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* A stub of the {@link DataTypeManagerService} interface. This can be used to supply a test values
|
||||
|
@ -135,4 +140,16 @@ public class TestDoubleDataTypeManagerService implements DataTypeManagerService
|
|||
public Set<String> getPossibleEquateNames(long value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeManager openArchive(ResourceFile file, boolean acquireWriteLock)
|
||||
throws IOException, DuplicateIdException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeManager openArchive(DomainFile domainFile, TaskMonitor monitor)
|
||||
throws VersionException, CancelledException, IOException, DuplicateIdException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.apache.commons.lang3.StringUtils;
|
|||
import docking.widgets.button.BrowseButton;
|
||||
import docking.widgets.filechooser.GhidraFileChooser;
|
||||
import docking.widgets.filechooser.GhidraFileChooserMode;
|
||||
import ghidra.util.filechooser.GhidraFileFilter;
|
||||
|
||||
/**
|
||||
* Bean editor to show a text field and a browse button to bring
|
||||
|
@ -42,8 +43,17 @@ public class FileChooserEditor extends PropertyEditorSupport {
|
|||
private JTextField textField = new JTextField(NUMBER_OF_COLUMNS);
|
||||
private File currentDir;
|
||||
private GhidraFileChooser fileChooser;
|
||||
private GhidraFileFilter fileFilter;
|
||||
private MouseListener otherMouseListener;
|
||||
|
||||
public FileChooserEditor() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public FileChooserEditor(GhidraFileFilter fileFilter) {
|
||||
this.fileFilter = fileFilter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAsText() {
|
||||
return textField.getText().trim();
|
||||
|
@ -74,14 +84,14 @@ public class FileChooserEditor extends PropertyEditorSupport {
|
|||
public void setValue(Object value) {
|
||||
if (value == null) {
|
||||
currentFileValue = null;
|
||||
textField.setText("");
|
||||
}
|
||||
|
||||
if (value instanceof File) {
|
||||
else if (value instanceof File) {
|
||||
currentFileValue = (File) value;
|
||||
textField.setText(currentFileValue.getAbsolutePath());
|
||||
}
|
||||
else if (value instanceof String) {
|
||||
setAsText((String) value);
|
||||
else if (value instanceof String s) {
|
||||
setAsText(s);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -162,6 +172,9 @@ public class FileChooserEditor extends PropertyEditorSupport {
|
|||
fileChooser.setApproveButtonText("Choose Path");
|
||||
fileChooser.setTitle("Choose Path");
|
||||
fileChooser.setFileSelectionMode(GhidraFileChooserMode.FILES_AND_DIRECTORIES);
|
||||
if (fileFilter != null) {
|
||||
fileChooser.setFileFilter(fileFilter);
|
||||
}
|
||||
if (currentFileValue != null) {
|
||||
fileChooser.setSelectedFile(currentFileValue);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,8 @@ import ghidra.program.model.lang.Language;
|
|||
import ghidra.util.InvalidNameException;
|
||||
import ghidra.util.UniversalID;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.filechooser.ExtensionFileFilter;
|
||||
import ghidra.util.filechooser.GhidraFileFilter;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
|
@ -37,6 +39,9 @@ public class FileDataTypeManager extends StandAloneDataTypeManager
|
|||
implements FileArchiveBasedDataTypeManager {
|
||||
|
||||
public final static String EXTENSION = "gdt"; // Ghidra Data Types
|
||||
public static final GhidraFileFilter GDT_FILEFILTER =
|
||||
ExtensionFileFilter.forExtensions("Ghidra Data Type Files", EXTENSION);
|
||||
|
||||
/**
|
||||
* Suffix for an archive file.
|
||||
*/
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue