diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/dbg/isf/IsfServer.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/dbg/isf/IsfServer.java
index 14d2d9067e..aeba8d0941 100644
--- a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/dbg/isf/IsfServer.java
+++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/dbg/isf/IsfServer.java
@@ -36,7 +36,6 @@ import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.FileDataTypeManager;
import ghidra.program.model.listing.Program;
import ghidra.util.Msg;
-import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitor;
public class IsfServer extends Thread {
@@ -101,13 +100,13 @@ public class IsfServer extends Thread {
try {
DataTypeManager dtm;
if (ns.endsWith(".gdt")) {
- dtm = openAsArchive(ns);
+ dtm = openAsDataTypeArchive(ns);
}
else if (ns.endsWith(".gzf")) {
- dtm = openAsDatabase(ns);
+ dtm = openAsProgramDatabase(ns);
}
else {
- dtm = openAsDomainFile(ns);
+ dtm = openAsProgramFile(ns);
}
managers.put(ns, dtm);
return dtm;
@@ -119,43 +118,43 @@ public class IsfServer extends Thread {
}
}
- private DataTypeManager openAsDomainFile(String ns) throws Exception {
+ private DataTypeManager openAsProgramFile(String ns) throws Exception {
ProjectData projectData = project.getProjectData();
DomainFile df = projectData.getFile(ns);
+ if (!Program.class.isAssignableFrom(df.getDomainObjectClass())) {
+ throw new IOException("File does not correspond to Program content: " + ns);
+ }
+
+ // FIXME: Need to track and release Program instance after DTM use is complete (GP-6895)
Program program = (Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY);
return program.getDataTypeManager();
}
- private DataTypeManager openAsArchive(String ns) throws Exception {
+ private DataTypeManager openAsDataTypeArchive(String ns) throws Exception {
File gdt = new File(ns);
return FileDataTypeManager.openFileArchive(gdt, false);
}
- private DataTypeManager openAsDatabase(String ns) throws Exception {
+ private DataTypeManager openAsProgramDatabase(String ns) throws Exception {
File gzf = new File(ns);
TaskMonitor dummy = TaskMonitor.DUMMY;
PackedDatabase db = PackedDatabase.getPackedDatabase(gzf, dummy);
+
DBHandle dbh = db.openForUpdate(dummy);
- ProgramDB p = null;
+
+ Program p;
+ boolean success = false;
try {
- p = new ProgramDB(dbh, OpenMode.UPDATE, dummy, this);
- }
- catch (VersionException e) {
- if (!e.isUpgradable()) {
- throw new RuntimeException(p + " uses an older version and is not upgradable.");
- }
+ p = new ProgramDB(dbh, OpenMode.UPGRADE, dummy, this);
+ success = true;
}
finally {
- dbh.close();
- }
-
- dbh = db.openForUpdate(dummy);
- p = new ProgramDB(dbh, OpenMode.UPGRADE, dummy, this);
-
- if (!p.isChanged()) {
- throw new RuntimeException(p + " uses an older version and was not upgraded.");
+ if (!success) {
+ dbh.close();
+ }
}
+ // FIXME: Need to track and release Program instance after DTM use is complete (GP-6895)
return p.getListing().getDataTypeManager();
}
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/export/TraceViewAsciiExporter.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/export/TraceViewAsciiExporter.java
deleted file mode 100644
index f31c1ffe8a..0000000000
--- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/export/TraceViewAsciiExporter.java
+++ /dev/null
@@ -1,27 +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.plugin.core.debug.export;
-
-import ghidra.app.util.exporter.AsciiExporter;
-import ghidra.framework.model.DomainObject;
-import ghidra.trace.model.Trace;
-
-public class TraceViewAsciiExporter extends AsciiExporter {
- @Override
- public boolean canExportDomainObject(Class extends DomainObject> domainObjectClass) {
- return Trace.class.isAssignableFrom(domainObjectClass);
- }
-}
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/export/TraceViewBinaryExporter.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/export/TraceViewBinaryExporter.java
deleted file mode 100644
index 2949322a91..0000000000
--- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/export/TraceViewBinaryExporter.java
+++ /dev/null
@@ -1,27 +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.plugin.core.debug.export;
-
-import ghidra.app.util.exporter.BinaryExporter;
-import ghidra.framework.model.DomainObject;
-import ghidra.trace.model.Trace;
-
-public class TraceViewBinaryExporter extends BinaryExporter {
- @Override
- public boolean canExportDomainObject(Class extends DomainObject> domainObjectClass) {
- return Trace.class.isAssignableFrom(domainObjectClass);
- }
-}
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/export/TraceViewHtmlExporter.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/export/TraceViewHtmlExporter.java
deleted file mode 100644
index b9c581e2c9..0000000000
--- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/export/TraceViewHtmlExporter.java
+++ /dev/null
@@ -1,27 +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.plugin.core.debug.export;
-
-import ghidra.app.util.exporter.HtmlExporter;
-import ghidra.framework.model.DomainObject;
-import ghidra.trace.model.Trace;
-
-public class TraceViewHtmlExporter extends HtmlExporter {
- @Override
- public boolean canExportDomainObject(Class extends DomainObject> domainObjectClass) {
- return Trace.class.isAssignableFrom(domainObjectClass);
- }
-}
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/export/TraceViewIntelHexExporter.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/export/TraceViewIntelHexExporter.java
deleted file mode 100644
index 96c85d60fd..0000000000
--- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/export/TraceViewIntelHexExporter.java
+++ /dev/null
@@ -1,27 +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.plugin.core.debug.export;
-
-import ghidra.app.util.exporter.IntelHexExporter;
-import ghidra.framework.model.DomainObject;
-import ghidra.trace.model.Trace;
-
-public class TraceViewIntelHexExporter extends IntelHexExporter {
- @Override
- public boolean canExportDomainObject(Class extends DomainObject> domainObjectClass) {
- return Trace.class.isAssignableFrom(domainObjectClass);
- }
-}
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/export/TraceViewXmlExporter.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/export/TraceViewXmlExporter.java
deleted file mode 100644
index 89778fc795..0000000000
--- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/export/TraceViewXmlExporter.java
+++ /dev/null
@@ -1,56 +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.plugin.core.debug.export;
-
-import java.util.*;
-import java.util.stream.Collectors;
-
-import ghidra.app.util.*;
-import ghidra.app.util.exporter.XmlExporter;
-import ghidra.framework.model.DomainObject;
-import ghidra.trace.model.Trace;
-
-// TODO: perhaps getApplicableExporters should use domainObject's class, not file's object class.
-// TODO: Where un-supported, be less abrasive, e.g., present empty managers.
-public class TraceViewXmlExporter extends XmlExporter {
- private final Map hideOpts = Map.of(
- "Properties", false,
- "Relocation Table", false,
- "External Libraries", false);
-
- @Override
- public boolean canExportDomainObject(Class extends DomainObject> domainObjectClass) {
- return Trace.class.isAssignableFrom(domainObjectClass);
- }
-
- @Override
- public List
+
gdt
+
+
+
File extension given to a compressed Ghidra Data Type Archive database file.
+
+
gzf
-
File extension given to Ghidra program database files that have been "zipped up".
+
File extension given to a compressed Ghidra Program database file.
+
+
gzt
+
+
+
File extension given to a compressed Ghidra Debugger Trace database file.
Project Window: Drag a file from the system file explorer application and drop
onto the Ghidra Project Tree destination folder. Dropping onto the table view is not
- supported. In the case of Ghidra Zip File (GZF) or Ghidra Data Type Archive (GDT) file
+ supported. In the case of Ghidra Zip File (GZF), Ghidra Zip Debugger Trace file (GZT),
+ or Ghidra Data Type Archive (GDT) file
imports, an immediate unpack can be performed wthout a popup dialog if the Front End option
- Enable simple GZF/GDT unpack is enabled (
- EditTool Options...File ImportEnable simple GZF/GDT unpack).
+ Enable simple GZF/GZT/GDT unpack is enabled (
+ EditTool Options...
+ File ImportEnable simple GZF/GZT/GDT unpack).
or Running Tool: Drag a file from the system file explorer application and drop
@@ -274,9 +277,10 @@
folder, otherwise the root folder will be the default. The ... will bring up a
dialog for changing the destination folder.
-
Program Name - This field specifies the name for the newly imported program.
+
Program Name - This field specifies the name for the newly imported file into
+ the active project.
By default, it will be the name of the imported file with any format specific extenstion
- removed (e.g., .xml, .gzf). Path information at the beginning of this field
+ removed (e.g., .xml, .gzf, .gzt, .gdt). Path information at the beginning of this field
will be used to create a destination folder in the current project under the root folder
specified by the Destination Folder field.
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/exporter/ExporterDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/exporter/ExporterDialog.java
index 6b6ce75542..d99e4ec2b6 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/exporter/ExporterDialog.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/exporter/ExporterDialog.java
@@ -317,7 +317,7 @@ public class ExporterDialog extends DialogComponentProvider implements AddressFa
private void chooseDestinationFile() {
GhidraFileChooser chooser = new GhidraFileChooser(getComponent());
- chooser.setSelectedFile(getLastExportDirectory());
+ chooser.setCurrentDirectory(getLastExportDirectory());
chooser.setTitle("Select Output File");
chooser.setApproveButtonText("Select Output File");
chooser.setApproveButtonToolTipText("Select File");
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/exporter/ExporterPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/exporter/ExporterPlugin.java
index 9e46e72e4b..a73c8c3aff 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/exporter/ExporterPlugin.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/exporter/ExporterPlugin.java
@@ -18,19 +18,25 @@ package ghidra.app.plugin.core.exporter;
import java.awt.event.KeyEvent;
import java.util.List;
-import docking.action.*;
+import javax.swing.KeyStroke;
+
+import docking.ActionContext;
+import docking.action.DockingAction;
+import docking.action.MenuData;
+import docking.action.builder.ActionBuilder;
+import docking.tool.ToolConstants;
import ghidra.app.CorePluginPackage;
-import ghidra.app.context.NavigatableActionContext;
-import ghidra.app.context.NavigatableContextAction;
+import ghidra.app.context.ProgramLocationActionContext;
import ghidra.app.plugin.PluginCategoryNames;
-import ghidra.app.services.CodeViewerService;
+import ghidra.app.plugin.ProgramPlugin;
import ghidra.framework.main.ApplicationLevelPlugin;
import ghidra.framework.main.FrontEndService;
import ghidra.framework.main.datatable.FrontendProjectTreeAction;
import ghidra.framework.main.datatable.ProjectDataContext;
import ghidra.framework.model.DomainFile;
import ghidra.framework.model.DomainFolder;
-import ghidra.framework.plugintool.*;
+import ghidra.framework.plugintool.PluginInfo;
+import ghidra.framework.plugintool.PluginTool;
import ghidra.framework.plugintool.util.PluginStatus;
import ghidra.program.model.listing.Program;
import ghidra.program.util.ProgramSelection;
@@ -45,7 +51,7 @@ import ghidra.util.HelpLocation;
description = "This plugin exports a program or datatype archive to an external file."
)
//@formatter:on
-public class ExporterPlugin extends Plugin implements ApplicationLevelPlugin {
+public class ExporterPlugin extends ProgramPlugin implements ApplicationLevelPlugin {
private FrontEndService frontEndService;
@@ -64,32 +70,39 @@ public class ExporterPlugin extends Plugin implements ApplicationLevelPlugin {
return; // do not add File menu Export Program action to front-end
}
- DockingAction action = new NavigatableContextAction("Export Program", getName()) {
-
- @Override
- protected void actionPerformed(NavigatableActionContext context) {
- Program program = context.getProgram();
- DomainFile domainFile = program.getDomainFile();
- ExporterDialog.showExporterDialog(tool, domainFile, program,
- context.getSelection());
- }
- };
- MenuData menuData =
- new MenuData(new String[] { "&File", "Export Program..." }, "Import Export");
- menuData.setMenuSubGroup("z"); // last in the "Save" group
- action.setMenuBarData(menuData);
- action.setKeyBindingData(new KeyBindingData(KeyEvent.VK_O, 0));
- action.setHelpLocation(new HelpLocation("ExporterPlugin", "Export"));
- action.setDescription(getPluginDescription().getDescription());
- tool.addAction(action);
+ new ActionBuilder("Export Program", getName())
+ .description(getPluginDescription().getDescription())
+ .helpLocation(new HelpLocation("ExporterPlugin", "Export"))
+ .menuPath(ToolConstants.MENU_FILE, "Export Program...")
+ .menuGroup("DomainObjectSaveExport")
+ .keyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_O, 0))
+ .enabledWhen(c -> getProgram(c) != null)
+ .onAction(c -> doExport(c))
+ .buildAndInstall(tool);
}
- protected ProgramSelection getSelection() {
- CodeViewerService service = tool.getService(CodeViewerService.class);
- if (service != null) {
- return service.getCurrentSelection();
+ private Program getProgram(ActionContext ctx) {
+ if (ctx instanceof ProgramLocationActionContext programCtx) {
+ Program p = programCtx.getProgram();
+ if (p != null) {
+ return p;
+ }
}
- return null;
+ return getCurrentProgram();
+ }
+
+ private ProgramSelection getProgramSelection(ActionContext ctx) {
+ if (ctx instanceof ProgramLocationActionContext programCtx) {
+ return programCtx.getSelection();
+ }
+ return getProgramSelection();
+ }
+
+ private void doExport(ActionContext ctx) {
+ Program program = getProgram(ctx);
+ DomainFile domainFile = program.getDomainFile();
+ ExporterDialog.showExporterDialog(tool, domainFile, program,
+ getProgramSelection(ctx));
}
private void createFrontEndAction() {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/MultiProgramManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/MultiProgramManager.java
index acd7db4b74..21ee8b0682 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/MultiProgramManager.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/MultiProgramManager.java
@@ -4,9 +4,9 @@
* 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.
@@ -76,8 +76,23 @@ class MultiProgramManager implements TransactionListener {
};
}
- void addProgram(Program p, ProgramLocator locator, int state) {
+ /**
+ * Add specified program.
+ *
+ * NOTE: If this is the first program to be added it will be forced to CURRENT state.
+ *
+ * @param p program to be added
+ * @param locator program location source information
+ * @param state initial state
+ * @return true if program is the current program
+ */
+ boolean addProgram(Program p, ProgramLocator locator, int state) {
+ if (programMap.isEmpty()) {
+ // Tool does not handle case where single open program is not current program
+ state = ProgramManager.OPEN_CURRENT;
+ }
addProgram(new ProgramInfo(p, locator, state != ProgramManager.OPEN_HIDDEN), state);
+ return state == ProgramManager.OPEN_CURRENT;
}
private void addProgram(ProgramInfo programInfo, int state) {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/ProgramManagerPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/ProgramManagerPlugin.java
index 718d446349..cb8d23d8a9 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/ProgramManagerPlugin.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/ProgramManagerPlugin.java
@@ -484,8 +484,7 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager, Opti
}
Runnable r = () -> {
- programMgr.addProgram(p, locator, state);
- if (state == ProgramManager.OPEN_CURRENT) {
+ if (programMgr.addProgram(p, locator, state)) {
programMgr.saveLocation();
}
contextChanged();
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/sourcefilestable/SourceFilesTablePlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/sourcefilestable/SourceFilesTablePlugin.java
index 0e2c3e1297..dd6e4796a5 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/sourcefilestable/SourceFilesTablePlugin.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/sourcefilestable/SourceFilesTablePlugin.java
@@ -161,14 +161,22 @@ public class SourceFilesTablePlugin extends ProgramPlugin implements OptionsChan
}
private boolean isEnabled(ListingActionContext context) {
+ Program p = getCurrentProgram();
+ if (p == null || p != context.getProgram()) {
+ return false;
+ }
Address address = context.getAddress();
- SourceFileManager manager = getCurrentProgram().getSourceFileManager();
+ SourceFileManager manager = p.getSourceFileManager();
return manager.getSourceMapEntries(address).size() > 0;
}
private void viewSourceFile(ListingActionContext context) {
+ Program p = getCurrentProgram();
+ if (p == null || p != context.getProgram()) {
+ return;
+ }
Address address = context.getAddress();
- SourceFileManager manager = getCurrentProgram().getSourceFileManager();
+ SourceFileManager manager = p.getSourceFileManager();
List entries = manager.getSourceMapEntries(address);
if (entries.isEmpty()) {
return; // sanity check
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/AsciiExporter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/AsciiExporter.java
index ece1a6ecfe..dc6caf5785 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/AsciiExporter.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/AsciiExporter.java
@@ -4,9 +4,9 @@
* 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.
@@ -30,7 +30,7 @@ import ghidra.util.task.TaskMonitor;
* An implementation of exporter that creates
* an Ascii representation of the program.
*/
-public class AsciiExporter extends Exporter {
+public class AsciiExporter extends ProgramExporter {
private ProgramTextOptions options;
/**
@@ -60,11 +60,14 @@ public class AsciiExporter extends Exporter {
log.clear();
- if (!(domainObj instanceof Program)) {
+ Program program;
+ try {
+ program = getProgram(domainObj);
+ }
+ catch (ClassCastException e) {
log.appendMsg("Unsupported type: " + domainObj.getClass().getName());
return false;
}
- Program program = (Program) domainObj;
getOptions(() -> program);
new ProgramTextWriter(file, program, addressSet, monitor, options, provider);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/BinaryExporter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/BinaryExporter.java
index be5ef9a285..39b6189fdc 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/BinaryExporter.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/BinaryExporter.java
@@ -4,9 +4,9 @@
* 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.
@@ -23,14 +23,15 @@ import ghidra.app.util.Option;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.Program;
-import ghidra.program.model.mem.*;
+import ghidra.program.model.mem.Memory;
+import ghidra.program.model.mem.MemoryAccessException;
import ghidra.util.HelpLocation;
import ghidra.util.task.TaskMonitor;
/**
* An {@link Exporter} that can export memory blocks as raw bytes
*/
-public class BinaryExporter extends Exporter {
+public class BinaryExporter extends ProgramExporter {
public BinaryExporter() {
super("Raw Bytes", "bin", new HelpLocation("ExporterPlugin", "binary"));
@@ -40,30 +41,27 @@ public class BinaryExporter extends Exporter {
public boolean export(File file, DomainObject domainObj, AddressSetView addrSet,
TaskMonitor monitor) throws IOException, ExporterException {
- if (!(domainObj instanceof Program)) {
+ Program program;
+ try {
+ program = getProgram(domainObj);
+ }
+ catch (ClassCastException e) {
log.appendMsg("Unsupported type: " + domainObj.getClass().getName());
return false;
}
- Program program = (Program) domainObj;
Memory memory = program.getMemory();
+ AddressSetView initializedAddressSet = memory.getAllInitializedAddressSet();
if (addrSet == null) {
- addrSet = memory;
+ addrSet = initializedAddressSet;
}
-
- AddressSet set = new AddressSet(addrSet);
-
- //skip blocks that are not initialized...
- MemoryBlock[] blocks = memory.getBlocks();
- for (int i = 0; i < blocks.length; ++i) {
- if (!blocks[i].isInitialized()) {
- set.delete(new AddressRangeImpl(blocks[i].getStart(), blocks[i].getEnd()));
- }
+ else {
+ addrSet = addrSet.intersect(initializedAddressSet);
}
try (FileOutputStream fos = new FileOutputStream(file)) {
- AddressRangeIterator iter = set.getAddressRanges();
+ AddressRangeIterator iter = addrSet.getAddressRanges();
while (iter.hasNext()) {
AddressRange range = iter.next();
byte[] mem = new byte[(int) range.getLength()];
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/Exporter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/Exporter.java
index dc0b9b39e9..ff940a0757 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/Exporter.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/Exporter.java
@@ -25,7 +25,6 @@ import ghidra.framework.model.DomainFile;
import ghidra.framework.model.DomainObject;
import ghidra.framework.plugintool.ServiceProvider;
import ghidra.program.model.address.AddressSetView;
-import ghidra.program.model.listing.Program;
import ghidra.util.HelpLocation;
import ghidra.util.classfinder.ExtensionPoint;
import ghidra.util.task.TaskMonitor;
@@ -101,34 +100,32 @@ abstract public class Exporter implements ExtensionPoint {
/**
* Returns true if this exporter is capable of exporting the given domain file/object content
* type. For example, some exporters have the ability to export programs, other exporters can
- * export project data type archives.
+ * export other {@link DomainFile} or {@link DomainObject} types such as project data type
+ * archives.
*
- * NOTE: This method should only be used as a preliminary check, if neccessary, to identify
+ * NOTE: This method should only be used as a preliminary check, if necessary, to identify
* exporter implementations that are capable of handling a specified content type/class. Prior
* to export a final check should be performed based on the export or either a
* {@link DomainFile} or {@link DomainObject}:
*
* {@link DomainFile} export - the method {@link #canExportDomainFile(DomainFile)} should be
* used to verify a direct project file export is possible using the
- * {@link #export(File, DomainFile, TaskMonitor)} method.
+ * {@link #export(File, DomainFile, TaskMonitor)} method which may avoid opening the file first.
*
* {@link DomainObject} export - the method {@link #canExportDomainObject(DomainObject)} should
- * be used to verify an export of a specific object is possible using the
+ * be used to verify an export of a specific object is possible before using the
* {@link #export(File, DomainObject, AddressSetView, TaskMonitor)} method.
*
- * avoid opening DomainFile when possible.
* @param domainObjectClass the class of the domain object to test for exporting.
* @return true if this exporter knows how to export the given domain object type.
*/
- public boolean canExportDomainObject(Class extends DomainObject> domainObjectClass) {
- return Program.class.isAssignableFrom(domainObjectClass);
- }
+ public abstract boolean canExportDomainObject(Class extends DomainObject> domainObjectClass);
/**
* Returns true if exporter can export the specified {@link DomainFile} without instantiating
* a {@link DomainObject}. This method should be used prior to exporting using the
- * {@link #export(File, DomainFile, TaskMonitor)} method. All exporter capable of a
- * {@link DomainFile} export must also support a export of a {@link DomainObject} so that any
+ * {@link #export(File, DomainFile, TaskMonitor)} method. All exporters capable of a
+ * {@link DomainFile} export must also support an export of a {@link DomainObject} so that any
* possible data modification/upgrade is included within resulting export.
*
* @param domainFile domain file
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/GdtExporter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/GdtExporter.java
index 21d049525a..1246f6d6d5 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/GdtExporter.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/GdtExporter.java
@@ -47,7 +47,7 @@ public class GdtExporter extends Exporter {
@Override
public boolean canExportDomainFile(DomainFile domainFile) {
- // Avoid exporting link-file itself
+ // Avoid exporting link-file itself or non-Datatype Archives
return !domainFile.isLink() && canExportDomainObject(domainFile.getDomainObjectClass());
}
@@ -59,6 +59,9 @@ public class GdtExporter extends Exporter {
@Override
public boolean export(File file, DomainObject domainObj, AddressSetView addrSet,
TaskMonitor monitor) {
+ if (!canExportDomainObject(domainObj.getClass())) {
+ throw new UnsupportedOperationException("only DataTypeArchiveDB objects are supported");
+ }
try {
file.delete();
domainObj.saveToPackedFile(file, monitor);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/GzfExporter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/GzfExporter.java
index 1e735b916f..e15f165144 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/GzfExporter.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/GzfExporter.java
@@ -42,7 +42,7 @@ public class GzfExporter extends Exporter {
@Override
public boolean canExportDomainFile(DomainFile domainFile) {
- // Avoid exporting link-file itself
+ // Avoid exporting link-file itself or non-Program files
return !domainFile.isLink() && canExportDomainObject(domainFile.getDomainObjectClass());
}
@@ -59,6 +59,9 @@ public class GzfExporter extends Exporter {
@Override
public boolean export(File file, DomainObject domainObj, AddressSetView addrSet,
TaskMonitor monitor) {
+ if (!canExportDomainObject(domainObj.getClass())) {
+ throw new UnsupportedOperationException("only ProgramDB objects are supported");
+ }
try {
file.delete();
domainObj.saveToPackedFile(file, monitor);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/HtmlExporter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/HtmlExporter.java
index 92c39e40ec..2140212bdf 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/HtmlExporter.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/HtmlExporter.java
@@ -4,9 +4,9 @@
* 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.
@@ -30,7 +30,7 @@ import ghidra.util.task.TaskMonitor;
* An implementation of exporter that creates
* an HTML representation of the program.
*/
-public class HtmlExporter extends Exporter {
+public class HtmlExporter extends ProgramExporter {
private ProgramTextOptions options;
/**
@@ -58,11 +58,14 @@ public class HtmlExporter extends Exporter {
public boolean export(File file, DomainObject domainObj, AddressSetView addressSet,
TaskMonitor monitor) throws IOException, ExporterException {
- if (!(domainObj instanceof Program)) {
+ Program program;
+ try {
+ program = getProgram(domainObj);
+ }
+ catch (ClassCastException e) {
log.appendMsg("Unsupported type: " + domainObj.getClass().getName());
return false;
}
- Program program = (Program) domainObj;
getOptions(() -> program);
new ProgramTextWriter(file, program, addressSet, monitor, options, provider);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/IntelHexExporter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/IntelHexExporter.java
index 73e392c6b4..7892cb309b 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/IntelHexExporter.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/IntelHexExporter.java
@@ -44,7 +44,7 @@ import ghidra.util.task.TaskMonitor;
* cause only lines that match the max record size to be printed; any other
* bytes will be dropped. If this option is not set, every byte will be represented in the output.
*/
-public class IntelHexExporter extends Exporter {
+public class IntelHexExporter extends ProgramExporter {
/** Option allowing the user to select the address space */
protected Option addressSpaceOption;
@@ -151,7 +151,11 @@ public class IntelHexExporter extends Exporter {
log.clear();
- if (!(domainObj instanceof Program program)) {
+ Program program;
+ try {
+ program = getProgram(domainObj);
+ }
+ catch (ClassCastException e) {
log.appendMsg("Unsupported type: " + domainObj.getClass().getName());
return false;
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/OriginalFileExporter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/OriginalFileExporter.java
index 7516b1eceb..d094fc331e 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/OriginalFileExporter.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/OriginalFileExporter.java
@@ -41,7 +41,7 @@ import utilities.util.FileUtilities;
* WARNING: Programs written to disk with this exporter may be runnable on your native platform.
* Use caution when exporting potentially malicious programs.
*/
-public class OriginalFileExporter extends Exporter {
+public class OriginalFileExporter extends ProgramExporter {
private static final String USER_MODS_OPTION_NAME = "Export User Byte Modifications";
private static final boolean USER_MODS_OPTION_DEFAULT = true;
@@ -63,6 +63,11 @@ public class OriginalFileExporter extends Exporter {
return false;
}
+ @Override
+ public boolean canExportDomainObject(Class extends DomainObject> domainObjectClass) {
+ return Program.class.isAssignableFrom(domainObjectClass);
+ }
+
@Override
public boolean canExportDomainObject(DomainObject domainObject) {
if (domainObject instanceof Program program) {
@@ -75,13 +80,15 @@ public class OriginalFileExporter extends Exporter {
public boolean export(File file, DomainObject domainObj, AddressSetView addrSet,
TaskMonitor monitor) throws IOException, ExporterException {
- if (!(domainObj instanceof Program)) {
- log.appendMsg("Unsupported type: " + domainObj.getClass().getSimpleName());
+ Program program;
+ try {
+ program = getProgram(domainObj);
+ }
+ catch (ClassCastException e) {
+ log.appendMsg("Unsupported type: " + domainObj.getClass().getName());
return false;
}
- Program program = (Program) domainObj;
-
List allFileBytes = program.getMemory().getAllFileBytes();
if (allFileBytes.isEmpty()) {
log.appendMsg("Exporting a program with no file source bytes is not supported");
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/ProgramExporter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/ProgramExporter.java
new file mode 100644
index 0000000000..b034f218a0
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/ProgramExporter.java
@@ -0,0 +1,55 @@
+/* ###
+ * 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.exporter;
+
+import ghidra.framework.model.DomainObject;
+import ghidra.program.model.listing.Program;
+import ghidra.util.HelpLocation;
+
+/**
+ * {@link ProgramExporter} provides an abstract {@link Exporter} implementation for
+ * {@link Program} objects.
+ */
+public abstract class ProgramExporter extends Exporter {
+
+ /**
+ * Constructs a new {@link Program} exporter.
+ * @param name the display name of this exporter
+ * @param extension the default extension for this exporter
+ * @param help the help location for this exporter
+ */
+ protected ProgramExporter(String name, String extension, HelpLocation help) {
+ super(name, extension, help);
+ }
+
+ /**
+ * Get an exportable Program instance from the specified DomainObject instance.
+ * The specified instance must satisfy {@link #canExportDomainObject(Class)}.
+ * @param domainObj domain object from which a Program may be derived.
+ * @return Program instance
+ * @throws ClassCastException if domain object class does not satisfy
+ * {@link #canExportDomainObject(Class)}.
+ */
+ protected Program getProgram(DomainObject domainObj) throws ClassCastException {
+ return (Program) domainObj;
+ }
+
+ @Override
+ public boolean canExportDomainObject(Class extends DomainObject> domainObjectClass) {
+ return Program.class.isAssignableFrom(domainObjectClass);
+ }
+
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/XmlExporter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/XmlExporter.java
index 964aeceede..f5ebf1d1ec 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/XmlExporter.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/XmlExporter.java
@@ -4,9 +4,9 @@
* 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.
@@ -33,7 +33,7 @@ import ghidra.util.task.TaskMonitor;
* An implementation of exporter that creates
* an XML representation of the program.
*/
-public class XmlExporter extends Exporter {
+public class XmlExporter extends ProgramExporter {
private XmlProgramOptions options = new XmlProgramOptions();
/**
@@ -62,11 +62,14 @@ public class XmlExporter extends Exporter {
log.clear();
- if (!(domainObj instanceof Program)) {
- log.appendMsg("Unsupported type: "+domainObj.getClass().getName());
+ Program program;
+ try {
+ program = getProgram(domainObj);
+ }
+ catch (ClassCastException e) {
+ log.appendMsg("Unsupported type: " + domainObj.getClass().getName());
return false;
}
- Program program = (Program)domainObj;
if (addrSet == null) {
addrSet = program.getMemory();
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/GdtLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/GdtLoader.java
index 89870d3174..d2892acb97 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/GdtLoader.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/GdtLoader.java
@@ -47,7 +47,7 @@ public class GdtLoader implements Loader {
@Override
public List
getDefaultOptions(ByteProvider provider, LoadSpec loadSpec,
DomainObject domainObject, boolean loadIntoProgram, boolean mirrorFsLayout) {
- return Collections.emptyList();
+ return List.of();
}
@Override
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/GzfLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/GzfLoader.java
index e60dd02034..674117e82f 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/GzfLoader.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/GzfLoader.java
@@ -66,7 +66,7 @@ public class GzfLoader implements Loader {
@Override
public List
getDefaultOptions(ByteProvider provider, LoadSpec loadSpec,
DomainObject domainObject, boolean loadIntoProgram, boolean mirrorFsLayout) {
- return Collections.emptyList();
+ return List.of();
}
@Override
@@ -131,7 +131,6 @@ public class GzfLoader implements Loader {
@Override
public Collection findSupportedLoadSpecs(ByteProvider provider) throws IOException {
- // TODO WRONG! try to parse a bit and tell for real
List loadSpecs = new ArrayList<>();
if (isGzfFile(provider)) {
loadSpecs.add(new LoadSpec(this, 0, false));
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterPlugin.java
index 597ee50ff8..1f53a1843d 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterPlugin.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterPlugin.java
@@ -86,7 +86,7 @@ public class ImporterPlugin extends Plugin
"This plugin manages importing files, including those contained within " +
"firmware/filesystem images.";
- private static final String SIMPLE_UNPACK_OPTION = "Enable simple GZF/GDT unpack";
+ private static final String SIMPLE_UNPACK_OPTION = "Enable simple GZF/GZT/GDT unpack";
private static final boolean SIMPLE_UNPACK_OPTION_DEFAULT = false;
private DockingAction importAction;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterUtilities.java b/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterUtilities.java
index 5d1709ee29..6dcd3bf5a0 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterUtilities.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterUtilities.java
@@ -450,7 +450,7 @@ public class ImporterUtilities {
ProgramManager programManager, LoadResults extends DomainObject> loadResults,
String importMessages, TaskMonitor monitor) throws CancelledException {
- boolean firstProgram = true;
+ boolean firstFile = true;
Set importedFilesSet = new HashSet<>();
for (Loaded extends DomainObject> loaded : loadResults) {
monitor.checkCancelled();
@@ -460,7 +460,7 @@ public class ImporterUtilities {
try {
if (obj instanceof Program) {
if (programManager != null) {
- int openState = firstProgram
+ int openState = firstFile
? ProgramManager.OPEN_CURRENT
: ProgramManager.OPEN_VISIBLE;
programManager.openProgram((Program) obj, openState);
@@ -477,16 +477,16 @@ public class ImporterUtilities {
}
}
}
- if (firstProgram) {
+ if (firstFile) {
// currently we only show results for the imported program, not any libraries
- displayResults(pluginTool, obj, df, importMessages);
+ displayResults(pluginTool, obj, importMessages);
// Optionally echo loader message log to application.log
if (!Loader.loggingDisabled && !importMessages.isEmpty()) {
Msg.info(ImporterUtilities.class, "Additional info:\n" + importMessages);
}
}
- firstProgram = false;
+ firstFile = false;
importedFilesSet.add(df);
}
finally {
@@ -518,7 +518,7 @@ public class ImporterUtilities {
program.getDomainFile().getPathname(), false, loadSpec, options, consumer,
messageLog, monitor);
loadSpec.getLoader().loadInto(program, settings);
- displayResults(tool, program, program.getDomainFile(), messageLog.toString());
+ displayResults(tool, program, messageLog.toString());
// Optionally echo loader message log to application.log
if (!Loader.loggingDisabled && messageLog.hasMessages()) {
@@ -538,18 +538,9 @@ public class ImporterUtilities {
}
- private static void displayResults(PluginTool tool, DomainObject obj, DomainFile df,
- String info) {
-
- DomainFile domainFile = obj.getDomainFile();
- Map metadata = obj.getMetadata();
- if (df != null) {
- domainFile = df;
- metadata = df.getMetadata();
- }
-
+ private static void displayResults(PluginTool tool, DomainObject obj, String info) {
HelpLocation helpLocation = new HelpLocation(GenericHelpTopics.ABOUT, "About_Program");
- AboutDomainObjectUtils.displayInformation(tool, domainFile, metadata,
+ AboutDomainObjectUtils.displayInformation(tool, obj.getDomainFile(), obj.getMetadata(),
"Import Results Summary", info, helpLocation);
}
diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/util/exporter/CppExporter.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/util/exporter/CppExporter.java
index 4c84198cdf..0ec314489d 100644
--- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/util/exporter/CppExporter.java
+++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/util/exporter/CppExporter.java
@@ -41,7 +41,7 @@ import ghidra.util.exception.CancelledException;
import ghidra.util.task.*;
import util.CollectionUtils;
-public class CppExporter extends Exporter {
+public class CppExporter extends ProgramExporter {
public static final String CREATE_C_FILE = "Create C File (.c)";
public static final String CREATE_HEADER_FILE = "Create Header File (.h)";
@@ -90,13 +90,16 @@ public class CppExporter extends Exporter {
@Override
public boolean export(File file, DomainObject domainObj, AddressSetView addrSet,
TaskMonitor monitor) throws IOException, ExporterException {
- if (!(domainObj instanceof Program)) {
+
+ Program program;
+ try {
+ program = getProgram(domainObj);
+ }
+ catch (ClassCastException e) {
log.appendMsg("Unsupported type: " + domainObj.getClass().getName());
return false;
}
- Program program = (Program) domainObj;
-
configureOptions(program);
configureFunctionTags(program);
diff --git a/Ghidra/Features/Sarif/src/main/java/sarif/export/SarifExporter.java b/Ghidra/Features/Sarif/src/main/java/sarif/export/SarifExporter.java
index 482f41b98f..0138f42548 100644
--- a/Ghidra/Features/Sarif/src/main/java/sarif/export/SarifExporter.java
+++ b/Ghidra/Features/Sarif/src/main/java/sarif/export/SarifExporter.java
@@ -20,8 +20,8 @@ import java.io.IOException;
import java.util.List;
import ghidra.app.util.*;
-import ghidra.app.util.exporter.Exporter;
import ghidra.app.util.exporter.ExporterException;
+import ghidra.app.util.exporter.ProgramExporter;
import ghidra.app.util.importer.MessageLog;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.address.AddressSetView;
@@ -36,7 +36,7 @@ import sarif.managers.ProgramSarifMgr;
* An implementation of exporter that creates
* an SARIF representation of the program.
*/
-public class SarifExporter extends Exporter {
+public class SarifExporter extends ProgramExporter {
private SarifProgramOptions options = new SarifProgramOptions();
/**
@@ -59,17 +59,21 @@ public class SarifExporter extends Exporter {
this.options.setOptions(options);
}
+
@Override
public boolean export(File file, DomainObject domainObj, AddressSetView addrSet, TaskMonitor monitor)
throws IOException, ExporterException {
log.clear();
- if (!(domainObj instanceof Program)) {
- log.appendMsg("Unsupported type: "+domainObj.getClass().getName());
+ Program program;
+ try {
+ program = getProgram(domainObj);
+ }
+ catch (ClassCastException e) {
+ log.appendMsg("Unsupported type: " + domainObj.getClass().getName());
return false;
}
- Program program = (Program)domainObj;
if (addrSet == null) {
addrSet = program.getMemory();
diff --git a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/FolderItem.java b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/FolderItem.java
index 1aa48dee02..a2b2f0bec3 100644
--- a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/FolderItem.java
+++ b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/FolderItem.java
@@ -276,8 +276,8 @@ public interface FolderItem {
/**
* Update the checkout version associated with this versioned item.
* @param checkoutId id corresponding to an existing checkout
- * @param checkoutVersion
- * @param user
+ * @param checkoutVersion current checkout version
+ * @param user user performing update
* @throws IOException if an IO error occurs.
*/
void updateCheckoutVersion(long checkoutId, int checkoutVersion, String user)
@@ -289,7 +289,7 @@ public interface FolderItem {
* @param version if this item is versioned, specifies the version to be output, otherwise
* -1 should be specified.
* @param monitor progress monitor
- * @throws IOException
+ * @throws IOException if failed to save packed file
* @throws CancelledException if monitor cancels operation
*/
public void output(File outputFile, int version, TaskMonitor monitor)
@@ -297,6 +297,8 @@ public interface FolderItem {
/**
* Returns this instance after refresh or null if item no longer exists
+ * @return refreshed item
+ * @throws IOException if error occured during refresh
*/
public FolderItem refresh() throws IOException;
diff --git a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/local/ItemDeserializer.java b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/local/ItemDeserializer.java
index 4499c350d2..1499711f93 100644
--- a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/local/ItemDeserializer.java
+++ b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/local/ItemDeserializer.java
@@ -4,9 +4,9 @@
* 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.
@@ -15,15 +15,15 @@
*/
package ghidra.framework.store.local;
+import java.io.*;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
import generic.jar.ResourceFile;
import ghidra.util.MonitoredInputStream;
import ghidra.util.exception.IOCancelledException;
import ghidra.util.task.TaskMonitor;
-import java.io.*;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
-
/**
* ItemDeserializer facilitates the reading of a compressed data stream
* contained within a "packed" file. A "packed" file contains the following meta-data
diff --git a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/local/LocalDataFileItem.java b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/local/LocalDataFileItem.java
index c7826dcdd5..8fecd3aa03 100644
--- a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/local/LocalDataFileItem.java
+++ b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/local/LocalDataFileItem.java
@@ -15,16 +15,16 @@
*/
package ghidra.framework.store.local;
+import java.io.*;
+
+import org.apache.commons.lang3.StringUtils;
+
import ghidra.framework.store.DataFileItem;
import ghidra.framework.store.FolderItem;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.DuplicateFileException;
import ghidra.util.task.TaskMonitor;
-import java.io.*;
-
-import org.apache.commons.lang3.StringUtils;
-
/**
* LocalDataFileItem provides a FolderItem implementation
* for a local serialized data file. This implementation supports
@@ -186,8 +186,7 @@ public class LocalDataFileItem extends LocalFolderItem implements DataFileItem {
@Override
public void output(File outputFile, int version, TaskMonitor monitor) throws IOException {
- throw new UnsupportedOperationException("Output not yet supported for DataFiles");
-
+ throw new IOException("Packed output not yet supported for DataFiles");
}
@Override
diff --git a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/local/LocalDatabaseItem.java b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/local/LocalDatabaseItem.java
index fcabd092c6..a25b136c9f 100644
--- a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/local/LocalDatabaseItem.java
+++ b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/local/LocalDatabaseItem.java
@@ -600,13 +600,18 @@ public class LocalDatabaseItem extends LocalFolderItem implements DatabaseItem {
public void output(File outputFile, int version, TaskMonitor monitor)
throws CancelledException, IOException {
synchronized (fileSystem) {
+
+ String contentType = getContentType();
+ if (UnknownFolderItem.UNKNOWN_CONTENT_TYPE.equals(contentType)) {
+ throw new IOException("Unknown content type");
+ }
+
if (isVersioned) {
- versionedDb.output(version, outputFile, getName(), DATABASE_FILE_TYPE,
- getContentType(), monitor);
+ versionedDb.output(version, outputFile, getName(), DATABASE_FILE_TYPE, contentType,
+ monitor);
}
else {
- privateDb.output(outputFile, getName(), DATABASE_FILE_TYPE, getContentType(),
- monitor);
+ privateDb.output(outputFile, getName(), DATABASE_FILE_TYPE, contentType, monitor);
}
}
}
diff --git a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/local/LocalTextDataItem.java b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/local/LocalTextDataItem.java
index ecf7b61f44..ab1be2b517 100644
--- a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/local/LocalTextDataItem.java
+++ b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/local/LocalTextDataItem.java
@@ -117,7 +117,7 @@ public class LocalTextDataItem extends LocalFolderItem implements TextDataItem {
@Override
public void output(File outputFile, int version, TaskMonitor monitor) throws IOException {
- throw new IOException("Output not supported");
+ throw new IOException("Packed output not supported for text data");
}
@Override
diff --git a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/local/LocalUnknownFolderItem.java b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/local/LocalUnknownFolderItem.java
index 716ed09732..93daab7c7e 100644
--- a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/local/LocalUnknownFolderItem.java
+++ b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/local/LocalUnknownFolderItem.java
@@ -115,7 +115,8 @@ public class LocalUnknownFolderItem extends LocalFolderItem implements UnknownFo
@Override
public void output(File outputFile, int version, TaskMonitor monitor) throws IOException {
- throw new UnsupportedOperationException("Output not supported for UnknownFolderItems");
+ throw new UnsupportedOperationException(
+ "Packed output not supported for UnknownFolderItems");
}
@Override
diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/model/DomainObject.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/model/DomainObject.java
index 9255d26daa..9cd1190842 100644
--- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/model/DomainObject.java
+++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/model/DomainObject.java
@@ -158,7 +158,7 @@ public interface DomainObject {
* Saves (i.e., serializes) the current content to a packed file.
* @param outputFile packed output file
* @param monitor progress monitor
- * @throws IOException if an exception occurs
+ * @throws IOException if an error occurs during operation
* @throws CancelledException if the user cancels
* @throws UnsupportedOperationException if not supported by object implementation
*/
diff --git a/GhidraBuild/Skeleton/src/main/java/skeleton/SkeletonExporter.java b/GhidraBuild/Skeleton/src/main/java/skeleton/SkeletonExporter.java
index 264b91bd04..d5063af2ab 100644
--- a/GhidraBuild/Skeleton/src/main/java/skeleton/SkeletonExporter.java
+++ b/GhidraBuild/Skeleton/src/main/java/skeleton/SkeletonExporter.java
@@ -50,6 +50,12 @@ public class SkeletonExporter extends Exporter {
return false;
}
+ @Override
+ public boolean canExportDomainObject(Class extends DomainObject> domainObjectClass) {
+ // return Program.class.isAssignableFrom(domainObjectClass);
+ return false;
+ }
+
@Override
public boolean export(File file, DomainObject domainObj, AddressSetView addrSet,
TaskMonitor monitor) throws ExporterException, IOException {