mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-10-06 04:59:23 +08:00
Merge remote-tracking branch 'origin/GP-6779_ghidragon_cleaning_up_standalone_dtm'
This commit is contained in:
@@ -32,8 +32,9 @@ import ghidra.framework.model.DomainFile;
|
||||
import ghidra.framework.model.ProjectData;
|
||||
import ghidra.framework.store.db.PackedDatabase;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
import ghidra.program.database.dtarchive.DataTypeArchiveFactory;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.FileDataTypeManager;
|
||||
import ghidra.program.model.dtarchive.FileDataTypeArchive;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
@@ -132,7 +133,9 @@ public class IsfServer extends Thread {
|
||||
|
||||
private DataTypeManager openAsDataTypeArchive(String ns) throws Exception {
|
||||
File gdt = new File(ns);
|
||||
return FileDataTypeManager.openFileArchive(gdt, false);
|
||||
FileDataTypeArchive archive =
|
||||
DataTypeArchiveFactory.openReadOnly(gdt, this, TaskMonitor.DUMMY);
|
||||
return archive != null ? archive.getDataTypeManager() : null;
|
||||
}
|
||||
|
||||
private DataTypeManager openAsProgramDatabase(String ns) throws Exception {
|
||||
|
||||
+4
-4
@@ -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.
|
||||
@@ -16,14 +16,14 @@
|
||||
package ghidra.trace.database;
|
||||
|
||||
import db.util.ErrorHandler;
|
||||
import ghidra.program.database.ManagerDB;
|
||||
import ghidra.program.database.ProgramDBModule;
|
||||
|
||||
public interface DBTraceManager extends ErrorHandler {
|
||||
/**
|
||||
* Invalidate this manager's caches
|
||||
*
|
||||
* @param all probably nothing. Check out implementations of
|
||||
* {@link ManagerDB#invalidateCache(boolean)}.
|
||||
* {@link ProgramDBModule#invalidateCache(boolean)}.
|
||||
*/
|
||||
void invalidateCache(boolean all);
|
||||
}
|
||||
|
||||
+9
-37
@@ -18,7 +18,6 @@ package ghidra.trace.database.data;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
|
||||
import db.DBHandle;
|
||||
import db.Transaction;
|
||||
@@ -27,13 +26,14 @@ import ghidra.framework.model.DomainFile;
|
||||
import ghidra.program.database.data.ProgramBasedDataTypeManagerDB;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.dtarchive.DataTypeStore;
|
||||
import ghidra.trace.database.DBTrace;
|
||||
import ghidra.trace.database.DBTraceManager;
|
||||
import ghidra.trace.database.guest.DBTraceGuestPlatform;
|
||||
import ghidra.trace.database.guest.DBTracePlatformManager.DBTraceHostPlatform;
|
||||
import ghidra.trace.database.guest.InternalTracePlatform;
|
||||
import ghidra.trace.model.data.TraceBasedDataTypeManager;
|
||||
import ghidra.util.InvalidNameException;
|
||||
import ghidra.util.Lock;
|
||||
import ghidra.util.UniversalID;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.VersionException;
|
||||
@@ -42,17 +42,6 @@ import ghidra.util.task.TaskMonitor;
|
||||
public class DBTraceDataTypeManager extends ProgramBasedDataTypeManagerDB
|
||||
implements TraceBasedDataTypeManager, DBTraceManager {
|
||||
|
||||
/**
|
||||
* NOTE: This "read-write" lock is actually just a compatibility wrapper around the
|
||||
* {@link ghidra.util.Lock} for the entire trace database. There was a time when I dreamed of
|
||||
* using an actual read-write lock (though it's not known if that'd actually achieve any
|
||||
* appreciable speed up); however, inheriting the existing DataTypeManager implementation
|
||||
* required its lock to be used throughout the database. Rather than convert all my code (and
|
||||
* lose the distinction of where I need write vs. read locks), I just wrapped the API. So no,
|
||||
* this code does not refer to the wrapper, but it does still use the lock. I keep a reference
|
||||
* to it here in case I ever need it.
|
||||
*/
|
||||
protected final ReadWriteLock lock;
|
||||
protected final DBTrace trace;
|
||||
protected final InternalTracePlatform platform;
|
||||
|
||||
@@ -64,11 +53,10 @@ public class DBTraceDataTypeManager extends ProgramBasedDataTypeManagerDB
|
||||
};
|
||||
}
|
||||
|
||||
public DBTraceDataTypeManager(DBHandle dbh, OpenMode openMode, ReadWriteLock lock,
|
||||
public DBTraceDataTypeManager(DBHandle dbh, OpenMode openMode, Lock lock,
|
||||
TaskMonitor monitor, DBTrace trace, InternalTracePlatform platform)
|
||||
throws CancelledException, VersionException, IOException {
|
||||
super(dbh, null, openMode, computePrefix(platform), trace, trace.getLock(), monitor);
|
||||
this.lock = lock; // TODO: nothing uses this local lock - not sure what its purpose is
|
||||
super(dbh, null, openMode, computePrefix(platform), trace, lock, monitor);
|
||||
this.trace = trace;
|
||||
this.platform = platform;
|
||||
|
||||
@@ -79,6 +67,11 @@ public class DBTraceDataTypeManager extends ProgramBasedDataTypeManagerDB
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeStore getDataStore() {
|
||||
return trace.getProgramView();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dataSettingChanged(Address address) {
|
||||
// ignored - instance settings are not current supported (no AddressMap provided)
|
||||
@@ -99,16 +92,6 @@ public class DBTraceDataTypeManager extends ProgramBasedDataTypeManagerDB
|
||||
return trace.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) throws InvalidNameException {
|
||||
if (name == null || name.length() == 0) {
|
||||
throw new InvalidNameException("Name must be at least one character long: " + name);
|
||||
}
|
||||
|
||||
trace.setName(name);
|
||||
categoryRenamed(CategoryPath.ROOT, getCategory(CategoryPath.ROOT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public InternalTracePlatform getPlatform() {
|
||||
return platform;
|
||||
@@ -239,23 +222,12 @@ public class DBTraceDataTypeManager extends ProgramBasedDataTypeManagerDB
|
||||
return trace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainFile getDomainFile() {
|
||||
return trace.getDomainFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDomainFileID() {
|
||||
DomainFile domainFile = trace.getDomainFile(); // Can be null if never saved
|
||||
return domainFile == null ? null : domainFile.getFileID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
DomainFile domainFile = trace.getDomainFile(); // Can be null if never saved
|
||||
return domainFile == null ? null : domainFile.getPathname();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArchiveType getType() {
|
||||
/**
|
||||
|
||||
+3
-3
@@ -17,7 +17,6 @@ package ghidra.trace.database.guest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
|
||||
import db.DBHandle;
|
||||
import ghidra.framework.data.OpenMode;
|
||||
@@ -33,6 +32,7 @@ import ghidra.trace.model.data.TraceBasedDataTypeManager;
|
||||
import ghidra.trace.model.guest.*;
|
||||
import ghidra.trace.util.TraceChangeRecord;
|
||||
import ghidra.trace.util.TraceEvents;
|
||||
import ghidra.util.Lock;
|
||||
import ghidra.util.LockHold;
|
||||
import ghidra.util.database.DBCachedObjectStore;
|
||||
import ghidra.util.database.DBCachedObjectStoreFactory;
|
||||
@@ -49,7 +49,7 @@ import ghidra.util.task.TaskMonitor;
|
||||
*/
|
||||
public class DBTracePlatformManager implements DBTraceManager, TracePlatformManager {
|
||||
protected final DBHandle dbh;
|
||||
protected final ReadWriteLock lock;
|
||||
protected final Lock lock;
|
||||
protected final Language baseLanguage;
|
||||
protected final CompilerSpec baseCompilerSpec;
|
||||
protected final DBTrace trace;
|
||||
@@ -157,7 +157,7 @@ public class DBTracePlatformManager implements DBTraceManager, TracePlatformMana
|
||||
|
||||
protected final InternalTracePlatform hostPlatform = new DBTraceHostPlatform();
|
||||
|
||||
public DBTracePlatformManager(DBHandle dbh, OpenMode openMode, ReadWriteLock lock,
|
||||
public DBTracePlatformManager(DBHandle dbh, OpenMode openMode, Lock lock,
|
||||
TaskMonitor monitor, CompilerSpec baseCompilerSpec, DBTrace trace)
|
||||
throws VersionException, IOException, CancelledException {
|
||||
this.dbh = dbh;
|
||||
|
||||
+7
-4
@@ -56,9 +56,8 @@ import ghidra.trace.model.bookmark.TraceBookmark;
|
||||
import ghidra.trace.model.bookmark.TraceBookmarkType;
|
||||
import ghidra.trace.model.data.TraceBasedDataTypeManager;
|
||||
import ghidra.trace.model.listing.*;
|
||||
import ghidra.trace.model.memory.TraceMemoryRegion;
|
||||
import ghidra.trace.model.memory.TraceMemoryState;
|
||||
import ghidra.trace.model.memory.TraceMemoryOperations.StatePredicate;
|
||||
import ghidra.trace.model.memory.TraceMemoryRegion;
|
||||
import ghidra.trace.model.program.TraceProgramView;
|
||||
import ghidra.trace.model.symbol.*;
|
||||
import ghidra.trace.util.TraceEvents;
|
||||
@@ -599,8 +598,7 @@ public class DBTraceProgramView implements TraceProgramView {
|
||||
}
|
||||
|
||||
protected static class OverlappingAddressRangeKeyIteratorMerger<T> extends
|
||||
PairingIteratorMerger<Entry<AddressRange, T>, Entry<AddressRange, T>,
|
||||
Entry<AddressRange, T>> {
|
||||
PairingIteratorMerger<Entry<AddressRange, T>, Entry<AddressRange, T>, Entry<AddressRange, T>> {
|
||||
|
||||
protected static <T> Iterable<Pair<Entry<AddressRange, T>, Entry<AddressRange, T>>> iter(
|
||||
Iterable<Entry<AddressRange, T>> left, Iterable<Entry<AddressRange, T>> right) {
|
||||
@@ -1565,4 +1563,9 @@ public class DBTraceProgramView implements TraceProgramView {
|
||||
}
|
||||
return queues;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArchiveType getArchiveType() {
|
||||
return ArchiveType.PROGRAM;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -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.
|
||||
@@ -169,12 +169,12 @@ public class DBTraceProgramViewFunctionManager implements FunctionManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProgram(ProgramDB program) {
|
||||
public void setDomainObject(ProgramDB program) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void programReady(OpenMode openMode, int currentRevision, TaskMonitor monitor)
|
||||
public void domainObjectReady(OpenMode openMode, int currentRevision, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@@ -20,9 +20,9 @@ import java.util.Collection;
|
||||
import javax.swing.Icon;
|
||||
|
||||
import generic.theme.GIcon;
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.program.model.address.AddressFactory;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.DataTypeManagerDomainObject;
|
||||
import ghidra.program.model.lang.CompilerSpec;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.program.model.listing.Program;
|
||||
@@ -60,7 +60,7 @@ import ghidra.util.LockHold;
|
||||
* specific snapshot and/or manipulate the trace as if it were a program, use
|
||||
* {@link #getProgramView()}.
|
||||
*/
|
||||
public interface Trace extends DataTypeManagerDomainObject {
|
||||
public interface Trace extends DomainObject {
|
||||
Icon TRACE_ICON = new GIcon("icon.content.handler.trace");
|
||||
|
||||
public interface TraceProgramViewListener {
|
||||
@@ -92,7 +92,6 @@ public interface Trace extends DataTypeManagerDomainObject {
|
||||
* For traces, this gets the "base" or "host" {@link DataTypeManager}. For platform-specific
|
||||
* managers, see {@link TracePlatform#getDataTypeManager()}.
|
||||
*/
|
||||
@Override
|
||||
default TraceBasedDataTypeManager getDataTypeManager() {
|
||||
return getBaseDataTypeManager();
|
||||
}
|
||||
|
||||
+8
-11
@@ -25,7 +25,9 @@ import java.nio.file.Path;
|
||||
import org.junit.*;
|
||||
|
||||
import db.Transaction;
|
||||
import ghidra.program.database.dtarchive.DataTypeArchiveFactory;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.dtarchive.FileDataTypeArchive;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.program.model.lang.LanguageID;
|
||||
import ghidra.program.util.DefaultLanguageService;
|
||||
@@ -77,22 +79,17 @@ public class DBTraceDataTypeManagerTest extends AbstractGhidraHeadlessIntegratio
|
||||
assertEquals("Testing", dtm.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetName() throws InvalidNameException {
|
||||
try (Transaction tx = trace.openTransaction("Testing")) {
|
||||
dtm.setName("Another name");
|
||||
}
|
||||
assertEquals("Another name", trace.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddSourceArchive() throws IOException {
|
||||
StructureDataType mine = getTestDataType();
|
||||
DataTypePath minePath = mine.getDataTypePath();
|
||||
Path tmpDir = Files.createTempDirectory("test");
|
||||
File archiveFile = tmpDir.resolve("test.gdt").toFile();
|
||||
FileDataTypeManager dtm2 = FileDataTypeManager.createFileArchive(archiveFile);
|
||||
try (Transaction tx = dtm2.openTransaction("Testing")) {
|
||||
|
||||
FileDataTypeArchive archive = DataTypeArchiveFactory.createFileArchive(archiveFile, this);
|
||||
DataTypeManager dtm2 = archive.getDataTypeManager();
|
||||
|
||||
try (Transaction tx = archive.openTransaction("Testing")) {
|
||||
dtm2.addDataType(mine, DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||
}
|
||||
DataType got = dtm2.getDataType(minePath);
|
||||
@@ -100,7 +97,7 @@ public class DBTraceDataTypeManagerTest extends AbstractGhidraHeadlessIntegratio
|
||||
try (Transaction tx = trace.openTransaction("Testing")) {
|
||||
dtm.addDataType(got, DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||
}
|
||||
dtm2.delete();
|
||||
archive.delete();
|
||||
|
||||
// TODO: Listen for sourceArchiveAdded event
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -35,12 +35,14 @@ import ghidra.app.script.GhidraScript;
|
||||
import ghidra.app.util.cparser.C.CParserUtils;
|
||||
import ghidra.app.util.cparser.C.ParseException;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.FileDataTypeManager;
|
||||
import ghidra.program.model.dtarchive.FileDataTypeArchive;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class CreateUEFIGDTArchivesScript extends GhidraScript {
|
||||
|
||||
private File outputDirectory;
|
||||
|
||||
|
||||
private static String headerFilePath = "/data/HeaderFiles/git/edk2";
|
||||
|
||||
@Override
|
||||
@@ -49,41 +51,49 @@ public class CreateUEFIGDTArchivesScript extends GhidraScript {
|
||||
|
||||
parseUEFIHeaders("X64", "x86:LE:64:default", "windows");
|
||||
parseUEFIHeaders("Ia32", "x86:LE:32:default", "windows");
|
||||
|
||||
|
||||
parseUEFIHeaders("AArch64", "AARCH64:LE:64:v8A", "windows");
|
||||
parseUEFIHeaders("Arm", "ARM:LE:32:v8", "default");
|
||||
|
||||
|
||||
parseUEFIHeaders("RiscV64", "RISCV:LE:64:RV64G", "gcc");
|
||||
parseUEFIHeaders("LoongArch64", "Loongarch:LE:64:lp64d", "default");
|
||||
}
|
||||
|
||||
private void parseHeaderFilesToGDT(File outputDir, String gdtName, String languageID, String compiler,
|
||||
String[] filenames, String includePaths[], String[] args)
|
||||
|
||||
private void parseHeaderFilesToGDT(File outputDir, String gdtName, String languageID,
|
||||
String compiler, String[] filenames, String includePaths[], String[] args)
|
||||
throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException {
|
||||
DataTypeManager openTypes[] = null;
|
||||
|
||||
parseHeaderFilesToGDT(openTypes, outputDir, gdtName, languageID, compiler, filenames, includePaths, args);
|
||||
|
||||
parseHeaderFilesToGDT(openTypes, outputDir, gdtName, languageID, compiler, filenames,
|
||||
includePaths, args);
|
||||
}
|
||||
|
||||
private void parseHeaderFilesToGDT(DataTypeManager openTypes[], File outputDir, String gdtName, String languageID, String compiler,
|
||||
String[] filenames, String[] includePaths, String[] args)
|
||||
private void parseHeaderFilesToGDT(DataTypeManager openTypes[], File outputDir, String gdtName,
|
||||
String languageID, String compiler, String[] filenames, String[] includePaths,
|
||||
String[] args)
|
||||
throws ParseException, ghidra.app.util.cparser.CPP.ParseException, IOException {
|
||||
|
||||
String dataTypeFile = outputDir + File.separator + gdtName + ".gdt";
|
||||
|
||||
File f = getArchiveFile(dataTypeFile);
|
||||
|
||||
FileDataTypeManager dtMgr = CParserUtils.parseHeaderFiles(openTypes, filenames,
|
||||
includePaths, args, f.getAbsolutePath(), languageID, compiler, monitor);
|
||||
|
||||
dtMgr.save();
|
||||
dtMgr.close();
|
||||
String dataTypeFile = outputDir + File.separator + gdtName + ".gdt";
|
||||
|
||||
File f = getArchiveFile(dataTypeFile);
|
||||
|
||||
FileDataTypeArchive archive = CParserUtils.parseHeaderFiles(filenames,
|
||||
includePaths, args, f.getAbsolutePath(), languageID, compiler, openTypes, this,
|
||||
monitor);
|
||||
|
||||
try {
|
||||
archive.save(null, TaskMonitor.DUMMY);
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
// can't happen since a DUMMY monitor was used
|
||||
}
|
||||
archive.release(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn string into a file, delete old archive if it exists
|
||||
*
|
||||
* @param dataTypeFile
|
||||
* @param dataTypeFile the file name of the stored archive
|
||||
*
|
||||
* @return file
|
||||
*/
|
||||
@@ -99,9 +109,9 @@ public class CreateUEFIGDTArchivesScript extends GhidraScript {
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
public void parseUEFIHeaders(String name, String languageID, String compiler) throws Exception {
|
||||
|
||||
|
||||
String filenames[] = {
|
||||
"ProcessorBind.h",
|
||||
"Uefi/UefiBaseType.h",
|
||||
@@ -116,22 +126,23 @@ public class CreateUEFIGDTArchivesScript extends GhidraScript {
|
||||
"Library/StandaloneMmDriverEntryPoint.h",
|
||||
"Library/UefiApplicationEntryPoint.h",
|
||||
"Library/UefiDriverEntryPoint.h",
|
||||
headerFilePath+"/MdePkg/Include/Pi/",
|
||||
headerFilePath+"/MdePkg/Include/Ppi/",
|
||||
headerFilePath+"/MdePkg/Include/Protocol/",
|
||||
headerFilePath+"/MdePkg/Include/IndustryStandard/",
|
||||
headerFilePath + "/MdePkg/Include/Pi/",
|
||||
headerFilePath + "/MdePkg/Include/Ppi/",
|
||||
headerFilePath + "/MdePkg/Include/Protocol/",
|
||||
headerFilePath + "/MdePkg/Include/IndustryStandard/",
|
||||
};
|
||||
|
||||
|
||||
String includePaths[] = {
|
||||
headerFilePath+"/MdePkg/Include/"+name,
|
||||
headerFilePath+"/MdePkg/Include",
|
||||
headerFilePath + "/MdePkg/Include/" + name,
|
||||
headerFilePath + "/MdePkg/Include",
|
||||
};
|
||||
|
||||
|
||||
String args[] = {
|
||||
"-DSTATIC_ASSERT=static_assert"
|
||||
};
|
||||
|
||||
parseHeaderFilesToGDT(outputDirectory, "uefi_"+name, languageID, compiler, filenames, includePaths, args);
|
||||
|
||||
parseHeaderFilesToGDT(outputDirectory, "uefi_" + name, languageID, compiler, filenames,
|
||||
includePaths, args);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -29,10 +29,11 @@ import ghidra.app.script.GhidraScript;
|
||||
import ghidra.app.services.DataTypeManagerService;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.database.ProjectDataTypeManager;
|
||||
import ghidra.program.database.data.*;
|
||||
import ghidra.program.database.data.DataTypeManagerDB;
|
||||
import ghidra.program.database.data.ProgramDataTypeManager;
|
||||
import ghidra.program.model.data.BuiltInDataTypeManager;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.dtarchive.ProjectDataTypeArchive;
|
||||
import ghidra.program.model.listing.Program;
|
||||
|
||||
public class FixupCompositeDataTypesScript extends GhidraScript {
|
||||
@@ -50,33 +51,30 @@ public class FixupCompositeDataTypesScript extends GhidraScript {
|
||||
popup("This script requires the DataTypeManagerService");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ArrayList<DTMWrapper> dtms = new ArrayList<>();
|
||||
|
||||
for (DataTypeManager dtm : service.getDataTypeManagers()) {
|
||||
if (dtm instanceof BuiltInDataTypeManager) {
|
||||
continue;
|
||||
}
|
||||
if (dtm instanceof ProgramDataTypeManager) {
|
||||
dtms.add(0, new DTMWrapper((ProgramDataTypeManager) dtm));
|
||||
}
|
||||
else if (dtm instanceof DataTypeManagerDB) {
|
||||
dtms.add(new DTMWrapper((DataTypeManagerDB) dtm));
|
||||
if (dtm instanceof DataTypeManagerDB dtmDB) {
|
||||
dtms.add(new DTMWrapper(dtmDB));
|
||||
}
|
||||
}
|
||||
|
||||
DataTypeManagerDB dtm =
|
||||
askChoice("Fixup All Composites", "Select Data Type Manager: ", dtms, dtms.get(0)).dtm;
|
||||
|
||||
if (dtm instanceof ProgramDataTypeManager) {
|
||||
Program program = ((ProgramDataTypeManager) dtm).getProgram();
|
||||
if (dtm instanceof ProgramDataTypeManager programDtm) {
|
||||
Program program = programDtm.getProgram();
|
||||
if (!program.hasExclusiveAccess()) {
|
||||
popup("Shared program must have an exclusive checkout.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (dtm instanceof ProjectDataTypeManager) {
|
||||
DomainFile df = ((ProjectDataTypeManager) dtm).getDomainFile();
|
||||
else if (dtm.getDataStore() instanceof ProjectDataTypeArchive projectArchive) {
|
||||
DomainFile df = projectArchive.getDomainFile();
|
||||
if (df.isVersioned() && !df.isCheckedOutExclusive()) {
|
||||
popup("Shared project archive must have an exclusive checkout.");
|
||||
return;
|
||||
@@ -87,7 +85,6 @@ public class FixupCompositeDataTypesScript extends GhidraScript {
|
||||
popup("Selected archive must be open for update.");
|
||||
return;
|
||||
}
|
||||
|
||||
dtm.fixupComposites(monitor);
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -22,48 +22,49 @@
|
||||
import java.io.File;
|
||||
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.database.dtarchive.DataTypeArchiveFactory;
|
||||
import ghidra.program.model.data.Category;
|
||||
import ghidra.program.model.data.FileDataTypeManager;
|
||||
import ghidra.program.model.data.StandAloneDataTypeManager.ArchiveWarning;
|
||||
import ghidra.program.model.dtarchive.ArchiveWarning;
|
||||
import ghidra.program.model.dtarchive.FileDataTypeArchive;
|
||||
import ghidra.util.InvalidNameException;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class SynchronizeGDTCategoryPaths extends GhidraScript {
|
||||
|
||||
@Override
|
||||
protected void run() throws Exception {
|
||||
|
||||
File firstFile = askFile("Select First GDT File", "Select 1st");
|
||||
try (FileDataTypeManager firstArchive =
|
||||
FileDataTypeManager.openFileArchive(firstFile, false)) {
|
||||
if (hasWarning(firstArchive, firstFile)) {
|
||||
FileDataTypeArchive archive1 = null;
|
||||
FileDataTypeArchive archive2 = null;
|
||||
try {
|
||||
File file1 = askFile("Select First GDT File", "Select 1st");
|
||||
archive1 = DataTypeArchiveFactory.openReadOnly(file1, this, TaskMonitor.DUMMY);
|
||||
if (hasWarning(archive1, file1)) {
|
||||
return;
|
||||
}
|
||||
File file2 = askFile("Select Second GDT File", "Select 2nd");
|
||||
archive2 = DataTypeArchiveFactory.openReadOnly(file2, this, TaskMonitor.DUMMY);
|
||||
if (hasWarning(archive2, file2)) {
|
||||
return;
|
||||
}
|
||||
Category firstCategory = archive1.getDataTypeManager().getRootCategory();
|
||||
Category secondCategory = archive2.getDataTypeManager().getRootCategory();
|
||||
|
||||
File secondFile = askFile("Select Second GDT File", "Select 2nd");
|
||||
try (FileDataTypeManager secondArchive =
|
||||
FileDataTypeManager.openFileArchive(secondFile, true)) {
|
||||
if (hasWarning(secondArchive, secondFile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int transactionID =
|
||||
secondArchive.startTransaction("Synchronize Category Path Names");
|
||||
try {
|
||||
Category firstCategory = firstArchive.getRootCategory();
|
||||
Category secondCategory = secondArchive.getRootCategory();
|
||||
synchronizeCategory(firstCategory, secondCategory);
|
||||
}
|
||||
finally {
|
||||
secondArchive.endTransaction(transactionID, true);
|
||||
secondArchive.save();
|
||||
secondArchive.close();
|
||||
}
|
||||
archive2.withTransaction("Synchronized Category Path Names",
|
||||
() -> synchronizeCategory(firstCategory, secondCategory));
|
||||
}
|
||||
finally {
|
||||
if (archive1 != null) {
|
||||
archive1.release(this);
|
||||
}
|
||||
if (archive2 != null) {
|
||||
archive2.release(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasWarning(FileDataTypeManager archive, File file) {
|
||||
private boolean hasWarning(FileDataTypeArchive archive, File file) {
|
||||
ArchiveWarning warning = archive.getWarning();
|
||||
if (warning == ArchiveWarning.NONE) {
|
||||
return false;
|
||||
|
||||
+9
-22
@@ -94,7 +94,7 @@
|
||||
<I>Data Type Manager</I> window. When a data type archive is open, it
|
||||
is displayed as a node in the <I>Data Type Manager</I>
|
||||
tree. Archives can be opened by the user or automatically when a program is opened which
|
||||
references that archive. Data type archives can be <A href="#open_for_editing">open for
|
||||
references that archive. Data type archives can be <A href="#Open_Archive_For_Editing">open for
|
||||
modification</A> or as read-only. Within the <I>Data Type Manager</I> window there are
|
||||
actions for opening, closing, renaming, and making archives modifiable.</P>
|
||||
</BLOCKQUOTE>
|
||||
@@ -243,17 +243,6 @@
|
||||
the program</B>.</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="Update_Source_Archive_Names">Update Source Archive Names</A></H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>When new releases of Ghidra are installed, old datatype archives may be dropped. In some
|
||||
cases these old archives may be replaced with a differently named archive. When this
|
||||
happens, this popup action can be used on a client archive to update the old source archive
|
||||
references. This popup action is only available when such an archive name change has
|
||||
occurred. Any programs or other client archives which reference the old archive will have
|
||||
this popup action available to update the source archive name reference.</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3>Committing Changes To Source Archive</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
@@ -349,7 +338,7 @@
|
||||
files are organized into directories in a filesystem. Archives are useful for sharing data
|
||||
types with other users, or making your data types available for use in other projects.
|
||||
Normally, file archives are opened in a read-only mode, but can optionally be <A href=
|
||||
"#open_for_editing">opened</A> for editing. Project archives are normally opened for
|
||||
"#Open_Archive_For_Editing">opened</A> for editing. Project archives are normally opened for
|
||||
editing, since they support sharing and version control and therefore allow more than one
|
||||
user to modify them at a time. Only one user at a time can have a file archive opened for
|
||||
editing.</P>
|
||||
@@ -467,7 +456,7 @@
|
||||
Archive</B></I> action. The archive will be removed from the tree.</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="open_for_editing"></A>Opening a File Data Type Archive for Editing</H3>
|
||||
<H3><A name="Open_Archive_For_Editing"></A>Opening a File Data Type Archive for Editing</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>When an archive is first opened, it is not editable. In order to make any changes to
|
||||
@@ -479,13 +468,13 @@
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<DIV align="left">
|
||||
<H3><A name="Unlock_Archive"></A> <A name="Lock_Archive"></A>Closing a File Data Type
|
||||
<H3><A name></A> <A name="Close_Archive_For_Editing"></A>Closing a File Data Type
|
||||
Archive for Editing<BR>
|
||||
</H3>
|
||||
</DIV>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>When an archive that is <A href="#open_for_editing">open for editing</A> no longer
|
||||
<P>When an archive that is <A href="#Open_Archive_For_Editing">open for editing</A> no longer
|
||||
needs to be edited, then it should be put back to a read-only mode so that other users
|
||||
can then modify it. Select the data type archive to close for editing, right-click on it
|
||||
and select the <I><B>Close for Editing</B></I> action. If the archive has unsaved
|
||||
@@ -502,7 +491,6 @@
|
||||
changes will be saved and the name will be updated to not show a '*'.</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<!-- Unimplemented Action
|
||||
<H3><A name="Save_As"></A>Saving a File Data Type Archive to a New File<BR>
|
||||
</H3>
|
||||
|
||||
@@ -512,7 +500,6 @@
|
||||
and filename for the new archive that will be created. The tree will be updated to show
|
||||
the new name for the archive (the filename). The original archive file is unaffected.</P>
|
||||
</BLOCKQUOTE>
|
||||
-->
|
||||
|
||||
<H3><A name="Undo_Archive_Change"></A>Undo Unsaved Archive Change</H3>
|
||||
|
||||
@@ -523,7 +510,7 @@
|
||||
stack of unsaved changes. The next change which may be reverted is described by the archive's
|
||||
Undo Change popup menu item. If this action is used and a change is reverted it may be re-applied by using the
|
||||
<A href="#Redo_Archive_Change">Redo Change</A> action. When the data type archive is
|
||||
<A href="#Save">saved</A> or <A href="#Lock_Archive">closed for editing</A> the undo/redo stack is
|
||||
<A href="#Save">saved</A> or <A href="#Close_Archive_For_Editing">closed for editing</A> the undo/redo stack is
|
||||
cleared.
|
||||
</P>
|
||||
|
||||
@@ -538,7 +525,7 @@
|
||||
The next reverted change which may be re-applied is described by the archive's
|
||||
Redo Change popup menu item. If this action is used and a change is re-applied it may again be reverted by using the
|
||||
<A href="#Undo_Archive_Change">Undo Change</A> action. When the data type archive is
|
||||
<A href="#Save">saved</A> or <A href="#Lock_Archive">closed for editing</A> the undo/redo stack is
|
||||
<A href="#Save">saved</A> or <A href="#Close_Archive_For_Editing">closed for editing</A> the undo/redo stack is
|
||||
cleared.
|
||||
</P>
|
||||
|
||||
@@ -550,7 +537,7 @@
|
||||
<P>Deleting an archive will not only remove the archive from the tree, but will
|
||||
permanently remove it from the filesystem. To delete an archive, right-click on it and
|
||||
select the <I><B>Delete Archive</B></I> action. An archive file must be open for editing
|
||||
before this action will appear (see <A href="#open_for_editing">Opening a Data Type
|
||||
before this action will appear (see <A href="#Open_Archive_For_Editing">Opening a Data Type
|
||||
Archive for Editing</A>).</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
@@ -615,7 +602,7 @@
|
||||
|
||||
<P><IMG alt="" src="help/shared/note.png">
|
||||
The source archive must be editable in order to commit. File archives must be <A href=
|
||||
"data_type_manager_description.htm#open_for_editing">open for editing</A> and project
|
||||
"data_type_manager_description.htm#Open_Archive_For_Editing">open for editing</A> and project
|
||||
archives that are under version control must be checked-out.</P>
|
||||
|
||||
<P><IMG alt="" src="help/shared/note.png">Any data type dependencies for a comitted
|
||||
|
||||
@@ -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.
|
||||
@@ -22,6 +22,7 @@ import ghidra.framework.PluggableServiceRegistry;
|
||||
import ghidra.framework.data.ToolStateFactory;
|
||||
import ghidra.framework.main.datatree.GhidraDataFlavorHandlerService;
|
||||
import ghidra.program.database.*;
|
||||
import ghidra.program.database.data.DataTypeArchiveMergeManagerFactory;
|
||||
|
||||
public class FoundationInitializer implements ModuleInitializer {
|
||||
@Override
|
||||
|
||||
+18
-21
@@ -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.
|
||||
@@ -16,21 +16,20 @@
|
||||
package ghidra.app.merge;
|
||||
|
||||
import ghidra.app.merge.datatypes.DataTypeMergeManager;
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.framework.plugintool.ModalPluginTool;
|
||||
import ghidra.program.model.data.DataTypeManagerDomainObject;
|
||||
import ghidra.program.model.listing.DataTypeArchive;
|
||||
import ghidra.program.model.dtarchive.ProjectDataTypeArchive;
|
||||
import ghidra.program.model.listing.DataTypeArchiveChangeSet;
|
||||
|
||||
/**
|
||||
* Top level object that manages each step of the merge/resolve conflicts
|
||||
* process.
|
||||
*/
|
||||
public class DataTypeArchiveMergeManager extends MergeManager {
|
||||
public class DataTypeArchiveMergeManager
|
||||
extends MergeManager<ProjectDataTypeArchive, DataTypeArchiveChangeSet> {
|
||||
|
||||
public DataTypeArchiveMergeManager(DataTypeManagerDomainObject resultDtArchive,
|
||||
DataTypeManagerDomainObject myDtArchive, DataTypeManagerDomainObject originalDtArchive,
|
||||
DataTypeManagerDomainObject latestDtArchive, DataTypeArchiveChangeSet latestChangeSet,
|
||||
public DataTypeArchiveMergeManager(ProjectDataTypeArchive resultDtArchive,
|
||||
ProjectDataTypeArchive myDtArchive, ProjectDataTypeArchive originalDtArchive,
|
||||
ProjectDataTypeArchive latestDtArchive, DataTypeArchiveChangeSet latestChangeSet,
|
||||
DataTypeArchiveChangeSet myChangeSet) {
|
||||
super(resultDtArchive, myDtArchive, originalDtArchive, latestDtArchive, latestChangeSet,
|
||||
myChangeSet);
|
||||
@@ -43,11 +42,8 @@ public class DataTypeArchiveMergeManager extends MergeManager {
|
||||
mergeResolvers = new MergeResolver[1];
|
||||
|
||||
mergeResolvers[idx++] =
|
||||
new DataTypeMergeManager(this, (DataTypeManagerDomainObject) resultDomainObject,
|
||||
(DataTypeManagerDomainObject) myDomainObject,
|
||||
(DataTypeManagerDomainObject) originalDomainObject,
|
||||
(DataTypeManagerDomainObject) latestDomainObject,
|
||||
(DataTypeArchiveChangeSet) latestChangeSet, (DataTypeArchiveChangeSet) myChangeSet);
|
||||
new DataTypeMergeManager(this, resultDomainObject, myDomainObject, originalDomainObject,
|
||||
latestDomainObject, latestChangeSet, myChangeSet);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,16 +54,16 @@ public class DataTypeArchiveMergeManager extends MergeManager {
|
||||
* @return the indicated program version or null if a valid version isn't specified.
|
||||
* @see MergeConstants
|
||||
*/
|
||||
public DataTypeArchive getDataTypeArchive(int version) {
|
||||
public ProjectDataTypeArchive getDataTypeArchive(int version) {
|
||||
switch (version) {
|
||||
case MergeConstants.LATEST:
|
||||
return (DataTypeArchive) latestDomainObject;
|
||||
return latestDomainObject;
|
||||
case MergeConstants.MY:
|
||||
return (DataTypeArchive) myDomainObject;
|
||||
return myDomainObject;
|
||||
case MergeConstants.ORIGINAL:
|
||||
return (DataTypeArchive) originalDomainObject;
|
||||
return originalDomainObject;
|
||||
case MergeConstants.RESULT:
|
||||
return (DataTypeArchive) resultDomainObject;
|
||||
return resultDomainObject;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@@ -75,9 +71,10 @@ public class DataTypeArchiveMergeManager extends MergeManager {
|
||||
|
||||
@Override
|
||||
protected MergeManagerPlugin createMergeManagerPlugin(ModalPluginTool mergePluginTool,
|
||||
MergeManager multiUserMergeManager, DomainObject modifiableDomainObject) {
|
||||
MergeManager<ProjectDataTypeArchive, DataTypeArchiveChangeSet> multiUserMergeManager,
|
||||
ProjectDataTypeArchive modifiableDomainObject) {
|
||||
return new DataTypeArchiveMergeManagerPlugin(mergeTool, DataTypeArchiveMergeManager.this,
|
||||
(DataTypeArchive) resultDomainObject);
|
||||
resultDomainObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+4
-4
@@ -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.
|
||||
@@ -21,7 +21,7 @@ import ghidra.app.CorePluginPackage;
|
||||
import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.framework.plugintool.*;
|
||||
import ghidra.framework.plugintool.util.PluginStatus;
|
||||
import ghidra.program.model.listing.DataTypeArchive;
|
||||
import ghidra.program.model.dtarchive.ProjectDataTypeArchive;
|
||||
|
||||
/**
|
||||
* Plugin that provides a merge component provider for data type archives.
|
||||
@@ -45,7 +45,7 @@ public class DataTypeArchiveMergeManagerPlugin extends MergeManagerPlugin {
|
||||
*/
|
||||
public DataTypeArchiveMergeManagerPlugin(PluginTool tool,
|
||||
DataTypeArchiveMergeManager mergeManager,
|
||||
DataTypeArchive dataTypeArchive) {
|
||||
ProjectDataTypeArchive dataTypeArchive) {
|
||||
super(tool, mergeManager, dataTypeArchive);
|
||||
}
|
||||
|
||||
|
||||
@@ -38,17 +38,20 @@ import help.HelpService;
|
||||
/**
|
||||
* Top level object that manages each step of the merge/resolve conflicts
|
||||
* process.
|
||||
* @param <T> domain object implementation class
|
||||
* @param <C> domain object change set implementation class
|
||||
*/
|
||||
public abstract class MergeManager implements DomainObjectMergeManager {
|
||||
public abstract class MergeManager<T extends DomainObject, C extends DomainObjectChangeSet>
|
||||
implements DomainObjectMergeManager {
|
||||
|
||||
protected MergeResolver[] mergeResolvers;
|
||||
|
||||
protected DomainObject resultDomainObject; // where changes will be merged to
|
||||
protected DomainObject myDomainObject; // source of changes to be applied
|
||||
protected DomainObject originalDomainObject; // original version that was checked out
|
||||
protected DomainObject latestDomainObject; // latest version of the program
|
||||
protected DomainObjectChangeSet latestChangeSet;
|
||||
protected DomainObjectChangeSet myChangeSet;
|
||||
protected T resultDomainObject; // where changes will be merged to
|
||||
protected T myDomainObject; // source of changes to be applied
|
||||
protected T originalDomainObject; // original version that was checked out
|
||||
protected T latestDomainObject; // latest version of the program
|
||||
protected C latestChangeSet;
|
||||
protected C myChangeSet;
|
||||
|
||||
protected MergeManagerPlugin mergePlugin;
|
||||
// protected ListingMergePanelPlugin listingPlugin;
|
||||
@@ -69,9 +72,9 @@ public abstract class MergeManager implements DomainObjectMergeManager {
|
||||
|
||||
// protected boolean isShowingListingMergePanel = false;
|
||||
|
||||
public MergeManager(DomainObject resultDomainObject, DomainObject myDomainObject,
|
||||
DomainObject originalDomainObject, DomainObject latestDomainObject,
|
||||
DomainObjectChangeSet latestChangeSet, DomainObjectChangeSet myChangeSet) {
|
||||
public MergeManager(T resultDomainObject, T myDomainObject,
|
||||
T originalDomainObject, T latestDomainObject,
|
||||
C latestChangeSet, C myChangeSet) {
|
||||
this.resultDomainObject = resultDomainObject;
|
||||
this.myDomainObject = myDomainObject;
|
||||
this.originalDomainObject = originalDomainObject;
|
||||
@@ -95,7 +98,7 @@ public abstract class MergeManager implements DomainObjectMergeManager {
|
||||
* @return the indicated program version or null if a valid version isn't specified.
|
||||
* @see MergeConstants
|
||||
*/
|
||||
public DomainObject getDomainObject(int version) {
|
||||
public T getDomainObject(int version) {
|
||||
switch (version) {
|
||||
case MergeConstants.LATEST:
|
||||
return latestDomainObject;
|
||||
@@ -208,7 +211,7 @@ public abstract class MergeManager implements DomainObjectMergeManager {
|
||||
}
|
||||
|
||||
protected abstract MergeManagerPlugin createMergeManagerPlugin(ModalPluginTool mergePluginTool,
|
||||
MergeManager multiUserMergeManager, DomainObject modifiableDomainObject);
|
||||
MergeManager<T, C> multiUserMergeManager, T modifiableDomainObject);
|
||||
|
||||
protected abstract void initializeMerge();
|
||||
|
||||
|
||||
+20
-20
@@ -33,7 +33,6 @@ import ghidra.app.nav.*;
|
||||
import ghidra.app.plugin.core.navigation.GoToAddressLabelPlugin;
|
||||
import ghidra.app.util.ListingHighlightProvider;
|
||||
import ghidra.app.util.viewer.util.FieldNavigator;
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.framework.plugintool.ModalPluginTool;
|
||||
import ghidra.framework.plugintool.Plugin;
|
||||
import ghidra.framework.plugintool.util.PluginException;
|
||||
@@ -50,7 +49,7 @@ import help.HelpService;
|
||||
/**
|
||||
* Top level object that manages each step of the merge/resolve conflicts process.
|
||||
*/
|
||||
public class ProgramMultiUserMergeManager extends MergeManager {
|
||||
public class ProgramMultiUserMergeManager extends MergeManager<Program, ProgramChangeSet> {
|
||||
|
||||
private ListingMergePanelPlugin listingPlugin;
|
||||
private GoToAddressLabelPlugin goToPlugin;
|
||||
@@ -73,10 +72,10 @@ public class ProgramMultiUserMergeManager extends MergeManager {
|
||||
|
||||
@Override
|
||||
protected void createMergeResolvers() {
|
||||
Program resultProgram = (Program) resultDomainObject;
|
||||
Program myProgram = (Program) myDomainObject;
|
||||
Program originalProgram = (Program) originalDomainObject;
|
||||
Program latestProgram = (Program) latestDomainObject;
|
||||
Program resultProgram = resultDomainObject;
|
||||
Program myProgram = myDomainObject;
|
||||
Program originalProgram = originalDomainObject;
|
||||
Program latestProgram = latestDomainObject;
|
||||
// create the merge resolvers
|
||||
int idx = 0;
|
||||
mergeResolvers = new MergeResolver[8];
|
||||
@@ -85,28 +84,28 @@ public class ProgramMultiUserMergeManager extends MergeManager {
|
||||
|
||||
mergeResolvers[idx++] =
|
||||
new ProgramTreeMergeManager(this, resultProgram, myProgram, originalProgram,
|
||||
latestProgram, (ProgramChangeSet) latestChangeSet, (ProgramChangeSet) myChangeSet);
|
||||
latestProgram, latestChangeSet, myChangeSet);
|
||||
|
||||
mergeResolvers[idx++] =
|
||||
new DataTypeMergeManager(this, resultProgram, myProgram, originalProgram, latestProgram,
|
||||
(ProgramChangeSet) latestChangeSet, (ProgramChangeSet) myChangeSet);
|
||||
latestChangeSet, myChangeSet);
|
||||
|
||||
mergeResolvers[idx++] =
|
||||
new ProgramContextMergeManager(this, resultProgram, originalProgram, latestProgram,
|
||||
myProgram, (ProgramChangeSet) latestChangeSet, (ProgramChangeSet) myChangeSet);
|
||||
myProgram, latestChangeSet, myChangeSet);
|
||||
|
||||
mergeResolvers[idx++] =
|
||||
new FunctionTagMerger(this, resultProgram, originalProgram, latestProgram, myProgram,
|
||||
(ProgramChangeSet) latestChangeSet, (ProgramChangeSet) myChangeSet);
|
||||
latestChangeSet, myChangeSet);
|
||||
|
||||
ListingMergeManager listingMergeManager =
|
||||
new ListingMergeManager(this, resultProgram, originalProgram, latestProgram, myProgram,
|
||||
(ProgramChangeSet) latestChangeSet, (ProgramChangeSet) myChangeSet);
|
||||
latestChangeSet, myChangeSet);
|
||||
mergeResolvers[idx++] = listingMergeManager;
|
||||
|
||||
mergeResolvers[idx++] =
|
||||
new ExternalProgramMerger(this, resultProgram, originalProgram, latestProgram,
|
||||
myProgram, (ProgramChangeSet) latestChangeSet, (ProgramChangeSet) myChangeSet);
|
||||
myProgram, latestChangeSet, myChangeSet);
|
||||
|
||||
mergeResolvers[idx++] = new PropertyListMergeManager(this, resultProgram, myProgram,
|
||||
originalProgram, latestProgram);
|
||||
@@ -122,13 +121,13 @@ public class ProgramMultiUserMergeManager extends MergeManager {
|
||||
public Program getProgram(int version) {
|
||||
switch (version) {
|
||||
case MergeConstants.LATEST:
|
||||
return (Program) resultDomainObject;
|
||||
return resultDomainObject;
|
||||
case MergeConstants.MY:
|
||||
return (Program) myDomainObject;
|
||||
return myDomainObject;
|
||||
case MergeConstants.ORIGINAL:
|
||||
return (Program) originalDomainObject;
|
||||
return originalDomainObject;
|
||||
case MergeConstants.RESULT:
|
||||
return (Program) latestDomainObject;
|
||||
return latestDomainObject;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@@ -136,15 +135,16 @@ public class ProgramMultiUserMergeManager extends MergeManager {
|
||||
|
||||
@Override
|
||||
protected MergeManagerPlugin createMergeManagerPlugin(ModalPluginTool mergePluginTool,
|
||||
MergeManager multiUserMergeManager, DomainObject modifiableDomainObject) {
|
||||
MergeManager<Program, ProgramChangeSet> multiUserMergeManager,
|
||||
Program modifiableDomainObject) {
|
||||
return new ProgramMergeManagerPlugin(mergeTool, ProgramMultiUserMergeManager.this,
|
||||
(Program) resultDomainObject);
|
||||
resultDomainObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initializeMerge() {
|
||||
mergePanel = new ListingMergePanel(mergeTool, (Program) originalDomainObject,
|
||||
(Program) resultDomainObject, (Program) myDomainObject, (Program) latestDomainObject,
|
||||
mergePanel = new ListingMergePanel(mergeTool, originalDomainObject,
|
||||
resultDomainObject, myDomainObject, latestDomainObject,
|
||||
showListingPanels);
|
||||
mergePanel.removeDomainObjectListener();
|
||||
navigatable = new MergeNavigatable(mergePanel);
|
||||
|
||||
+53
-25
@@ -26,11 +26,14 @@ import org.apache.commons.lang3.Strings;
|
||||
import ghidra.app.merge.*;
|
||||
import ghidra.app.util.HelpTopics;
|
||||
import ghidra.framework.data.DomainObjectMergeManager;
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.program.database.data.DataTypeManagerDB;
|
||||
import ghidra.program.database.data.DataTypeUtilities;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.Enum;
|
||||
import ghidra.program.model.dtarchive.ProjectDataTypeArchive;
|
||||
import ghidra.program.model.listing.DataTypeChangeSet;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
@@ -54,7 +57,7 @@ public class DataTypeMergeManager implements MergeResolver {
|
||||
static final int OPTION_ORIGINAL = 2; // Original
|
||||
|
||||
private DomainObjectMergeManager mergeManager;
|
||||
private DataTypeManagerDomainObject[] domainObjects = new DataTypeManagerDomainObject[4];
|
||||
private DomainObject[] domainObjects = new DomainObject[4];
|
||||
private DataTypeManager[] dtms = new DataTypeManager[4];
|
||||
private TaskMonitor currentMonitor;
|
||||
private int originalConflictOption;
|
||||
@@ -93,30 +96,55 @@ public class DataTypeMergeManager implements MergeResolver {
|
||||
/**
|
||||
* Manager for merging the data types using the four programs.
|
||||
* @param mergeManager overall merge manager for domain object
|
||||
* @param resultDomainObject the program to be updated with the result of the merge.
|
||||
* @param resultArchive the program to be updated with the result of the merge.
|
||||
* This is the program that will actually get checked in.
|
||||
* @param myDomainObject the program requesting to be checked in.
|
||||
* @param originalDomainObject the program that was checked out.
|
||||
* @param latestDomainObject the latest checked-in version of the program.
|
||||
* @param myArchive the program requesting to be checked in.
|
||||
* @param originalArchive the program that was checked out.
|
||||
* @param latestArchive the latest checked-in version of the program.
|
||||
* @param latestChanges the address set of changes between original and latest versioned program.
|
||||
* @param myChanges the address set of changes between original and my modified program.
|
||||
*/
|
||||
public DataTypeMergeManager(DomainObjectMergeManager mergeManager,
|
||||
DataTypeManagerDomainObject resultDomainObject,
|
||||
DataTypeManagerDomainObject myDomainObject,
|
||||
DataTypeManagerDomainObject originalDomainObject,
|
||||
DataTypeManagerDomainObject latestDomainObject, DataTypeChangeSet latestChanges,
|
||||
ProjectDataTypeArchive resultArchive,
|
||||
ProjectDataTypeArchive myArchive,
|
||||
ProjectDataTypeArchive originalArchive,
|
||||
ProjectDataTypeArchive latestArchive,
|
||||
DataTypeChangeSet latestChanges,
|
||||
DataTypeChangeSet myChanges) {
|
||||
this.mergeManager = mergeManager;
|
||||
domainObjects[RESULT] = resultDomainObject;
|
||||
domainObjects[ORIGINAL] = originalDomainObject;
|
||||
domainObjects[LATEST] = latestDomainObject;
|
||||
domainObjects[MY] = myDomainObject;
|
||||
dtms[RESULT] = resultDomainObject.getDataTypeManager();
|
||||
dtms[ORIGINAL] = originalDomainObject.getDataTypeManager();
|
||||
dtms[LATEST] = latestDomainObject.getDataTypeManager();
|
||||
dtms[MY] = myDomainObject.getDataTypeManager();
|
||||
|
||||
this.mergeManager = mergeManager;
|
||||
domainObjects[RESULT] = resultArchive;
|
||||
domainObjects[ORIGINAL] = originalArchive;
|
||||
domainObjects[LATEST] = latestArchive;
|
||||
domainObjects[MY] = myArchive;
|
||||
dtms[RESULT] = resultArchive.getDataTypeManager();
|
||||
dtms[ORIGINAL] = originalArchive.getDataTypeManager();
|
||||
dtms[LATEST] = latestArchive.getDataTypeManager();
|
||||
dtms[MY] = myArchive.getDataTypeManager();
|
||||
init(latestChanges, myChanges);
|
||||
}
|
||||
|
||||
public DataTypeMergeManager(DomainObjectMergeManager mergeManager,
|
||||
Program resultProgram,
|
||||
Program myProgram,
|
||||
Program originalProgram,
|
||||
Program latestProgram,
|
||||
DataTypeChangeSet latestChanges,
|
||||
DataTypeChangeSet myChanges) {
|
||||
|
||||
this.mergeManager = mergeManager;
|
||||
domainObjects[RESULT] = resultProgram;
|
||||
domainObjects[ORIGINAL] = originalProgram;
|
||||
domainObjects[LATEST] = latestProgram;
|
||||
domainObjects[MY] = myProgram;
|
||||
dtms[RESULT] = resultProgram.getDataTypeManager();
|
||||
dtms[ORIGINAL] = originalProgram.getDataTypeManager();
|
||||
dtms[LATEST] = latestProgram.getDataTypeManager();
|
||||
dtms[MY] = myProgram.getDataTypeManager();
|
||||
init(latestChanges, myChanges);
|
||||
}
|
||||
|
||||
private void init(DataTypeChangeSet latestChanges, DataTypeChangeSet myChanges) {
|
||||
totalConflictCount = 0;
|
||||
setupSourceArchiveChanges(latestChanges, myChanges);
|
||||
setupDataTypeChanges(latestChanges, myChanges);
|
||||
@@ -1315,7 +1343,7 @@ public class DataTypeMergeManager implements MergeResolver {
|
||||
try {
|
||||
resultComp =
|
||||
destStruct.addBitField(resultCompDt, bfDt.getDeclaredBitSize(),
|
||||
sourceComp.getFieldName(), comment);
|
||||
sourceComp.getFieldName(), comment);
|
||||
}
|
||||
catch (InvalidDataTypeException e) {
|
||||
displayError(destStruct, e);
|
||||
@@ -1338,14 +1366,14 @@ public class DataTypeMergeManager implements MergeResolver {
|
||||
// If I have compDt, it should now be from result DTM.
|
||||
resultComp =
|
||||
destStruct.add(resultCompDt, length, sourceComp.getFieldName(),
|
||||
comment);
|
||||
comment);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
comment =
|
||||
buildDataTypeFailureComment(sourceCompDt, e.getMessage(), comment);
|
||||
resultComp =
|
||||
destStruct.add(BadDataType.dataType, sourceComp.getLength(),
|
||||
sourceComp.getFieldName(), comment);
|
||||
sourceComp.getFieldName(), comment);
|
||||
if (e.getCause() instanceof DataTypeDependencyException) {
|
||||
badIdDtMsgs.put(dtId, e.getMessage());
|
||||
}
|
||||
@@ -1364,8 +1392,8 @@ public class DataTypeMergeManager implements MergeResolver {
|
||||
try {
|
||||
resultComp = destStruct
|
||||
.insertBitFieldAt(sourceComp.getOffset(), sourceComp.getLength(),
|
||||
bfDt.getBitOffset(), resultCompDt, bfDt.getDeclaredBitSize(),
|
||||
sourceComp.getFieldName(), comment);
|
||||
bfDt.getBitOffset(), resultCompDt, bfDt.getDeclaredBitSize(),
|
||||
sourceComp.getFieldName(), comment);
|
||||
}
|
||||
catch (InvalidDataTypeException e) {
|
||||
displayError(destStruct, e);
|
||||
@@ -1376,7 +1404,7 @@ public class DataTypeMergeManager implements MergeResolver {
|
||||
try {
|
||||
resultComp =
|
||||
destStruct.addBitField(primitiveBaseDt, bfDt.getDeclaredBitSize(),
|
||||
sourceComp.getFieldName(), comment);
|
||||
sourceComp.getFieldName(), comment);
|
||||
}
|
||||
catch (InvalidDataTypeException exc) {
|
||||
throw new RuntimeException(exc); // unexpected
|
||||
@@ -1429,7 +1457,7 @@ public class DataTypeMergeManager implements MergeResolver {
|
||||
comment = buildDataTypeFailureComment(sourceCompDt, badMsg, comment);
|
||||
resultComp =
|
||||
destStruct.insertAtOffset(sourceComp.getOffset(), BadDataType.dataType,
|
||||
sourceComp.getLength(), sourceComp.getFieldName(), comment);
|
||||
sourceComp.getLength(), sourceComp.getFieldName(), comment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-6
@@ -33,9 +33,9 @@ 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.data.*;
|
||||
import ghidra.program.model.dtarchive.FileDataTypeArchive;
|
||||
import ghidra.program.model.dtarchive.ProjectDataTypeArchive;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.util.Msg;
|
||||
@@ -132,11 +132,11 @@ public class ApplyDataArchiveAnalyzer extends AbstractAnalyzer {
|
||||
|
||||
options.registerOption(OPTION_NAME_GDT_FILEPATH, OptionType.FILE_TYPE, null, null,
|
||||
OPTION_DESCRIPTION_GDT_FILEPATH,
|
||||
() -> new FileChooserEditor(FileDataTypeManager.GDT_FILEFILTER));
|
||||
() -> new FileChooserEditor(FileDataTypeArchive.GDT_FILEFILTER));
|
||||
options.registerOption(OPTION_NAME_PROJECT_PATH, OptionType.STRING_TYPE, null, null,
|
||||
OPTION_DESCRIPTION_PROJECT_PATH,
|
||||
() -> new ProjectPathChooserEditor("Choose Data Type Archive",
|
||||
new DefaultDomainFileFilter(DataTypeArchive.class, false)));
|
||||
new DefaultDomainFileFilter(ProjectDataTypeArchive.class, false)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -293,7 +293,7 @@ public class ApplyDataArchiveAnalyzer extends AbstractAnalyzer {
|
||||
log.appendMsg("Missing project archive: %s".formatted(filename));
|
||||
return List.of();
|
||||
}
|
||||
if (!DataTypeArchive.class.isAssignableFrom(gdtDomainFile.getDomainObjectClass())) {
|
||||
if (!ProjectDataTypeArchive.class.isAssignableFrom(gdtDomainFile.getDomainObjectClass())) {
|
||||
log.appendMsg("Bad project file type: %s".formatted(filename));
|
||||
return List.of();
|
||||
}
|
||||
|
||||
+2
-2
@@ -21,14 +21,14 @@ import java.util.Set;
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.archive.BuiltInSourceArchive;
|
||||
import ghidra.app.plugin.core.datamgr.archive.DefaultDataTypeArchiveService;
|
||||
import ghidra.app.plugin.core.datamgr.archive.BasicDataTypeArchiveService;
|
||||
import ghidra.app.services.DataTypeManagerService;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
// FIXME!! TESTING
|
||||
public class DefaultDataTypeManagerService extends DefaultDataTypeArchiveService
|
||||
public class DefaultDataTypeManagerService extends BasicDataTypeArchiveService
|
||||
implements DataTypeManagerService {
|
||||
|
||||
// TODO: This implementation needs to be consolidated with the tool-based service in
|
||||
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
/* ###
|
||||
* 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.compositeeditor;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import db.DBHandle;
|
||||
import ghidra.framework.data.OpenMode;
|
||||
import ghidra.program.database.dtarchive.DataTypeArchiveDB;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.VersionException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import utility.function.Callback;
|
||||
|
||||
/**
|
||||
* DataTypeAchive used to edit composites (unions or structures)
|
||||
*
|
||||
* @param <T> The specific type of composite
|
||||
*/
|
||||
public class CompositeEditorDtArchiveDB<T extends Composite> extends DataTypeArchiveDB {
|
||||
private int transactionId;
|
||||
|
||||
/**
|
||||
* Special constructor for stack editor. We create a transaction that is always open for the
|
||||
* life of this archive so that undo/redo is not available.
|
||||
* @param originalDTM the data type manager this archive is shadowing.
|
||||
* @throws IOException if an {@link IOException} occurs initializing the database.
|
||||
*/
|
||||
CompositeEditorDtArchiveDB(DataTypeManager originalDTM) throws IOException {
|
||||
this(originalDTM, null, null, null);
|
||||
|
||||
// This prevents undo/redo by always have a transaction open during its full lifecycle.
|
||||
transactionId = startTransaction("Composite Edit");
|
||||
}
|
||||
|
||||
public CompositeEditorDtArchiveDB(T originalComposite, Callback changeCallback,
|
||||
Callback restoredCallback) throws IOException {
|
||||
this(originalComposite.getDataTypeManager(), originalComposite, changeCallback,
|
||||
restoredCallback);
|
||||
}
|
||||
|
||||
protected CompositeEditorDtArchiveDB(DataTypeManager originalDTM, T originalComposite,
|
||||
Callback changeCallback,
|
||||
Callback restoredCallback) throws IOException {
|
||||
super(new DBHandle(), originalDTM.getName(), new Object());
|
||||
CompositeViewerDataTypeManager<T> dtm = getDataTypeManager();
|
||||
withTransaction("Setup for Edit", () -> {
|
||||
dtm.intialize(originalDTM, originalComposite, changeCallback, restoredCallback);
|
||||
});
|
||||
clearUndo();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public CompositeViewerDataTypeManager<T> getDataTypeManager() {
|
||||
return (CompositeViewerDataTypeManager<T>) super.getDataTypeManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CompositeViewerDataTypeManager<T> createDataTypeManager(DBHandle handle,
|
||||
OpenMode openMode, TaskMonitor monitor)
|
||||
throws VersionException, IOException, CancelledException {
|
||||
|
||||
return new CompositeViewerDataTypeManager<>(handle, openMode, this, lock, monitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTemporary() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Temporary Data Type Archive For Composite Editing";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isArchitectureChangeAllowed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void close() {
|
||||
if (transactionId != 0) {
|
||||
endTransaction(transactionId, changed);
|
||||
}
|
||||
super.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArchiveType getArchiveType() {
|
||||
return ArchiveType.TEMPORARY;
|
||||
}
|
||||
|
||||
}
|
||||
+7
-7
@@ -100,9 +100,10 @@ abstract public class CompositeEditorModel<T extends Composite> extends Composit
|
||||
originalDataTypePath = originalComposite.getDataTypePath();
|
||||
currentName = originalComposite.getName();
|
||||
|
||||
// Use temporary standalone view datatype manager
|
||||
viewDTM = new CompositeViewerDataTypeManager<>(viewDTM.getName(),
|
||||
viewDTM.getResolvedViewComposite(), this::componentEdited, this::restoreEditor);
|
||||
// Use temporary view datatype manager
|
||||
T composite = viewDTM.getResolvedViewComposite();
|
||||
viewDTM = CompositeViewerDataTypeManager.createUndoableInstance(composite, this::componentEdited,
|
||||
this::restoreEditor);
|
||||
|
||||
viewComposite = viewDTM.getResolvedViewComposite();
|
||||
|
||||
@@ -225,10 +226,9 @@ abstract public class CompositeEditorModel<T extends Composite> extends Composit
|
||||
viewDTM = null;
|
||||
}
|
||||
|
||||
// Use temporary standalone view datatype manager
|
||||
viewDTM =
|
||||
new CompositeViewerDataTypeManager<>(originalComposite.getDataTypeManager().getName(),
|
||||
originalComposite, this::componentEdited, this::restoreEditor);
|
||||
// Use temporary stand-alone view datatype archive
|
||||
viewDTM = CompositeViewerDataTypeManager.createUndoableInstance(originalComposite,
|
||||
this::componentEdited, this::restoreEditor);
|
||||
|
||||
viewComposite = viewDTM.getResolvedViewComposite();
|
||||
|
||||
|
||||
+63
-58
File diff suppressed because it is too large
Load Diff
+38
-30
@@ -17,15 +17,18 @@ package ghidra.app.plugin.core.cparser;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.help.UnsupportedOperationException;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import docking.widgets.dialogs.MultiLineMessageDialog;
|
||||
import ghidra.app.util.cparser.C.CParserUtils.CParseResults;
|
||||
import ghidra.program.database.data.ProgramDataTypeManager;
|
||||
import ghidra.program.database.dtarchive.DataTypeArchiveFactory;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.FileDataTypeManager;
|
||||
import ghidra.program.model.dtarchive.DataTypeStore;
|
||||
import ghidra.program.model.dtarchive.FileDataTypeArchive;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.DuplicateFileException;
|
||||
import ghidra.util.task.Task;
|
||||
@@ -39,16 +42,16 @@ import ghidra.util.task.TaskMonitor;
|
||||
class CParserTask extends Task {
|
||||
|
||||
private CParserPlugin plugin;
|
||||
|
||||
|
||||
private String[] filenames;
|
||||
private String[] includePaths;
|
||||
|
||||
|
||||
private String options;
|
||||
|
||||
|
||||
// Language and Compiler Spec IDs valid only for new dataFileName use
|
||||
private String languageId;
|
||||
private String compilerSpecId;
|
||||
|
||||
|
||||
// Either dataTypeManager or dataFileName must be set, but not both
|
||||
private final DataTypeManager dataTypeManager; // specified for an existing DataTypeManager
|
||||
private final File dataFile; // specified for a new file
|
||||
@@ -61,6 +64,7 @@ class CParserTask extends Task {
|
||||
*/
|
||||
CParserTask(CParserPlugin plugin, String dataFileName) {
|
||||
super("Parsing C Files", true, false, false);
|
||||
Objects.requireNonNull(dataFileName, "Target datatype archive filename required");
|
||||
dataTypeManager = null;
|
||||
this.plugin = plugin;
|
||||
this.dataFile = new File(dataFileName);
|
||||
@@ -77,6 +81,7 @@ class CParserTask extends Task {
|
||||
*/
|
||||
public CParserTask(CParserPlugin plugin, DataTypeManager dataTypeManager) {
|
||||
super("Parsing C Files", true, false, false);
|
||||
Objects.requireNonNull(dataTypeManager, "Target datatype manager required");
|
||||
dataFile = null;
|
||||
this.plugin = plugin;
|
||||
this.dataTypeManager = dataTypeManager;
|
||||
@@ -101,7 +106,7 @@ class CParserTask extends Task {
|
||||
this.languageId = languageId;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the compiler spec ID to be used. This ID must be defined for the specified language.
|
||||
*
|
||||
@@ -121,17 +126,17 @@ class CParserTask extends Task {
|
||||
this.compilerSpecId = compilerSpecId;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public CParserTask setIncludePaths(String includePaths[]) {
|
||||
this.includePaths = includePaths.clone();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public CParserTask setFileNames(String names[]) {
|
||||
this.filenames = names.clone();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public CParserTask setOptions(String options) {
|
||||
this.options = options;
|
||||
return this;
|
||||
@@ -158,16 +163,16 @@ class CParserTask extends Task {
|
||||
return msg;
|
||||
}
|
||||
|
||||
private String getParseDestination(DataTypeManager dtMgr) {
|
||||
private String getParseDestination(DataTypeStore archive) {
|
||||
String parseDest = "";
|
||||
if (dtMgr instanceof ProgramDataTypeManager) {
|
||||
parseDest = "Program " + dtMgr.getName();
|
||||
if (archive instanceof Program) {
|
||||
parseDest = "Program " + archive.getName();
|
||||
}
|
||||
else if (dtMgr instanceof FileDataTypeManager fileDtm) {
|
||||
parseDest = "Archive File: " + fileDtm.getFilename();
|
||||
else if (archive instanceof FileDataTypeArchive fileArchive) {
|
||||
parseDest = "Archive File: " + fileArchive.getPath();
|
||||
}
|
||||
else {
|
||||
parseDest = dtMgr.getName();
|
||||
parseDest = archive.getName();
|
||||
}
|
||||
return parseDest;
|
||||
}
|
||||
@@ -175,7 +180,7 @@ class CParserTask extends Task {
|
||||
@Override
|
||||
public void run(TaskMonitor monitor) {
|
||||
|
||||
FileDataTypeManager fileDtMgr = null;
|
||||
FileDataTypeArchive dataFileArchive = null;
|
||||
if (dataFile != null) {
|
||||
try {
|
||||
if ((languageId != null) != (compilerSpecId != null)) {
|
||||
@@ -184,8 +189,8 @@ class CParserTask extends Task {
|
||||
compilerSpecId);
|
||||
return;
|
||||
}
|
||||
fileDtMgr =
|
||||
FileDataTypeManager.createFileArchive(dataFile, languageId, compilerSpecId);
|
||||
dataFileArchive = DataTypeArchiveFactory.createFileArchive(dataFile, languageId,
|
||||
compilerSpecId, this);
|
||||
}
|
||||
catch (IOException e) {
|
||||
Msg.showError(this, plugin.getDialog().getComponent(), "Archive Failure",
|
||||
@@ -194,10 +199,12 @@ class CParserTask extends Task {
|
||||
}
|
||||
}
|
||||
|
||||
DataTypeManager dtMgr = fileDtMgr != null ? fileDtMgr : dataTypeManager;
|
||||
DataTypeManager dtMgr =
|
||||
dataFileArchive != null ? dataFileArchive.getDataTypeManager() : dataTypeManager;
|
||||
|
||||
int initialDtCount = dtMgr.getDataTypeCount(true);
|
||||
|
||||
String archiveDetination = getParseDestination(dtMgr.getDataStore());
|
||||
try {
|
||||
|
||||
CParseResults results = plugin.parse(filenames, includePaths, options, dtMgr, monitor);
|
||||
@@ -205,10 +212,10 @@ class CParserTask extends Task {
|
||||
return; // cancelled
|
||||
}
|
||||
|
||||
if (fileDtMgr != null && dtMgr.getDataTypeCount(true) != 0) {
|
||||
if (dataFileArchive != null && dtMgr.getDataTypeCount(true) != 0) {
|
||||
// If archive created - save to file
|
||||
try {
|
||||
fileDtMgr.save();
|
||||
dataFileArchive.save(null, monitor);
|
||||
}
|
||||
catch (DuplicateFileException e) {
|
||||
Msg.showError(this, plugin.getDialog().getComponent(),
|
||||
@@ -228,7 +235,7 @@ class CParserTask extends Task {
|
||||
if (!results.successful()) {
|
||||
MultiLineMessageDialog.showModalMessageDialog(
|
||||
plugin.getDialog().getComponent(), "C-Parse Failed",
|
||||
"Failed to parse header file(s) to " + getParseDestination(dtMgr),
|
||||
"Failed to parse header file(s) to " + archiveDetination,
|
||||
plugin.getFormattedParseMessage(msg),
|
||||
MultiLineMessageDialog.INFORMATION_MESSAGE);
|
||||
}
|
||||
@@ -236,7 +243,7 @@ class CParserTask extends Task {
|
||||
MultiLineMessageDialog.showModalMessageDialog(
|
||||
plugin.getDialog().getComponent(),
|
||||
"C-Parse Completed",
|
||||
"Successfully parsed header file(s) to " + getParseDestination(dtMgr),
|
||||
"Successfully parsed header file(s) to " + archiveDetination,
|
||||
plugin.getFormattedParseMessage(msg),
|
||||
MultiLineMessageDialog.INFORMATION_MESSAGE);
|
||||
}
|
||||
@@ -247,7 +254,7 @@ class CParserTask extends Task {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
MultiLineMessageDialog.showMessageDialog(plugin.getDialog().getComponent(),
|
||||
"C-Parse Failed",
|
||||
"Failed to parse header file(s) to " + getParseDestination(dtMgr),
|
||||
"Failed to parse header file(s) to " + archiveDetination,
|
||||
plugin.getFormattedParseMessage(errMsg),
|
||||
MultiLineMessageDialog.ERROR_MESSAGE);
|
||||
});
|
||||
@@ -257,7 +264,7 @@ class CParserTask extends Task {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
MultiLineMessageDialog.showMessageDialog(plugin.getDialog().getComponent(),
|
||||
"C-PreProcessor Parse Failed",
|
||||
"Failed to parse header file(s) to " + getParseDestination(dtMgr),
|
||||
"Failed to parse header file(s) to " + archiveDetination,
|
||||
plugin.getFormattedParseMessage(errMsg),
|
||||
MultiLineMessageDialog.ERROR_MESSAGE);
|
||||
});
|
||||
@@ -270,15 +277,16 @@ class CParserTask extends Task {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
MultiLineMessageDialog.showMessageDialog(plugin.getDialog().getComponent(),
|
||||
"Error During C-Parse",
|
||||
"Failed to parse header file(s) to " + getParseDestination(dtMgr),
|
||||
"Failed to parse header file(s) to " + archiveDetination,
|
||||
plugin.getFormattedParseMessage(errMsg),
|
||||
MultiLineMessageDialog.ERROR_MESSAGE);
|
||||
});
|
||||
}
|
||||
finally {
|
||||
if (fileDtMgr != null) {
|
||||
boolean deleteFile = fileDtMgr.getDataTypeCount(true) == 0;
|
||||
fileDtMgr.close();
|
||||
if (dataFileArchive != null) {
|
||||
boolean deleteFile =
|
||||
dataFileArchive.getDataTypeManager().getDataTypeCount(true) == 0;
|
||||
dataFileArchive.release(this);
|
||||
if (deleteFile) {
|
||||
dataFile.delete();
|
||||
}
|
||||
|
||||
+17
-17
@@ -46,7 +46,7 @@ import ghidra.framework.Application;
|
||||
import ghidra.framework.options.SaveState;
|
||||
import ghidra.framework.preferences.Preferences;
|
||||
import ghidra.framework.store.db.PackedDatabase;
|
||||
import ghidra.program.model.data.FileDataTypeManager;
|
||||
import ghidra.program.model.dtarchive.FileDataTypeArchive;
|
||||
import ghidra.program.model.lang.CompilerSpecID;
|
||||
import ghidra.program.model.lang.LanguageID;
|
||||
import ghidra.util.HelpLocation;
|
||||
@@ -150,7 +150,7 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
||||
void writeState(SaveState saveState) {
|
||||
// Get the current state if the dialog has been displayed
|
||||
if (!initialBuild) {
|
||||
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
|
||||
ComboBoxItem item = comboBox.getSelectedItem();
|
||||
|
||||
currentProfileName = item.file.getName();
|
||||
userDefined = item.isUserDefined;
|
||||
@@ -172,7 +172,7 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
||||
if (initialBuild) {
|
||||
return;
|
||||
}
|
||||
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
|
||||
ComboBoxItem item = comboBox.getSelectedItem();
|
||||
if (item.isChanged) {
|
||||
processItemChanged(item);
|
||||
}
|
||||
@@ -255,7 +255,7 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
||||
});
|
||||
|
||||
tableListener = e -> {
|
||||
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
|
||||
ComboBoxItem item = comboBox.getSelectedItem();
|
||||
item.isChanged = !initialBuild;
|
||||
notifyContextChanged();
|
||||
};
|
||||
@@ -270,7 +270,7 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
||||
new ExtensionFileFilter(new String[] { "h" }, "C Header Files"));
|
||||
|
||||
parsePathTableListener = e -> {
|
||||
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
|
||||
ComboBoxItem item = comboBox.getSelectedItem();
|
||||
item.isChanged = !initialBuild;
|
||||
notifyContextChanged();
|
||||
pathPanel.getTable().repaint();
|
||||
@@ -485,7 +485,7 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
||||
}
|
||||
|
||||
private void itemChanged() {
|
||||
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
|
||||
ComboBoxItem item = comboBox.getSelectedItem();
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
@@ -497,12 +497,12 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
||||
saveAction = new DockingAction("Save Profile", plugin.getName()) {
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
save((ComboBoxItem) comboBox.getSelectedItem());
|
||||
save(comboBox.getSelectedItem());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
|
||||
ComboBoxItem item = comboBox.getSelectedItem();
|
||||
return item.isChanged && item.isUserDefined;
|
||||
}
|
||||
};
|
||||
@@ -516,7 +516,7 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
||||
saveAsAction = new DockingAction("Save Profile As", plugin.getName()) {
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
saveAs((ComboBoxItem) comboBox.getSelectedItem());
|
||||
saveAs(comboBox.getSelectedItem());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -577,7 +577,7 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
|
||||
ComboBoxItem item = comboBox.getSelectedItem();
|
||||
return item.isUserDefined;
|
||||
}
|
||||
};
|
||||
@@ -590,7 +590,7 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
||||
}
|
||||
|
||||
private void refresh() {
|
||||
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
|
||||
ComboBoxItem item = comboBox.getSelectedItem();
|
||||
if (item.isChanged) {
|
||||
processItemChanged(item);
|
||||
}
|
||||
@@ -610,7 +610,7 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
||||
private void clear() {
|
||||
pathPanel.clear();
|
||||
parseOptionsField.setText("");
|
||||
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
|
||||
ComboBoxItem item = comboBox.getSelectedItem();
|
||||
item.isChanged = true;
|
||||
}
|
||||
|
||||
@@ -681,7 +681,7 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
||||
}
|
||||
tableModel.removeTableModelListener(tableListener);
|
||||
parsePathTableModel.removeTableModelListener(parsePathTableListener);
|
||||
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
|
||||
ComboBoxItem item = comboBox.getSelectedItem();
|
||||
item.isChanged = false;
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
@@ -817,7 +817,7 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
||||
}
|
||||
|
||||
private void delete() {
|
||||
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
|
||||
ComboBoxItem item = comboBox.getSelectedItem();
|
||||
if (item.isUserDefined) {
|
||||
if (OptionDialog.showOptionDialog(getComponent(), "Delete Profile?",
|
||||
"Are you sure you want to delete profile " + item.getName(), "Delete",
|
||||
@@ -944,8 +944,8 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
||||
}
|
||||
|
||||
String name = file.getName();
|
||||
if (!file.getName().endsWith(FileDataTypeManager.SUFFIX)) {
|
||||
file = new File(file.getParentFile(), name + FileDataTypeManager.SUFFIX);
|
||||
if (!file.getName().endsWith(FileDataTypeArchive.SUFFIX)) {
|
||||
file = new File(file.getParentFile(), name + FileDataTypeArchive.SUFFIX);
|
||||
}
|
||||
|
||||
if (!file.exists()) {
|
||||
@@ -1086,7 +1086,7 @@ class ParseDialog extends ReusableDialogComponentProvider {
|
||||
}
|
||||
|
||||
ComboBoxItem getCurrentItem() {
|
||||
ComboBoxItem item = (ComboBoxItem) comboBox.getSelectedItem();
|
||||
ComboBoxItem item = comboBox.getSelectedItem();
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
+572
File diff suppressed because it is too large
Load Diff
+11
-13
@@ -1,37 +1,35 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* 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 ghidra.framework.GenericRunInfo;
|
||||
import ghidra.framework.preferences.Preferences;
|
||||
import ghidra.program.model.data.FileDataTypeManager;
|
||||
import ghidra.util.filechooser.ExtensionFileFilter;
|
||||
package ghidra.app.plugin.core.datamgr;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.io.File;
|
||||
|
||||
import docking.widgets.filechooser.GhidraFileChooser;
|
||||
import ghidra.framework.GenericRunInfo;
|
||||
import ghidra.framework.preferences.Preferences;
|
||||
import ghidra.program.model.dtarchive.FileDataTypeArchive;
|
||||
import ghidra.util.filechooser.ExtensionFileFilter;
|
||||
|
||||
public class ArchiveFileChooser extends GhidraFileChooser {
|
||||
|
||||
public ArchiveFileChooser(Component component) {
|
||||
super(component);
|
||||
|
||||
setFileFilter(new ExtensionFileFilter(new String[] { FileDataTypeManager.EXTENSION },
|
||||
setFileFilter(new ExtensionFileFilter(new String[] { FileDataTypeArchive.EXTENSION },
|
||||
"Ghidra Data Type Files"));
|
||||
setApproveButtonText("Save As");
|
||||
setApproveButtonToolTipText("Save As");
|
||||
@@ -52,7 +50,7 @@ public class ArchiveFileChooser extends GhidraFileChooser {
|
||||
}
|
||||
setCurrentDirectory(projectDirectory);
|
||||
|
||||
String suggestedName = suggestedFileName + FileDataTypeManager.SUFFIX;
|
||||
String suggestedName = suggestedFileName + FileDataTypeArchive.SUFFIX;
|
||||
setSelectedFile(new File(projectDirectory, suggestedName));
|
||||
|
||||
File file = getSelectedFile();
|
||||
@@ -68,10 +66,10 @@ public class ArchiveFileChooser extends GhidraFileChooser {
|
||||
|
||||
private File fixFilenameSuffix(File file) {
|
||||
String filename = file.getName();
|
||||
if (filename.endsWith(FileDataTypeManager.SUFFIX)) {
|
||||
if (filename.endsWith(FileDataTypeArchive.SUFFIX)) {
|
||||
return file;
|
||||
}
|
||||
filename += FileDataTypeManager.SUFFIX;
|
||||
filename += FileDataTypeArchive.SUFFIX;
|
||||
return new File(file.getParentFile(), filename);
|
||||
}
|
||||
}
|
||||
+826
File diff suppressed because it is too large
Load Diff
+73
@@ -0,0 +1,73 @@
|
||||
/* ###
|
||||
* 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;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.archive.InvalidArchive;
|
||||
import ghidra.program.model.dtarchive.PersistentDataTypeArchive;
|
||||
import ghidra.program.model.dtarchive.DataTypeStore;
|
||||
import ghidra.program.model.listing.Program;
|
||||
|
||||
/**
|
||||
* Interface for notifications when archives change in the archive manager
|
||||
*/
|
||||
public interface ArchiveManagerListener {
|
||||
/**
|
||||
* Called when a new Archive is opened.
|
||||
* @param archive the new archive that was opened.
|
||||
*/
|
||||
public void archiveOpened(PersistentDataTypeArchive archive);
|
||||
|
||||
/**
|
||||
* Called when an archive is closed.
|
||||
* @param archive the archive that was closed.
|
||||
*/
|
||||
public void archiveClosed(PersistentDataTypeArchive archive);
|
||||
|
||||
/**
|
||||
* Called when a new program is activated
|
||||
* @param program the program that is activated
|
||||
*/
|
||||
public void programOpened(Program program);
|
||||
|
||||
/**
|
||||
* Called when the current program is deactivated
|
||||
* @param program the program that is being deactivated
|
||||
*/
|
||||
public void programClosed(Program program);
|
||||
|
||||
/**
|
||||
* Called when the tool attempts to open a file or project archive that is referenced by
|
||||
* a program, but can't be found. This creates a object that actions can operate on to
|
||||
* either attempt to find it or use it to remove the references from a program.
|
||||
* @param invalidArchive the InvalidArchive object that describes what the program was trying
|
||||
* to open.
|
||||
*/
|
||||
public void invalidArchiveAdded(InvalidArchive invalidArchive);
|
||||
|
||||
/**
|
||||
* Called when an invalid archive is removed from the tool.
|
||||
* @param invalidArchive the invalid archive object that was removed from the tool
|
||||
*/
|
||||
public void invalidArchiveRemoved(InvalidArchive invalidArchive);
|
||||
|
||||
/**
|
||||
* Notification that a change to the datatypeStore has occurred. Could be a datatype or
|
||||
* category was added, changed, or deleted. Could also mean that the changes were saved to
|
||||
* the backing store or the that a save as operation occurred.
|
||||
* @param dataTypeStore The store whose state changed
|
||||
*/
|
||||
public void stateChanged(DataTypeStore dataTypeStore);
|
||||
}
|
||||
+61
-62
File diff suppressed because it is too large
Load Diff
+87
@@ -0,0 +1,87 @@
|
||||
/* ###
|
||||
* 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;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.HelpTopics;
|
||||
import ghidra.framework.main.DataTreeDialog;
|
||||
import ghidra.framework.main.DataTreeDialogType;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.framework.model.DomainFolder;
|
||||
import ghidra.program.database.dtarchive.DataTypeArchiveFactory;
|
||||
import ghidra.program.model.dtarchive.ProjectDataTypeArchive;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
public class CreateProjectArchiveDialog extends DataTreeDialog {
|
||||
|
||||
private Object consumer;
|
||||
private ProjectDataTypeArchive archive;
|
||||
|
||||
public CreateProjectArchiveDialog(Object consumer) {
|
||||
super(null, "Create Project Archive", DataTreeDialogType.CREATE);
|
||||
this.consumer = consumer;
|
||||
setHelpLocation(new HelpLocation(HelpTopics.DATA_MANAGER, "New_Project_Data_Type_Archive"));
|
||||
}
|
||||
|
||||
public ProjectDataTypeArchive getArchive() {
|
||||
return archive;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void okCallback() {
|
||||
DomainFolder folder = getDomainFolder();
|
||||
String name = getNameText();
|
||||
if (name.length() == 0) {
|
||||
setStatusText("Please enter a name");
|
||||
return;
|
||||
}
|
||||
if (folder == null) {
|
||||
setStatusText("Please select a folder");
|
||||
return;
|
||||
}
|
||||
DomainFile file = folder.getFile(name);
|
||||
if (file != null) {
|
||||
setStatusText("Choose a name that doesn't exist");
|
||||
return;
|
||||
}
|
||||
if (createArchive()) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean createArchive() {
|
||||
DomainFolder domainFolder = getDomainFolder();
|
||||
String archiveName = getNameText();
|
||||
try {
|
||||
archive =
|
||||
DataTypeArchiveFactory.createProjectArchive(domainFolder, archiveName, consumer);
|
||||
return true;
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
setStatusText("Duplicate Name: " + e.getMessage());
|
||||
}
|
||||
catch (InvalidNameException e) {
|
||||
setStatusText("Invalid Name: " + e.getMessage());
|
||||
}
|
||||
catch (IOException e) {
|
||||
setStatusText("Unexpected IOException!");
|
||||
Msg.showError(null, getComponent(), "Unexpected Exception", e.getMessage(), e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
/* ###
|
||||
* 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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.rmi.ConnectException;
|
||||
import java.util.List;
|
||||
|
||||
import docking.widgets.OptionDialog;
|
||||
import ghidra.framework.client.ClientUtil;
|
||||
import ghidra.framework.client.NotConnectedException;
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.framework.model.TransactionInfo;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.dtarchive.PersistentDataTypeArchive;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.Task;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class DataTypeArchiveSaveTask extends Task {
|
||||
private static final String CONTENT_NAME = "Data Type Archive";
|
||||
private PersistentDataTypeArchive archive;
|
||||
private PluginTool tool;
|
||||
|
||||
DataTypeArchiveSaveTask(PersistentDataTypeArchive archive, PluginTool tool) {
|
||||
super("Save " + archive.getName(), true, true, true);
|
||||
this.archive = archive;
|
||||
this.tool = tool;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(TaskMonitor monitor) {
|
||||
monitor.setMessage("Saving " + archive.getName() + "...");
|
||||
if (acquireSaveLock(archive)) {
|
||||
try {
|
||||
archive.save(null, monitor);
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
// O.K., expected
|
||||
}
|
||||
catch (NotConnectedException e) {
|
||||
ClientUtil.promptForReconnect(tool.getProject().getRepository(),
|
||||
tool.getToolFrame());
|
||||
}
|
||||
catch (ConnectException e) {
|
||||
ClientUtil.promptForReconnect(tool.getProject().getRepository(),
|
||||
tool.getToolFrame());
|
||||
}
|
||||
catch (IOException e) {
|
||||
ClientUtil.handleException(tool.getProject().getRepository(), e, "Save File",
|
||||
tool.getToolFrame());
|
||||
}
|
||||
finally {
|
||||
archive.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean acquireSaveLock(DomainObject domainObject) {
|
||||
if (!domainObject.lock(null)) {
|
||||
String title = "Save " + CONTENT_NAME + " (Busy)";
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append("The " + CONTENT_NAME + " is currently being modified by \n");
|
||||
buf.append("the following actions:\n ");
|
||||
TransactionInfo t = domainObject.getCurrentTransactionInfo();
|
||||
List<String> list = t.getOpenSubTransactions();
|
||||
for (String element : list) {
|
||||
buf.append("\n ");
|
||||
buf.append(element);
|
||||
}
|
||||
buf.append("\n \n");
|
||||
buf.append(
|
||||
"WARNING! The above task(s) should be cancelled before attempting a Save.\n");
|
||||
buf.append("Only proceed if unable to cancel them.\n \n");
|
||||
buf.append(
|
||||
"If you continue, all changes made by these tasks, as well as any other overlapping task,\n");
|
||||
buf.append(
|
||||
"will be LOST and subsequent transaction errors may occur while these tasks remain active.\n \n");
|
||||
|
||||
int result = OptionDialog.showOptionDialog(tool.getToolFrame(), title, buf.toString(),
|
||||
"Save Archive!", OptionDialog.WARNING_MESSAGE);
|
||||
|
||||
if (result == OptionDialog.OPTION_ONE) {
|
||||
domainObject.forceLock(true, "Save Archive");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.plugin.core.datamgr.archive;
|
||||
package ghidra.app.plugin.core.datamgr;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
+476
-160
File diff suppressed because it is too large
Load Diff
+11
-11
@@ -1,13 +1,12 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* 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.
|
||||
@@ -16,18 +15,19 @@
|
||||
*/
|
||||
package ghidra.app.plugin.core.datamgr;
|
||||
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.SystemUtilities;
|
||||
import ghidra.util.datastruct.WeakDataStructureFactory;
|
||||
import ghidra.util.datastruct.WeakSet;
|
||||
|
||||
import java.awt.event.KeyEvent;
|
||||
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.dtarchive.PersistentDataTypeArchive;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.SystemUtilities;
|
||||
import ghidra.util.datastruct.WeakDataStructureFactory;
|
||||
import ghidra.util.datastruct.WeakSet;
|
||||
|
||||
/**
|
||||
* Manages the attributes for data types; used by the manage data types
|
||||
* dialog to populate the data types tree structure.
|
||||
@@ -110,8 +110,8 @@ public class DataTypePropertyManager {
|
||||
programDataTypesManager = null;
|
||||
}
|
||||
|
||||
void domainObjectRestored(DataTypeManagerDomainObject domainObject) {
|
||||
DataTypeManager dataTypeManager = domainObject.getDataTypeManager();
|
||||
void domainObjectRestored(PersistentDataTypeArchive archive) {
|
||||
DataTypeManager dataTypeManager = archive.getDataTypeManager();
|
||||
if (dataTypeManager != programDataTypesManager) {
|
||||
return; // Ignore since not our program data type manager.
|
||||
}
|
||||
|
||||
+14
-15
@@ -25,7 +25,6 @@ import javax.swing.SwingUtilities;
|
||||
import org.apache.commons.lang3.Strings;
|
||||
|
||||
import docking.widgets.label.GDHtmlLabel;
|
||||
import ghidra.app.plugin.core.datamgr.archive.DataTypeManagerHandler;
|
||||
import ghidra.app.util.ToolTipUtils;
|
||||
import ghidra.app.util.html.HTMLDataTypeRepresentation;
|
||||
import ghidra.app.util.html.MissingArchiveDataTypeHTMLRepresentation;
|
||||
@@ -48,17 +47,17 @@ public class DataTypeSynchronizer {
|
||||
/**
|
||||
* Creates a DataTypeSynchronizer to be used for synchronizing data types between a program
|
||||
* and an archive.
|
||||
* @param dataTypeManagerHandler the handler that manages all the open data type managers
|
||||
* @param archiveManager the handler that manages all the open data type managers
|
||||
* whether built-in, program, project data type archive or file data type archive.
|
||||
* @param dataTypeManager the program data type manager.
|
||||
* @param source the data type source archive information indicating the associated archive for
|
||||
* synchronizing.
|
||||
*/
|
||||
public DataTypeSynchronizer(DataTypeManagerHandler dataTypeManagerHandler,
|
||||
DataTypeManager dataTypeManager, SourceArchive source) {
|
||||
public DataTypeSynchronizer(ArchiveManager archiveManager, DataTypeManager dataTypeManager,
|
||||
SourceArchive source) {
|
||||
this.dataTypeManager = dataTypeManager;
|
||||
this.sourceArchive = source;
|
||||
this.sourceDTM = dataTypeManagerHandler.getDataTypeManager(source);
|
||||
this.sourceDTM = archiveManager.getDataTypeManager(source);
|
||||
}
|
||||
|
||||
public List<DataTypeSyncInfo> findOutOfSynchDataTypes() {
|
||||
@@ -150,13 +149,13 @@ public class DataTypeSynchronizer {
|
||||
/**
|
||||
* Commits a single program data type's changes to the associated source data type in the
|
||||
* archive.
|
||||
* @param dtmHandler the handler that manages data types
|
||||
* @param archiveManager the archive manager
|
||||
* @param dt the program data type
|
||||
* @return true if the commit succeeds
|
||||
*/
|
||||
public static boolean commit(DataTypeManagerHandler dtmHandler, DataType dt) {
|
||||
public static boolean commit(ArchiveManager archiveManager, DataType dt) {
|
||||
SourceArchive sourceArchive = dt.getSourceArchive();
|
||||
DataTypeManager sourceDTM = dtmHandler.getDataTypeManager(sourceArchive);
|
||||
DataTypeManager sourceDTM = archiveManager.getDataTypeManager(sourceArchive);
|
||||
if (sourceDTM == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -167,14 +166,14 @@ public class DataTypeSynchronizer {
|
||||
/**
|
||||
* Updates a single data type in the program to match the associated source data type from the
|
||||
* archive.
|
||||
* @param dtmHandler the handler that manages data types
|
||||
* @param archiveManager the handler that manages data types
|
||||
* @param dt the data type
|
||||
* @return true if the update succeeds
|
||||
*/
|
||||
public static boolean update(DataTypeManagerHandler dtmHandler, DataType dt) {
|
||||
public static boolean update(ArchiveManager archiveManager, DataType dt) {
|
||||
DataTypeManager dataTypeManager = dt.getDataTypeManager();
|
||||
SourceArchive sourceArchive = dt.getSourceArchive();
|
||||
DataTypeManager sourceDtm = dtmHandler.getDataTypeManager(sourceArchive);
|
||||
DataTypeManager sourceDtm = archiveManager.getDataTypeManager(sourceArchive);
|
||||
if (dataTypeManager == null || sourceDtm == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -275,7 +274,7 @@ public class DataTypeSynchronizer {
|
||||
|
||||
}
|
||||
|
||||
public static DataTypeSyncState getSyncStatus(DataTypeManagerHandler handler,
|
||||
public static DataTypeSyncState getSyncStatus(ArchiveManager archiveManager,
|
||||
DataType dataType) {
|
||||
DataTypeManager dataTypeManager = dataType.getDataTypeManager();
|
||||
SourceArchive sourceArchive = dataType.getSourceArchive();
|
||||
@@ -287,7 +286,7 @@ public class DataTypeSynchronizer {
|
||||
boolean hasChangedLocally =
|
||||
dataType.getLastChangeTime() != dataType.getLastChangeTimeInSourceArchive();
|
||||
|
||||
DataTypeManager sourceDTM = handler.getDataTypeManager(sourceArchive);
|
||||
DataTypeManager sourceDTM = archiveManager.getDataTypeManager(sourceArchive);
|
||||
DataTypeSyncInfo syncInfo = new DataTypeSyncInfo(dataType, sourceDTM);
|
||||
if (sourceDTM == null) {
|
||||
return hasChangedLocally ? DataTypeSyncState.COMMIT : DataTypeSyncState.IN_SYNC;
|
||||
@@ -295,7 +294,7 @@ public class DataTypeSynchronizer {
|
||||
return syncInfo.getSyncState();
|
||||
}
|
||||
|
||||
public static String getDiffToolTip(DataTypeManagerHandler handler, DataType dataType) {
|
||||
public static String getDiffToolTip(ArchiveManager archiveManager, DataType dataType) {
|
||||
DataTypeManager dataTypeManager = dataType.getDataTypeManager();
|
||||
SourceArchive sourceArchive = dataType.getSourceArchive();
|
||||
UniversalID dataTypeID = dataType.getUniversalID();
|
||||
@@ -304,7 +303,7 @@ public class DataTypeSynchronizer {
|
||||
return null;
|
||||
}
|
||||
|
||||
DataTypeManager sourceDTM = handler.getDataTypeManager(sourceArchive);
|
||||
DataTypeManager sourceDTM = archiveManager.getDataTypeManager(sourceArchive);
|
||||
boolean hasChangedLocally =
|
||||
dataType.getLastChangeTime() != dataType.getLastChangeTimeInSourceArchive();
|
||||
DataType sourceDT = null;
|
||||
|
||||
+19
-6
@@ -26,11 +26,11 @@ import docking.widgets.tree.GTreeNode;
|
||||
import docking.widgets.tree.support.GTreeNodeTransferable;
|
||||
import ghidra.app.context.ProgramActionContext;
|
||||
import ghidra.app.plugin.core.datamgr.archive.BuiltInSourceArchive;
|
||||
import ghidra.app.plugin.core.datamgr.archive.ProjectArchive;
|
||||
import ghidra.app.plugin.core.datamgr.tree.*;
|
||||
import ghidra.framework.main.datatable.DomainFileContext;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.dtarchive.ProjectDataTypeArchive;
|
||||
import ghidra.program.model.listing.Program;
|
||||
|
||||
public class DataTypesActionContext extends ProgramActionContext implements DomainFileContext {
|
||||
@@ -90,11 +90,11 @@ public class DataTypesActionContext extends ProgramActionContext implements Doma
|
||||
domainFiles = new ArrayList<DomainFile>();
|
||||
for (TreePath path : selectionPaths) {
|
||||
Object lastPathComponent = path.getLastPathComponent();
|
||||
if (lastPathComponent instanceof ProjectArchiveNode) {
|
||||
ProjectArchiveNode node = (ProjectArchiveNode) lastPathComponent;
|
||||
ProjectArchive archive = (ProjectArchive) node.getArchive();
|
||||
DomainFile originalDomainFile = archive.getDomainFile();
|
||||
domainFiles.add(originalDomainFile);
|
||||
if (lastPathComponent instanceof ProjectArchiveNode node) {
|
||||
DomainFile originalDomainFile = node.getOriginalDomainFile();
|
||||
if (originalDomainFile != null) {
|
||||
domainFiles.add(originalDomainFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -156,4 +156,17 @@ public class DataTypesActionContext extends ProgramActionContext implements Doma
|
||||
return dataTypeNode;
|
||||
}
|
||||
|
||||
public List<ProjectDataTypeArchive> getSelectedProjectArchives() {
|
||||
List<ProjectDataTypeArchive> list = new ArrayList<>();
|
||||
|
||||
List<GTreeNode> selectedNodes = getSelectedNodes();
|
||||
for (GTreeNode node : selectedNodes) {
|
||||
if (node instanceof ProjectArchiveNode projectNode) {
|
||||
ProjectDataTypeArchive archive = projectNode.getArchive();
|
||||
list.add(archive);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+82
-126
File diff suppressed because it is too large
Load Diff
-239
File diff suppressed because it is too large
Load Diff
+117
@@ -0,0 +1,117 @@
|
||||
/* ###
|
||||
* 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;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
|
||||
import docking.widgets.OptionDialog;
|
||||
import generic.jar.ResourceFile;
|
||||
import ghidra.app.services.Upgrade;
|
||||
import ghidra.program.database.dtarchive.DataTypeArchiveFactory;
|
||||
import ghidra.program.model.dtarchive.FileDataTypeArchive;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.VersionExceptionHandler;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.VersionException;
|
||||
import ghidra.util.task.Task;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
class OpenFileArchiveTask extends Task {
|
||||
private ResourceFile file;
|
||||
private FileDataTypeArchive archive = null;
|
||||
private Object consumer;
|
||||
private Upgrade upgradeStrategy;
|
||||
private boolean openForUpdate;
|
||||
|
||||
OpenFileArchiveTask(ResourceFile file, boolean openForUpdate,
|
||||
Upgrade upgradeStrategy, Object consumer) {
|
||||
super("Opening File DataType Archive " + file.getName(), false, false, true);
|
||||
this.file = file;
|
||||
this.openForUpdate = openForUpdate;
|
||||
this.upgradeStrategy = upgradeStrategy;
|
||||
this.consumer = consumer;
|
||||
}
|
||||
|
||||
FileDataTypeArchive getArchive() {
|
||||
return archive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(TaskMonitor monitor) {
|
||||
try {
|
||||
archive = openArchive(monitor);
|
||||
}
|
||||
catch (FileNotFoundException e) {
|
||||
Msg.showError(this, null, "Open File Archive Failed",
|
||||
file.getAbsolutePath() + " not found!");
|
||||
}
|
||||
catch (IOException e) {
|
||||
Msg.showError(this, null, "Open File Archive Failed",
|
||||
e.getMessage() + ": " + file.getName());
|
||||
}
|
||||
catch (VersionException e) {
|
||||
VersionExceptionHandler.showVersionError(null, file.getName(), "Archive", "open", false,
|
||||
e);
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
// user cancelled, nothing to report
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public FileDataTypeArchive openArchive(TaskMonitor monitor)
|
||||
throws VersionException, IOException, CancelledException {
|
||||
|
||||
if (!openForUpdate) {
|
||||
return DataTypeArchiveFactory.openReadOnly(file, consumer, monitor);
|
||||
}
|
||||
try {
|
||||
return DataTypeArchiveFactory.openForUpdate(file, false, consumer, monitor);
|
||||
}
|
||||
catch (VersionException e) {
|
||||
if (shouldUpgrade(e)) {
|
||||
return DataTypeArchiveFactory.openForUpdate(file, true, consumer, monitor);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldUpgrade(VersionException e) {
|
||||
if (!e.isUpgradable()) {
|
||||
return false;
|
||||
}
|
||||
switch (upgradeStrategy) {
|
||||
case YES:
|
||||
return true;
|
||||
case NO:
|
||||
return false;
|
||||
case ASK:
|
||||
default:
|
||||
return askToUpgrade();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private boolean askToUpgrade() {
|
||||
return OptionDialog.showOptionDialog(null,
|
||||
"Upgrade File Archive: " + file.getName(),
|
||||
"File archive is an older version.\n" +
|
||||
"Do you want to upgrade it to the latest version?",
|
||||
"Upgrade",
|
||||
OptionDialog.QUESTION_MESSAGE) == OptionDialog.YES_OPTION;
|
||||
}
|
||||
}
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
/* ###
|
||||
* 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;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import docking.widgets.OptionDialog;
|
||||
import ghidra.app.services.Recover;
|
||||
import ghidra.app.services.Upgrade;
|
||||
import ghidra.framework.client.ClientUtil;
|
||||
import ghidra.framework.main.AppInfo;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.program.database.dtarchive.DataTypeArchiveFactory;
|
||||
import ghidra.program.model.dtarchive.ProjectDataTypeArchive;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.VersionException;
|
||||
import ghidra.util.task.Task;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
class OpenProjectArchiveTask extends Task {
|
||||
private DomainFile file;
|
||||
private int version;
|
||||
private ProjectDataTypeArchive archive = null;
|
||||
private Object consumer;
|
||||
private Recover recoverStrategy;
|
||||
private Upgrade upgradeStrategy;
|
||||
|
||||
OpenProjectArchiveTask(DomainFile file, int version, Upgrade upgradeStrategy,
|
||||
Recover recoverStrategy, Object consumer) {
|
||||
super("Open Project Data Type Archive", true, true, true);
|
||||
this.file = file;
|
||||
this.upgradeStrategy = upgradeStrategy;
|
||||
this.recoverStrategy = recoverStrategy;
|
||||
this.consumer = consumer;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
ProjectDataTypeArchive getArchive() {
|
||||
return archive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(TaskMonitor monitor) {
|
||||
monitor.setMessage(getDescription());
|
||||
try {
|
||||
archive = openArchive(monitor);
|
||||
}
|
||||
catch (VersionException e) {
|
||||
String contentType = file.getContentType();
|
||||
VersionExceptionHandler.showVersionError(null, file.getName(),
|
||||
contentType, "Open", false, e);
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
// do nothing, user cancelled
|
||||
}
|
||||
catch (IOException e) {
|
||||
if (file.isVersioned() && file.isInWritableProject()) {
|
||||
ClientUtil.handleException(AppInfo.getActiveProject().getRepository(), e,
|
||||
"Get Versioned Object", null);
|
||||
}
|
||||
else {
|
||||
Msg.showError(this, null, "Project Archive Open Error",
|
||||
"Error occurred while opening " + file.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private String getDescription() {
|
||||
String description = "Opening " + file.getName();
|
||||
if (version != DomainFile.DEFAULT_VERSION) {
|
||||
description += " (version " + version + ")";
|
||||
}
|
||||
return description;
|
||||
}
|
||||
|
||||
public ProjectDataTypeArchive openArchive(TaskMonitor monitor)
|
||||
throws VersionException, IOException, CancelledException {
|
||||
|
||||
if (shouldOpenImmutable(file)) {
|
||||
return DataTypeArchiveFactory.openReadOnly(file, version, consumer, monitor);
|
||||
}
|
||||
boolean okToRecover = shouldRecover();
|
||||
try {
|
||||
return DataTypeArchiveFactory.openForUpdate(file, consumer, false, okToRecover,
|
||||
monitor);
|
||||
}
|
||||
catch (VersionException e) {
|
||||
if (shouldUpgrade(e)) {
|
||||
return DataTypeArchiveFactory.openForUpdate(file, consumer, true, okToRecover,
|
||||
monitor);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldUpgrade(VersionException e) {
|
||||
if (!e.isUpgradable()) {
|
||||
return false;
|
||||
}
|
||||
switch (upgradeStrategy) {
|
||||
case YES:
|
||||
return true;
|
||||
case NO:
|
||||
return false;
|
||||
case ASK:
|
||||
default:
|
||||
return VersionExceptionHandler.isUpgradeOK(null, file, "Open File Archive", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldOpenImmutable(DomainFile domainFile) {
|
||||
if (version != DomainFile.DEFAULT_VERSION) {
|
||||
return true;
|
||||
}
|
||||
if (domainFile.isReadOnly()) {
|
||||
return true;
|
||||
}
|
||||
return domainFile.isVersioned() && !domainFile.isCheckedOut();
|
||||
}
|
||||
|
||||
private boolean shouldRecover() {
|
||||
if (!file.isInWritableProject()) {
|
||||
return false;
|
||||
}
|
||||
switch (recoverStrategy) {
|
||||
case YES:
|
||||
return true;
|
||||
case NO:
|
||||
return false;
|
||||
case ASK:
|
||||
default:
|
||||
return askToRecover();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean askToRecover() {
|
||||
if (!file.canRecover()) {
|
||||
return false;
|
||||
}
|
||||
int option = OptionDialog.showYesNoDialog(null, "Crash Recovery Data Found",
|
||||
"<html>" + HTMLUtilities.escapeHTML(file.getName()) + " has crash data.<br>" +
|
||||
"Would you like to recover unsaved changes?");
|
||||
return (option == OptionDialog.OPTION_ONE);
|
||||
}
|
||||
|
||||
}
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
/* ###
|
||||
* 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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import docking.widgets.OptionDialog;
|
||||
import ghidra.app.util.HelpTopics;
|
||||
import ghidra.framework.main.DataTreeDialog;
|
||||
import ghidra.framework.main.DataTreeDialogType;
|
||||
import ghidra.framework.model.*;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.dtarchive.ProjectDataTypeArchive;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskLauncher;
|
||||
|
||||
public class ProjectArchiveSaveAsDialog extends DataTreeDialog {
|
||||
private static final String CONTENT_NAME = "Data Type Archive";
|
||||
|
||||
private ProjectDataTypeArchive archive;
|
||||
|
||||
private PluginTool tool;
|
||||
|
||||
public ProjectArchiveSaveAsDialog(PluginTool tool, ProjectDataTypeArchive archive) {
|
||||
super(null, "Save Project Archive As", DataTreeDialogType.SAVE);
|
||||
this.tool = tool;
|
||||
this.archive = archive;
|
||||
setHelpLocation(new HelpLocation(HelpTopics.PROGRAM, "Save_As_File"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void okCallback() {
|
||||
DomainFolder folder = getDomainFolder();
|
||||
String name = getNameText();
|
||||
if (name.length() == 0) {
|
||||
setStatusText("Please enter a name");
|
||||
return;
|
||||
}
|
||||
if (folder == null) {
|
||||
setStatusText("Please select a folder");
|
||||
return;
|
||||
}
|
||||
DomainFile file = folder.getFile(name);
|
||||
if (file != null) {
|
||||
setStatusText("Choose a name that doesn't exist");
|
||||
return;
|
||||
}
|
||||
close();
|
||||
doSaveAs();
|
||||
}
|
||||
|
||||
private void doSaveAs() {
|
||||
if (!getSaveAsLock(archive)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
DomainFolder folder = getDomainFolder();
|
||||
String newName = getNameText();
|
||||
tool.prepareToSave(archive);
|
||||
TaskLauncher.launchModal("Save As", monitor -> {
|
||||
try {
|
||||
folder.createFile(newName, archive, monitor);
|
||||
}
|
||||
catch (InvalidNameException e) {
|
||||
Msg.showError(this, null, "Invalid Name", e.getMessage(), e);
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
// user cancelled, nothing to do
|
||||
}
|
||||
catch (IOException e) {
|
||||
Msg.showError(this, null, "I/O error ", e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
}
|
||||
finally {
|
||||
archive.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean getSaveAsLock(DomainObject domainObject) {
|
||||
if (!domainObject.lock(null)) {
|
||||
String title = "Save " + CONTENT_NAME + " As (Busy)";
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append("The " + CONTENT_NAME +
|
||||
" is currently being modified by the following actions/tasks:\n \n");
|
||||
TransactionInfo t = domainObject.getCurrentTransactionInfo();
|
||||
List<String> list = t.getOpenSubTransactions();
|
||||
for (String element : list) {
|
||||
buf.append("\n ");
|
||||
buf.append(element);
|
||||
}
|
||||
buf.append("\n \n");
|
||||
buf.append(
|
||||
"WARNING! The above task(s) should be cancelled before attempting a Save As...\n");
|
||||
buf.append("Only proceed if unable to cancel them.\n \n");
|
||||
buf.append(
|
||||
"If you click 'Save Archive As (Rollback)' {recommended}, all changes made\n");
|
||||
buf.append("by these tasks, as well as any other overlapping task, will be LOST!\n");
|
||||
buf.append(
|
||||
"If you click 'Save As (As Is)', the archive will be saved in its current\n");
|
||||
buf.append("state which may contain some incomplete data.\n");
|
||||
buf.append("Any forced save may also result in subsequent transaction errors while\n");
|
||||
buf.append("the above tasks remain active.\n ");
|
||||
|
||||
int result = OptionDialog.showOptionDialog(null, title, buf.toString(),
|
||||
"Save Archive As (Rollback)!", "Save Archive As (As Is)!",
|
||||
OptionDialog.WARNING_MESSAGE);
|
||||
|
||||
if (result == OptionDialog.OPTION_ONE) {
|
||||
domainObject.forceLock(true, "Save Archive As");
|
||||
return true;
|
||||
}
|
||||
else if (result == OptionDialog.OPTION_TWO) {
|
||||
domainObject.forceLock(false, "Save Archive As");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
+21
-22
@@ -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.
|
||||
@@ -27,8 +27,7 @@ import docking.widgets.tree.GTreeNode;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypesActionContext;
|
||||
import ghidra.app.plugin.core.datamgr.tree.*;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.StandAloneDataTypeManager;
|
||||
import ghidra.program.model.dtarchive.PersistentDataTypeArchive;
|
||||
|
||||
public abstract class AbstractUndoRedoArchiveTransactionAction extends DockingAction {
|
||||
|
||||
@@ -62,28 +61,28 @@ public abstract class AbstractUndoRedoArchiveTransactionAction extends DockingAc
|
||||
}
|
||||
|
||||
TreePath[] selectionPaths = getSelectionPaths(context);
|
||||
return getModifiableProjectOrFileDTM(selectionPaths) != null;
|
||||
return getModifiableProjectOrFileArchive(selectionPaths) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the corresponding undo/redo can be performed
|
||||
* @param dtm archive datatype manager
|
||||
* @param archive datatype archive
|
||||
* @return true if action can be performed on archive
|
||||
*/
|
||||
abstract protected boolean canExecute(StandAloneDataTypeManager dtm);
|
||||
abstract protected boolean canExecute(PersistentDataTypeArchive archive);
|
||||
|
||||
/**
|
||||
* Determine the next undo/redo transaction name
|
||||
* @param dtm archive datatype manager
|
||||
* @param archive datatype archive
|
||||
* @return next undo/redo transaction name
|
||||
*/
|
||||
abstract protected String getNextName(StandAloneDataTypeManager dtm);
|
||||
abstract protected String getNextName(PersistentDataTypeArchive archive);
|
||||
|
||||
/**
|
||||
* Execute the undo/redo operation on the specified archive datatype manager.
|
||||
* @param dtm archive datatype manager
|
||||
* Execute the undo/redo operation on the specified archive.
|
||||
* @param archive datatype archive
|
||||
*/
|
||||
abstract protected void execute(StandAloneDataTypeManager dtm);
|
||||
abstract protected void execute(PersistentDataTypeArchive archive);
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
@@ -92,9 +91,9 @@ public abstract class AbstractUndoRedoArchiveTransactionAction extends DockingAc
|
||||
}
|
||||
|
||||
TreePath[] selectionPaths = getSelectionPaths(context);
|
||||
StandAloneDataTypeManager dtm = getModifiableProjectOrFileDTM(selectionPaths);
|
||||
if (dtm != null && canExecute(dtm)) {
|
||||
setPopupMenuData(getMenuData(getNextName(dtm)));
|
||||
PersistentDataTypeArchive dta = getModifiableProjectOrFileArchive(selectionPaths);
|
||||
if (dta != null && canExecute(dta)) {
|
||||
setPopupMenuData(getMenuData(getNextName(dta)));
|
||||
return true;
|
||||
}
|
||||
setPopupMenuData(getMenuData(null));
|
||||
@@ -109,9 +108,9 @@ public abstract class AbstractUndoRedoArchiveTransactionAction extends DockingAc
|
||||
}
|
||||
|
||||
TreePath[] selectionPaths = getSelectionPaths(context);
|
||||
StandAloneDataTypeManager dtm = getModifiableProjectOrFileDTM(selectionPaths);
|
||||
if (dtm != null && canExecute(dtm)) {
|
||||
execute(dtm);
|
||||
PersistentDataTypeArchive dta = getModifiableProjectOrFileArchive(selectionPaths);
|
||||
if (dta != null && canExecute(dta)) {
|
||||
execute(dta);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,7 +121,7 @@ public abstract class AbstractUndoRedoArchiveTransactionAction extends DockingAc
|
||||
return selectionPaths;
|
||||
}
|
||||
|
||||
private StandAloneDataTypeManager getModifiableProjectOrFileDTM(TreePath[] selectionPaths) {
|
||||
private PersistentDataTypeArchive getModifiableProjectOrFileArchive(TreePath[] selectionPaths) {
|
||||
// only valid if single file or project archive node is selected
|
||||
if (selectionPaths.length != 1) {
|
||||
return null;
|
||||
@@ -140,9 +139,9 @@ public abstract class AbstractUndoRedoArchiveTransactionAction extends DockingAc
|
||||
|
||||
ArchiveNode archiveNode = (ArchiveNode) node;
|
||||
if (archiveNode.isModifiable()) {
|
||||
DataTypeManager dtm = archiveNode.getArchive().getDataTypeManager();
|
||||
if (dtm instanceof StandAloneDataTypeManager archiveDtm) {
|
||||
return archiveDtm;
|
||||
PersistentDataTypeArchive archive = archiveNode.getArchive();
|
||||
if (archive instanceof PersistentDataTypeArchive dta) {
|
||||
return dta;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
+6
-6
@@ -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.
|
||||
@@ -78,8 +78,8 @@ public class CaptureFunctionDataTypesAction extends DockingAction {
|
||||
public void actionPerformed(ActionContext context) {
|
||||
GTree gTree = (GTree) context.getContextObject();
|
||||
TreePath selectionPath = gTree.getSelectionPath();
|
||||
ArchiveNode node = (ArchiveNode) selectionPath.getLastPathComponent();
|
||||
if (!node.getArchive().isModifiable()) {
|
||||
DataTypeStoreNode node = (DataTypeStoreNode) selectionPath.getLastPathComponent();
|
||||
if (!node.getDataTypeStore().isChangeable()) {
|
||||
informNotModifiable(node);
|
||||
return;
|
||||
}
|
||||
@@ -89,7 +89,7 @@ public class CaptureFunctionDataTypesAction extends DockingAction {
|
||||
if (currentSelection == null || currentSelection.isEmpty()) {
|
||||
currentSelection = program.getMemory();
|
||||
}
|
||||
final DataTypeManager manager = node.getArchive().getDataTypeManager();
|
||||
final DataTypeManager manager = node.getDataTypeManager();
|
||||
final PluginTool tool = plugin.getTool();
|
||||
CaptureFunctionDataTypesCmd cmd =
|
||||
new CaptureFunctionDataTypesCmd(manager, currentSelection,
|
||||
@@ -105,7 +105,7 @@ public class CaptureFunctionDataTypesAction extends DockingAction {
|
||||
tool.executeBackgroundCommand(cmd, program);
|
||||
}
|
||||
|
||||
private void informNotModifiable(ArchiveNode node) {
|
||||
private void informNotModifiable(DataTypeStoreNode node) {
|
||||
String message;
|
||||
if (node instanceof ProgramArchiveNode) {
|
||||
message = "The program \"" + node.getName() + "\" isn't modifiable.";
|
||||
|
||||
+20
-46
@@ -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,8 +15,6 @@
|
||||
*/
|
||||
package ghidra.app.plugin.core.datamgr.actions;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import docking.ActionContext;
|
||||
@@ -26,13 +24,11 @@ import docking.widgets.OptionDialog;
|
||||
import docking.widgets.tree.GTree;
|
||||
import docking.widgets.tree.GTreeNode;
|
||||
import generic.theme.GThemeDefaults.Colors.Messages;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypesActionContext;
|
||||
import ghidra.app.plugin.core.datamgr.archive.*;
|
||||
import ghidra.app.plugin.core.datamgr.*;
|
||||
import ghidra.app.plugin.core.datamgr.tree.*;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.framework.store.LockException;
|
||||
import ghidra.program.model.data.StandAloneDataTypeManager;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.dtarchive.PersistentDataTypeArchive;
|
||||
import ghidra.program.model.dtarchive.ProjectDataTypeArchive;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.*;
|
||||
@@ -71,8 +67,7 @@ public class ClearArchiveArchitectureAction extends DockingAction {
|
||||
return false;
|
||||
}
|
||||
ArchiveNode archiveNode = (ArchiveNode) node;
|
||||
StandAloneDataTypeManager dtm =
|
||||
(StandAloneDataTypeManager) archiveNode.getArchive().getDataTypeManager();
|
||||
DataTypeManager dtm = archiveNode.getDataTypeManager();
|
||||
|
||||
return dtm.getProgramArchitectureSummary() != null && dtm.isUpdatable();
|
||||
}
|
||||
@@ -91,7 +86,7 @@ public class ClearArchiveArchitectureAction extends DockingAction {
|
||||
|
||||
if (node instanceof ProjectArchiveNode) {
|
||||
ProjectArchiveNode paNode = (ProjectArchiveNode) node;
|
||||
ProjectArchive pa = (ProjectArchive) paNode.getArchive();
|
||||
ProjectDataTypeArchive pa = paNode.getArchive();
|
||||
if (!pa.hasExclusiveAccess()) {
|
||||
Msg.showError(this, null, "Clear Program Architecture Failed",
|
||||
"Clearing program-architecture on Project Archive requires exclusive checkout.");
|
||||
@@ -100,10 +95,9 @@ public class ClearArchiveArchitectureAction extends DockingAction {
|
||||
}
|
||||
|
||||
ArchiveNode archiveNode = (ArchiveNode) node;
|
||||
StandAloneDataTypeManager dtm =
|
||||
(StandAloneDataTypeManager) archiveNode.getArchive().getDataTypeManager();
|
||||
PersistentDataTypeArchive archive = archiveNode.getArchive();
|
||||
|
||||
if (dtm.isChanged()) {
|
||||
if (archive.isChanged()) {
|
||||
if (OptionDialog.OPTION_ONE != OptionDialog.showOptionDialogWithCancelAsDefaultButton(
|
||||
null, "Save Archive Changes",
|
||||
"Archive has unsaved changes which must be saved before continuing." +
|
||||
@@ -111,20 +105,14 @@ public class ClearArchiveArchitectureAction extends DockingAction {
|
||||
"Save")) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
archiveNode.getArchive().save();
|
||||
}
|
||||
catch (IOException e) {
|
||||
Msg.showError(this, null, "Save Archive Failed",
|
||||
"Failed to save changes for Archive: " + dtm.getName() + "\n" + e.getMessage());
|
||||
return;
|
||||
}
|
||||
ArchiveManager archiveManager = plugin.getArchiveManager();
|
||||
archiveManager.save(archive);
|
||||
}
|
||||
|
||||
// TODO: Update message indicating that custom storage specification will not be
|
||||
// retained/permitted (once supported)
|
||||
String msg = "<html>Clear program-architecture for Archive?<BR><font color=\"" +
|
||||
Messages.NORMAL + "\">" + dtm.getPath() +
|
||||
Messages.NORMAL + "\">" + archive.getPath() +
|
||||
"</font><BR> <BR>Archive will revert to using default data organization.";
|
||||
int response = OptionDialog.showOptionDialogWithCancelAsDefaultButton(null,
|
||||
"Confirm Clearing Archive Architecture", msg, "Clear Architecture",
|
||||
@@ -133,25 +121,23 @@ public class ClearArchiveArchitectureAction extends DockingAction {
|
||||
return;
|
||||
}
|
||||
|
||||
new TaskLauncher(new ClearProgramArchitectureTask(archiveNode.getArchive(), dtm));
|
||||
new TaskLauncher(new ClearProgramArchitectureTask(archive));
|
||||
}
|
||||
|
||||
private class ClearProgramArchitectureTask extends Task {
|
||||
|
||||
private final Archive archive;
|
||||
private final StandAloneDataTypeManager dtm;
|
||||
private final PersistentDataTypeArchive archive;
|
||||
|
||||
public ClearProgramArchitectureTask(Archive archive, StandAloneDataTypeManager dtm) {
|
||||
public ClearProgramArchitectureTask(PersistentDataTypeArchive archive) {
|
||||
super("Clearing Program-Architecture for Archive", true, false, true, false);
|
||||
this.archive = archive;
|
||||
this.dtm = dtm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(TaskMonitor monitor) throws CancelledException {
|
||||
boolean success = false;
|
||||
try {
|
||||
dtm.clearProgramArchitecture(monitor);
|
||||
archive.clearProgramArchitecture(monitor);
|
||||
success = true;
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
@@ -159,25 +145,13 @@ public class ClearArchiveArchitectureAction extends DockingAction {
|
||||
}
|
||||
catch (Exception e) {
|
||||
Msg.showError(this, null, "Archive Update Failed",
|
||||
"Failed to clear program-architecture for Archive: " + dtm.getName() + "\n" +
|
||||
"Failed to clear program-architecture for Archive: " + archive.getName() +
|
||||
"\n" +
|
||||
e.getMessage());
|
||||
}
|
||||
finally {
|
||||
if (!success) {
|
||||
if (archive instanceof FileArchive) {
|
||||
try {
|
||||
((FileArchive) archive).releaseWriteLock();
|
||||
((FileArchive) archive).acquireWriteLock();
|
||||
}
|
||||
catch (LockException | IOException e) {
|
||||
archive.close();
|
||||
}
|
||||
}
|
||||
else { // if (archive instanceof ProjectArchive) {
|
||||
archive.close();
|
||||
DomainFile df = ((ProjectArchive) archive).getDomainFile();
|
||||
plugin.openArchive(df);
|
||||
}
|
||||
plugin.getArchiveManager().reopenArchive(archive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+38
-43
@@ -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.
|
||||
@@ -18,19 +18,15 @@ package ghidra.app.plugin.core.datamgr.actions;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.DockingAction;
|
||||
import docking.action.MenuData;
|
||||
import docking.widgets.tree.GTree;
|
||||
import docking.widgets.tree.GTreeNode;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypesActionContext;
|
||||
import ghidra.app.plugin.core.datamgr.archive.Archive;
|
||||
import ghidra.app.plugin.core.datamgr.archive.ArchiveUtils;
|
||||
import ghidra.app.plugin.core.datamgr.*;
|
||||
import ghidra.app.plugin.core.datamgr.editor.DataTypeEditorManager;
|
||||
import ghidra.app.plugin.core.datamgr.tree.*;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.dtarchive.PersistentDataTypeArchive;
|
||||
|
||||
public class CloseArchiveAction extends DockingAction {
|
||||
|
||||
@@ -42,28 +38,25 @@ public class CloseArchiveAction extends DockingAction {
|
||||
|
||||
setPopupMenuData(new MenuData(new String[] { "Close Archive" }, null, "File"));
|
||||
|
||||
setDescription("Closes a data type archive and removes it from the tool "
|
||||
+ "(does not affect program file associations).");
|
||||
setDescription("Closes a data type archive and removes it from the tool " +
|
||||
"(does not affect program file associations).");
|
||||
setEnabled(true);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
if (!(context instanceof DataTypesActionContext)) {
|
||||
if (!(context instanceof DataTypesActionContext dtac)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Object contextObject = context.getContextObject();
|
||||
GTree gtree = (GTree) contextObject;
|
||||
TreePath[] selectionPaths = gtree.getSelectionPaths();
|
||||
List<GTreeNode> selectedNodes = dtac.getSelectedNodes();
|
||||
|
||||
if (selectionPaths.length == 0) {
|
||||
if (selectedNodes.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (TreePath path : selectionPaths) {
|
||||
GTreeNode node = (GTreeNode) path.getLastPathComponent();
|
||||
for (GTreeNode node : selectedNodes) {
|
||||
if (!(node instanceof FileArchiveNode) && !(node instanceof InvalidArchiveNode) &&
|
||||
!(node instanceof ProjectArchiveNode)) {
|
||||
return false;
|
||||
@@ -74,38 +67,40 @@ public class CloseArchiveAction extends DockingAction {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
GTree gtree = (GTree) context.getContextObject();
|
||||
TreePath[] selectionPaths = gtree.getSelectionPaths();
|
||||
DataTypeEditorManager editorManager = plugin.getEditorManager();
|
||||
List<Archive> archives = new ArrayList<Archive>();
|
||||
for (TreePath path : selectionPaths) {
|
||||
Object pathComponent = path.getLastPathComponent();
|
||||
if (pathComponent instanceof InvalidArchiveNode) {
|
||||
InvalidArchiveNode invalidArchiveNode = (InvalidArchiveNode) pathComponent;
|
||||
Archive archive = invalidArchiveNode.getArchive();
|
||||
archive.close();
|
||||
continue;
|
||||
}
|
||||
DataTypesActionContext dtac = (DataTypesActionContext) context;
|
||||
ArchiveManager archiveManager = plugin.getArchiveManager();
|
||||
|
||||
Archive archive = null;
|
||||
Object node = path.getLastPathComponent();
|
||||
if (node instanceof ArchiveNode) {
|
||||
ArchiveNode archiveNode = (ArchiveNode) node;
|
||||
archive = archiveNode.getArchive();
|
||||
List<PersistentDataTypeArchive> archives = new ArrayList<>();
|
||||
List<GTreeNode> selectedNodes = dtac.getSelectedNodes();
|
||||
for (GTreeNode node : selectedNodes) {
|
||||
if (node instanceof InvalidArchiveNode invalidNode) {
|
||||
archiveManager.closeInvalidArchive(invalidNode.getInvalidArchive());
|
||||
}
|
||||
if (archive != null) {
|
||||
else if (node instanceof ArchiveNode archiveNode) {
|
||||
PersistentDataTypeArchive archive = archiveNode.getArchive();
|
||||
archives.add(archive);
|
||||
if (!editorManager.checkEditors(archive.getDataTypeManager(), true)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ArchiveUtils.canClose(archives, gtree)) {
|
||||
for (Archive archive : archives) {
|
||||
editorManager.dismissEditors(archive.getDataTypeManager());
|
||||
archive.close();
|
||||
if (checkEditors(archives)) {
|
||||
return;
|
||||
}
|
||||
for (PersistentDataTypeArchive archive : archives) {
|
||||
if (!plugin.resolveModifiedArchive(archive)) {
|
||||
return;
|
||||
}
|
||||
archiveManager.closeArchive(archive);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkEditors(List<PersistentDataTypeArchive> archives) {
|
||||
DataTypeEditorManager editorManager = plugin.getEditorManager();
|
||||
for (PersistentDataTypeArchive archive : archives) {
|
||||
DataTypeManager dtm = archive.getDataTypeManager();
|
||||
if (!editorManager.checkEditors(dtm, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+24
-54
@@ -1,13 +1,12 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* 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.
|
||||
@@ -16,31 +15,28 @@
|
||||
*/
|
||||
package ghidra.app.plugin.core.datamgr.actions;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypesActionContext;
|
||||
import ghidra.app.plugin.core.datamgr.archive.ArchiveUtils;
|
||||
import ghidra.app.plugin.core.datamgr.archive.FileArchive;
|
||||
import ghidra.app.plugin.core.datamgr.editor.DataTypeEditorManager;
|
||||
import ghidra.app.plugin.core.datamgr.tree.FileArchiveNode;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.DockingAction;
|
||||
import docking.action.MenuData;
|
||||
import docking.widgets.tree.*;
|
||||
import docking.widgets.tree.GTree;
|
||||
import docking.widgets.tree.GTreeNode;
|
||||
import ghidra.app.plugin.core.datamgr.*;
|
||||
import ghidra.app.plugin.core.datamgr.editor.DataTypeEditorManager;
|
||||
import ghidra.app.plugin.core.datamgr.tree.FileArchiveNode;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.dtarchive.FileDataTypeArchive;
|
||||
|
||||
public class UnlockArchiveAction extends DockingAction {
|
||||
public static final String ACTION_NAME = "Unlock Archive";
|
||||
/**
|
||||
* Action to set an archive to be read only
|
||||
*/
|
||||
public class CloseArchiveForEditingAction extends DockingAction {
|
||||
public static final String ACTION_NAME = "Close Archive For Editing";
|
||||
|
||||
private final DataTypeManagerPlugin plugin;
|
||||
|
||||
public UnlockArchiveAction(DataTypeManagerPlugin plugin) {
|
||||
public CloseArchiveForEditingAction(DataTypeManagerPlugin plugin) {
|
||||
super(ACTION_NAME, plugin.getName());
|
||||
this.plugin = plugin;
|
||||
|
||||
@@ -89,7 +85,7 @@ public class UnlockArchiveAction extends DockingAction {
|
||||
// only valid if all selected paths are file archives
|
||||
for (TreePath path : selectionPaths) {
|
||||
GTreeNode node = (GTreeNode) path.getLastPathComponent();
|
||||
if (hasWriteLock((FileArchiveNode) node)) {
|
||||
if (isModifiable((FileArchiveNode) node)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -103,9 +99,9 @@ public class UnlockArchiveAction extends DockingAction {
|
||||
return selectionPaths;
|
||||
}
|
||||
|
||||
private boolean hasWriteLock(FileArchiveNode fileArchiveNode) {
|
||||
FileArchive archive = (FileArchive) fileArchiveNode.getArchive();
|
||||
return archive.hasWriteLock();
|
||||
private boolean isModifiable(FileArchiveNode fileArchiveNode) {
|
||||
FileDataTypeArchive archive = fileArchiveNode.getArchive();
|
||||
return archive.isChangeable();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -113,48 +109,22 @@ public class UnlockArchiveAction extends DockingAction {
|
||||
GTree gTree = (GTree) context.getContextObject();
|
||||
|
||||
TreePath[] selectionPaths = gTree.getSelectionPaths();
|
||||
GTreeState treeState = gTree.getTreeState();
|
||||
|
||||
DataTypeEditorManager editorManager = plugin.getEditorManager();
|
||||
for (TreePath path : selectionPaths) {
|
||||
FileArchiveNode node = (FileArchiveNode) path.getLastPathComponent();
|
||||
FileArchive archive = (FileArchive) node.getArchive();
|
||||
if (!canReleaseLock(archive, gTree)) {
|
||||
continue;
|
||||
}
|
||||
FileDataTypeArchive archive = node.getArchive();
|
||||
|
||||
DataTypeManager dataTypeManager = archive.getDataTypeManager();
|
||||
if (!editorManager.checkEditors(dataTypeManager, true)) {
|
||||
return;
|
||||
}
|
||||
// check for changes and save if desired by user. If cancelled, get out.
|
||||
if (!ArchiveUtils.canClose(archive, gTree)) {
|
||||
if (!plugin.resolveModifiedArchive(archive)) {
|
||||
return;
|
||||
}
|
||||
editorManager.dismissEditors(dataTypeManager);
|
||||
|
||||
releaseLock(archive);
|
||||
}
|
||||
gTree.restoreTreeState(treeState);
|
||||
}
|
||||
|
||||
private boolean canReleaseLock(FileArchive archive, Component parent) {
|
||||
if (archive.getFile() == null) {
|
||||
Msg.showInfo(getClass(), parent,
|
||||
"Unsaved Archive", "Unsaved Archives must first be saved.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void releaseLock(FileArchive archive) {
|
||||
try {
|
||||
archive.releaseWriteLock();
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
Msg.showError(this, plugin.getProvider().getComponent(),
|
||||
"Unable to Release Write Lock",
|
||||
"Problem attempting to release write lock for archive: " + archive.getName() +
|
||||
"\nMessage: " + ioe.getMessage(), ioe);
|
||||
ArchiveManager archiveManager = plugin.getArchiveManager();
|
||||
archiveManager.reopenFileArchive(archive, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -71,7 +71,7 @@ public class CopyAction extends DockingAction {
|
||||
if (node instanceof ArchiveRootNode) {
|
||||
return true;
|
||||
}
|
||||
else if (node instanceof ArchiveNode) {
|
||||
else if (node instanceof DataTypeStoreNode) {
|
||||
return true;
|
||||
}
|
||||
else if (node instanceof CategoryNode) {
|
||||
|
||||
+6
-6
@@ -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.
|
||||
@@ -22,10 +22,10 @@ import docking.action.DockingAction;
|
||||
import docking.action.MenuData;
|
||||
import docking.widgets.OptionDialog;
|
||||
import docking.widgets.tree.GTreeNode;
|
||||
import ghidra.app.plugin.core.datamgr.ArchiveFileChooser;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.archive.Archive;
|
||||
import ghidra.app.plugin.core.datamgr.archive.ArchiveFileChooser;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeArchiveGTree;
|
||||
import ghidra.program.model.dtarchive.FileDataTypeArchive;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
public class CreateArchiveAction extends DockingAction {
|
||||
@@ -71,14 +71,14 @@ public class CreateArchiveAction extends DockingAction {
|
||||
Msg.trace(this, "\toverwriting file!");
|
||||
file.delete();
|
||||
}
|
||||
Archive newArchive = plugin.getDataTypeManagerHandler().createArchive(file);
|
||||
FileDataTypeArchive newArchive = plugin.getArchiveManager().createFileArchive(file);
|
||||
if (newArchive != null) {
|
||||
Msg.trace(this, "Created new archive: " + newArchive.getName());
|
||||
selectNewArchive(newArchive, gTree);
|
||||
}
|
||||
}
|
||||
|
||||
private void selectNewArchive(final Archive archive, final DataTypeArchiveGTree gTree) {
|
||||
private void selectNewArchive(FileDataTypeArchive archive, DataTypeArchiveGTree gTree) {
|
||||
GTreeNode rootNode = gTree.getModelRoot();
|
||||
gTree.setSelectedNodeByNamePath(new String[] { rootNode.getName(), archive.getName() });
|
||||
}
|
||||
|
||||
+6
-7
@@ -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.
|
||||
@@ -24,9 +24,9 @@ import docking.widgets.tree.GTree;
|
||||
import docking.widgets.tree.GTreeNode;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypesActionContext;
|
||||
import ghidra.app.plugin.core.datamgr.archive.Archive;
|
||||
import ghidra.app.plugin.core.datamgr.tree.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.Category;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.util.InvalidNameException;
|
||||
|
||||
public class CreateCategoryAction extends DockingAction {
|
||||
@@ -85,9 +85,8 @@ public class CreateCategoryAction extends DockingAction {
|
||||
TreePath[] selectionPaths = gtree.getSelectionPaths();
|
||||
final CategoryNode node = (CategoryNode) selectionPaths[0].getLastPathComponent();
|
||||
Category category = node.getCategory();
|
||||
ArchiveNode archiveNode = node.getArchiveNode();
|
||||
Archive archive = archiveNode.getArchive();
|
||||
DataTypeManager dataTypeManager = archive.getDataTypeManager();
|
||||
DataTypeStoreNode dataStoreNode = node.getArchiveNode();
|
||||
DataTypeManager dataTypeManager = dataStoreNode.getDataTypeManager();
|
||||
|
||||
String newNodeName = getUniqueCategoryName(category);
|
||||
String path = category.toString() + newNodeName;
|
||||
|
||||
+1
-1
@@ -96,7 +96,7 @@ public class CreatePointerAction extends DockingAction {
|
||||
return false;
|
||||
}
|
||||
|
||||
ArchiveNode archiveNode = node.getArchiveNode();
|
||||
DataTypeStoreNode archiveNode = node.getArchiveNode();
|
||||
if (archiveNode == null) {
|
||||
// this can happen as the tree is changing
|
||||
return false;
|
||||
|
||||
+6
-11
@@ -22,9 +22,8 @@ import docking.action.DockingAction;
|
||||
import docking.action.MenuData;
|
||||
import docking.widgets.tree.GTreeNode;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.archive.Archive;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeArchiveGTree;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.program.model.dtarchive.ProjectDataTypeArchive;
|
||||
|
||||
public class CreateProjectArchiveAction extends DockingAction {
|
||||
private final DataTypeManagerPlugin plugin;
|
||||
@@ -40,17 +39,13 @@ public class CreateProjectArchiveAction extends DockingAction {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
try {
|
||||
Archive newArchive = plugin.getDataTypeManagerHandler().createProjectArchive();
|
||||
DataTypeArchiveGTree gTree = plugin.getProvider().getGTree();
|
||||
selectNewArchive(newArchive, gTree);
|
||||
}
|
||||
catch (CancelledException ce) {
|
||||
plugin.getTool().setStatusInfo("Create project archive was cancelled.");
|
||||
}
|
||||
ProjectDataTypeArchive newArchive = plugin.getArchiveManager().createProjectArchive();
|
||||
DataTypeArchiveGTree gTree = plugin.getProvider().getGTree();
|
||||
selectNewArchive(newArchive, gTree);
|
||||
}
|
||||
|
||||
private void selectNewArchive(final Archive archive, final DataTypeArchiveGTree gTree) {
|
||||
private void selectNewArchive(ProjectDataTypeArchive archive,
|
||||
final DataTypeArchiveGTree gTree) {
|
||||
|
||||
GTreeNode root = gTree.getViewRoot();
|
||||
gTree.whenNodeIsReady(root, archive.getName(), archiveNode -> {
|
||||
|
||||
+3
-5
@@ -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.
|
||||
@@ -62,7 +62,7 @@ public class CreateTypeDefAction extends AbstractTypeDefAction {
|
||||
return false;
|
||||
}
|
||||
|
||||
ArchiveNode archiveNode = node.getArchiveNode();
|
||||
DataTypeStoreNode archiveNode = node.getArchiveNode();
|
||||
if (archiveNode == null) {
|
||||
// this can happen as the tree is changing
|
||||
return false;
|
||||
@@ -113,7 +113,6 @@ public class CreateTypeDefAction extends AbstractTypeDefAction {
|
||||
DataTypeNode dataTypeNode = (DataTypeNode) selectionPaths[0].getLastPathComponent();
|
||||
DataType dataType = dataTypeNode.getDataType();
|
||||
|
||||
|
||||
DerivativeDataTypeInfo info =
|
||||
new DerivativeDataTypeInfo(plugin, gTree, dataTypeNode, dataType);
|
||||
|
||||
@@ -132,5 +131,4 @@ public class CreateTypeDefAction extends AbstractTypeDefAction {
|
||||
gTree.startEditing(finalParentNode, newNodeName);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -28,7 +28,7 @@ import docking.widgets.tree.GTree;
|
||||
import docking.widgets.tree.GTreeNode;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypesActionContext;
|
||||
import ghidra.app.plugin.core.datamgr.tree.ArchiveNode;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeStoreNode;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeTreeNode;
|
||||
import ghidra.app.plugin.core.datamgr.util.DataTypeTreeDeleteTask;
|
||||
|
||||
@@ -84,7 +84,7 @@ public class DeleteAction extends DockingAction {
|
||||
private boolean containsUndeletableNodes(TreePath[] selectionPaths) {
|
||||
for (TreePath path : selectionPaths) {
|
||||
DataTypeTreeNode node = (DataTypeTreeNode) path.getLastPathComponent();
|
||||
if (!node.canDelete() || (node instanceof ArchiveNode)) {
|
||||
if (!node.canDelete() || (node instanceof DataTypeStoreNode)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
+10
-5
@@ -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.
|
||||
@@ -27,15 +27,18 @@ import docking.widgets.tree.GTree;
|
||||
import generic.theme.GThemeDefaults.Colors.Messages;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypesActionContext;
|
||||
import ghidra.app.plugin.core.datamgr.archive.FileArchive;
|
||||
import ghidra.app.plugin.core.datamgr.tree.*;
|
||||
import ghidra.program.model.dtarchive.FileDataTypeArchive;
|
||||
import ghidra.util.HTMLUtilities;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
public class DeleteArchiveAction extends DockingAction {
|
||||
|
||||
private DataTypeManagerPlugin plugin;
|
||||
|
||||
public DeleteArchiveAction(DataTypeManagerPlugin plugin) {
|
||||
super("Delete Archive", plugin.getName());
|
||||
this.plugin = plugin;
|
||||
|
||||
setPopupMenuData(new MenuData(new String[] { "Delete Archive" }, null, "File"));
|
||||
|
||||
@@ -61,7 +64,7 @@ public class DeleteArchiveAction extends DockingAction {
|
||||
if (!(node instanceof FileArchiveNode)) {
|
||||
return false;
|
||||
}
|
||||
return ((ArchiveNode) node).isModifiable();
|
||||
return ((DataTypeStoreNode) node).isModifiable();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -102,7 +105,9 @@ public class DeleteArchiveAction extends DockingAction {
|
||||
}
|
||||
|
||||
try {
|
||||
((FileArchive) node.getArchive()).delete();
|
||||
FileDataTypeArchive archive = node.getArchive();
|
||||
plugin.getArchiveManager().closeArchive(archive);
|
||||
archive.delete();
|
||||
}
|
||||
catch (IOException e1) {
|
||||
Msg.showError(this, null, "Error", "Error deleting data type archive.", e1);
|
||||
|
||||
+9
-9
@@ -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.
|
||||
@@ -19,9 +19,8 @@ import java.util.List;
|
||||
|
||||
import docking.widgets.tree.GTreeNode;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.archive.Archive;
|
||||
import ghidra.app.plugin.core.datamgr.tree.ArchiveNode;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeArchiveGTree;
|
||||
import ghidra.app.plugin.core.datamgr.tree.ProgramArchiveNode;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.SystemUtilities;
|
||||
import ghidra.util.exception.AssertException;
|
||||
@@ -76,16 +75,17 @@ class DerivativeDataTypeInfo {
|
||||
return parentNode;
|
||||
}
|
||||
|
||||
private ArchiveNode getProgramArchiveNode(DataTypeArchiveGTree tree) {
|
||||
private ProgramArchiveNode getProgramArchiveNode(DataTypeArchiveGTree tree) {
|
||||
|
||||
DataTypeManager manager = plugin.getProgramDataTypeManager();
|
||||
GTreeNode rootNode = tree.getModelRoot();
|
||||
List<GTreeNode> children = rootNode.getChildren();
|
||||
for (GTreeNode node : children) {
|
||||
ArchiveNode archiveNode = (ArchiveNode) node;
|
||||
Archive archive = archiveNode.getArchive();
|
||||
if (archive.getDataTypeManager() == manager) {
|
||||
return archiveNode;
|
||||
if (node instanceof ProgramArchiveNode programNode) {
|
||||
DataTypeManager dtm = programNode.getDataTypeManager();
|
||||
if (dtm == manager) {
|
||||
return programNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+7
-7
@@ -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.
|
||||
@@ -21,8 +21,8 @@ import docking.action.DockingAction;
|
||||
import docking.action.MenuData;
|
||||
import docking.widgets.filechooser.GhidraFileChooserMode;
|
||||
import docking.widgets.pathmanager.PathManager;
|
||||
import ghidra.app.plugin.core.datamgr.ArchiveManager;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.archive.DataTypeManagerHandler;
|
||||
import ghidra.framework.preferences.Preferences;
|
||||
import ghidra.util.HelpLocation;
|
||||
|
||||
@@ -61,8 +61,8 @@ public class EditArchivePathAction extends DockingAction {
|
||||
false, null);
|
||||
setHelpLocation(new HelpLocation("DataTypeManagerPlugin", "Edit_Archive_Paths_Dialog"));
|
||||
|
||||
pathManager.restoreFromPreferences(DataTypeManagerHandler.DATA_TYPE_ARCHIVE_PATH_KEY,
|
||||
null, DataTypeManagerHandler.DISABLED_DATA_TYPE_ARCHIVE_PATH_KEY);
|
||||
pathManager.restoreFromPreferences(ArchiveManager.DATA_TYPE_ARCHIVE_PATH_KEY,
|
||||
null, ArchiveManager.DISABLED_DATA_TYPE_ARCHIVE_PATH_KEY);
|
||||
addWorkPanel(pathManager.getComponent());
|
||||
addOKButton();
|
||||
addCancelButton();
|
||||
@@ -70,8 +70,8 @@ public class EditArchivePathAction extends DockingAction {
|
||||
|
||||
@Override
|
||||
protected void okCallback() {
|
||||
pathManager.saveToPreferences(DataTypeManagerHandler.DATA_TYPE_ARCHIVE_PATH_KEY,
|
||||
DataTypeManagerHandler.DISABLED_DATA_TYPE_ARCHIVE_PATH_KEY);
|
||||
pathManager.saveToPreferences(ArchiveManager.DATA_TYPE_ARCHIVE_PATH_KEY,
|
||||
ArchiveManager.DISABLED_DATA_TYPE_ARCHIVE_PATH_KEY);
|
||||
close();
|
||||
}
|
||||
|
||||
|
||||
+20
-25
@@ -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.
|
||||
@@ -26,15 +26,14 @@ import docking.widgets.filechooser.GhidraFileChooser;
|
||||
import docking.widgets.tree.GTree;
|
||||
import docking.widgets.tree.GTreeNode;
|
||||
import generic.jar.ResourceFile;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypesProvider;
|
||||
import ghidra.app.plugin.core.datamgr.archive.Archive;
|
||||
import ghidra.app.plugin.core.datamgr.archive.DataTypeManagerHandler;
|
||||
import ghidra.app.plugin.core.datamgr.*;
|
||||
import ghidra.app.plugin.core.datamgr.tree.ArchiveNode;
|
||||
import ghidra.app.services.Upgrade;
|
||||
import ghidra.framework.Application;
|
||||
import ghidra.framework.GenericRunInfo;
|
||||
import ghidra.framework.preferences.Preferences;
|
||||
import ghidra.program.model.data.FileDataTypeManager;
|
||||
import ghidra.program.model.dtarchive.PersistentDataTypeArchive;
|
||||
import ghidra.program.model.dtarchive.FileDataTypeArchive;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
public class OpenArchiveAction extends DockingAction {
|
||||
@@ -58,47 +57,43 @@ public class OpenArchiveAction extends DockingAction {
|
||||
GhidraFileChooser fileChooser = new GhidraFileChooser(tree);
|
||||
|
||||
File archiveDirectory = getArchiveDirectory();
|
||||
fileChooser.setFileFilter(FileDataTypeManager.GDT_FILEFILTER);
|
||||
fileChooser.setFileFilter(FileDataTypeArchive.GDT_FILEFILTER);
|
||||
fileChooser.setCurrentDirectory(archiveDirectory);
|
||||
fileChooser.setApproveButtonText("Open DataType Archive File");
|
||||
fileChooser.setApproveButtonToolTipText("Open DataType Archive File");
|
||||
|
||||
DataTypeManagerHandler manager = plugin.getDataTypeManagerHandler();
|
||||
ArchiveManager manager = plugin.getArchiveManager();
|
||||
File file = fileChooser.getSelectedFile();
|
||||
fileChooser.dispose();
|
||||
if (file == null) {
|
||||
return;
|
||||
}
|
||||
if (!file.getName().endsWith(FileDataTypeManager.EXTENSION)) {
|
||||
file = new File(file.getParent(), file.getName() + "." + FileDataTypeManager.EXTENSION);
|
||||
if (!file.getName().endsWith(FileDataTypeArchive.EXTENSION)) {
|
||||
file = new File(file.getParent(), file.getName() + "." + FileDataTypeArchive.EXTENSION);
|
||||
}
|
||||
|
||||
File lastOpenedDir = file.getParentFile();
|
||||
Preferences.setProperty(Preferences.LAST_OPENED_ARCHIVE_DIRECTORY,
|
||||
lastOpenedDir.getAbsolutePath());
|
||||
|
||||
try {
|
||||
Archive archive = manager.openArchive(file, false, true);
|
||||
ResourceFile resourceFile = new ResourceFile(file);
|
||||
PersistentDataTypeArchive archive =
|
||||
manager.openFileArchiveInTask(resourceFile, false, Upgrade.ASK, true);
|
||||
if (archive != null) {
|
||||
GTreeNode node = getNodeForArchive(tree, archive);
|
||||
if (node != null) {
|
||||
tree.setSelectedNode(node);
|
||||
}
|
||||
}
|
||||
catch (Throwable t) {
|
||||
DataTypeManagerHandler.handleArchiveFileException(plugin, new ResourceFile(file), t);
|
||||
tree.setSelectedNode(node);
|
||||
}
|
||||
}
|
||||
|
||||
private GTreeNode getNodeForArchive(GTree tree, Archive archive) {
|
||||
private GTreeNode getNodeForArchive(GTree tree, PersistentDataTypeArchive archive) {
|
||||
GTreeNode rootNode = tree.getModelRoot();
|
||||
List<GTreeNode> allChildren = rootNode.getChildren();
|
||||
for (GTreeNode node : allChildren) {
|
||||
ArchiveNode archiveNode = (ArchiveNode) node;
|
||||
if (archiveNode.getArchive() == archive) {
|
||||
return archiveNode;
|
||||
if (node instanceof ArchiveNode archiveNode) {
|
||||
if (archiveNode.getArchive() == archive) {
|
||||
return archiveNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
+22
-24
@@ -1,13 +1,12 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* 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.
|
||||
@@ -16,29 +15,27 @@
|
||||
*/
|
||||
package ghidra.app.plugin.core.datamgr.actions;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypesActionContext;
|
||||
import ghidra.app.plugin.core.datamgr.archive.ArchiveUtils;
|
||||
import ghidra.app.plugin.core.datamgr.archive.FileArchive;
|
||||
import ghidra.app.plugin.core.datamgr.tree.FileArchiveNode;
|
||||
import ghidra.program.model.data.FileDataTypeManager;
|
||||
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.DockingAction;
|
||||
import docking.action.MenuData;
|
||||
import docking.widgets.tree.*;
|
||||
import ghidra.app.plugin.core.datamgr.*;
|
||||
import ghidra.app.plugin.core.datamgr.tree.FileArchiveNode;
|
||||
import ghidra.program.model.dtarchive.FileDataTypeArchive;
|
||||
|
||||
public class LockArchiveAction extends DockingAction {
|
||||
public static final String ACTION_NAME = "Lock Archive";
|
||||
/**
|
||||
* Action to convert a read-only archive to be open for editing
|
||||
*/
|
||||
public class OpenArchiveForEditingAction extends DockingAction {
|
||||
public static final String ACTION_NAME = "Open Archive For Editing";
|
||||
private DataTypeManagerPlugin plugin;
|
||||
|
||||
public LockArchiveAction(DataTypeManagerPlugin plugin) {
|
||||
public OpenArchiveForEditingAction(DataTypeManagerPlugin plugin) {
|
||||
super(ACTION_NAME, plugin.getName());
|
||||
|
||||
// ACTIONS - auto generated
|
||||
this.plugin = plugin;
|
||||
setPopupMenuData(new MenuData(new String[] { "Open For Editing" }, null, "FileEdit"));
|
||||
|
||||
setEnabled(true);
|
||||
}
|
||||
|
||||
@@ -83,7 +80,7 @@ public class LockArchiveAction extends DockingAction {
|
||||
// only valid if all selected paths are file archives
|
||||
for (TreePath path : selectionPaths) {
|
||||
GTreeNode node = (GTreeNode) path.getLastPathComponent();
|
||||
if (canLock(node)) {
|
||||
if (canOpenForEditing(node)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -97,14 +94,14 @@ public class LockArchiveAction extends DockingAction {
|
||||
return selectionPaths;
|
||||
}
|
||||
|
||||
private boolean canLock(GTreeNode node) {
|
||||
private boolean canOpenForEditing(GTreeNode node) {
|
||||
FileArchiveNode fileNode = (FileArchiveNode) node;
|
||||
FileArchive archive = (FileArchive) fileNode.getArchive();
|
||||
FileDataTypeArchive archive = fileNode.getArchive();
|
||||
String fname = archive.getFile().getName();
|
||||
if (!fname.endsWith(FileDataTypeManager.SUFFIX)) {
|
||||
if (!fname.endsWith(FileDataTypeArchive.SUFFIX)) {
|
||||
return false;
|
||||
}
|
||||
return !archive.hasWriteLock();
|
||||
return !archive.isChangeable();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -116,9 +113,10 @@ public class LockArchiveAction extends DockingAction {
|
||||
|
||||
for (TreePath path : selectionPaths) {
|
||||
FileArchiveNode node = (FileArchiveNode) path.getLastPathComponent();
|
||||
FileArchive archive = (FileArchive) node.getArchive();
|
||||
if (!archive.hasWriteLock()) {
|
||||
ArchiveUtils.lockArchive(archive);
|
||||
FileDataTypeArchive archive = node.getArchive();
|
||||
if (!archive.isChangeable()) {
|
||||
ArchiveManager archiveManager = plugin.getArchiveManager();
|
||||
archiveManager.reopenFileArchive(archive, true);
|
||||
}
|
||||
}
|
||||
|
||||
+34
-5
@@ -1,13 +1,12 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* 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.
|
||||
@@ -16,11 +15,23 @@
|
||||
*/
|
||||
package ghidra.app.plugin.core.datamgr.actions;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import docking.ActionContext;
|
||||
import docking.action.DockingAction;
|
||||
import docking.action.MenuData;
|
||||
import ghidra.app.plugin.core.datamgr.ArchiveManager;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.services.Recover;
|
||||
import ghidra.app.services.Upgrade;
|
||||
import ghidra.app.util.HelpTopics;
|
||||
import ghidra.framework.main.OpenVersionedFileDialog;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.dtarchive.ProjectDataTypeArchive;
|
||||
import ghidra.util.HelpLocation;
|
||||
|
||||
/**
|
||||
* Action for opening file datatype archives.
|
||||
*/
|
||||
public class OpenProjectArchiveAction extends DockingAction {
|
||||
|
||||
private final DataTypeManagerPlugin plugin;
|
||||
@@ -38,7 +49,25 @@ public class OpenProjectArchiveAction extends DockingAction {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
plugin.openProjectDataTypeArchive();
|
||||
PluginTool tool = plugin.getTool();
|
||||
ArchiveManager archiveManager = plugin.getArchiveManager();
|
||||
OpenVersionedFileDialog<ProjectDataTypeArchive> dialog = new OpenVersionedFileDialog<>(tool,
|
||||
"Open Project Data Type Archive", ProjectDataTypeArchive.class);
|
||||
dialog.setHelpLocation(new HelpLocation(HelpTopics.PROGRAM, "Open_File_Dialog"));
|
||||
dialog.addOkActionListener(ev -> {
|
||||
DomainFile domainFile = dialog.getDomainFile();
|
||||
int version = dialog.getVersion();
|
||||
if (domainFile == null) {
|
||||
dialog.setStatusText("Please choose a Project Data Type Archive");
|
||||
}
|
||||
else {
|
||||
dialog.close();
|
||||
archiveManager.openProjectArchiveInTask(domainFile, version, Upgrade.ASK,
|
||||
Recover.ASK, true);
|
||||
}
|
||||
});
|
||||
|
||||
tool.showDialog(dialog);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -118,10 +118,10 @@ public class PasteAction extends DockingAction {
|
||||
}
|
||||
|
||||
// can't cut nodes from one archive and paste into another
|
||||
ArchiveNode destinationArchiveNode = destinationNode.getArchiveNode();
|
||||
DataTypeStoreNode destinationArchiveNode = destinationNode.getArchiveNode();
|
||||
for (GTreeNode cutNode : nodeList) {
|
||||
DataTypeTreeNode dataTypeTreeNode = (DataTypeTreeNode) cutNode;
|
||||
ArchiveNode archiveNode = dataTypeTreeNode.getArchiveNode();
|
||||
DataTypeStoreNode archiveNode = dataTypeTreeNode.getArchiveNode();
|
||||
if (!Objects.equals(archiveNode, destinationArchiveNode)) {
|
||||
return true; // is invalid
|
||||
}
|
||||
|
||||
+13
-32
@@ -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.
|
||||
@@ -18,13 +18,14 @@ package ghidra.app.plugin.core.datamgr.actions;
|
||||
import docking.ActionContext;
|
||||
import docking.action.DockingAction;
|
||||
import docking.action.MenuData;
|
||||
import generic.jar.ResourceFile;
|
||||
import generic.util.Path;
|
||||
import ghidra.app.plugin.core.datamgr.ArchiveManager;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.archive.DataTypeManagerHandler;
|
||||
import ghidra.app.services.Recover;
|
||||
import ghidra.app.services.Upgrade;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.task.Task;
|
||||
import ghidra.util.task.TaskLauncher;
|
||||
|
||||
/**
|
||||
* Class for action to open a recently opened data type archive.
|
||||
@@ -41,7 +42,7 @@ public class RecentlyOpenedArchiveAction extends DockingAction {
|
||||
String menuGroup) {
|
||||
super(menuGroup + ": \"" + archivePath + "\"", plugin.getName(), false);
|
||||
this.plugin = plugin;
|
||||
String[] projectPathname = DataTypeManagerHandler.parseProjectPathname(archivePath);
|
||||
String[] projectPathname = DataTypeManagerPlugin.parseProjectPathname(archivePath);
|
||||
if (projectPathname == null) {
|
||||
this.projectName = null;
|
||||
this.archivePath = archivePath;
|
||||
@@ -64,7 +65,7 @@ public class RecentlyOpenedArchiveAction extends DockingAction {
|
||||
return getTypeInfoRelativeName(filepath);
|
||||
}
|
||||
|
||||
String[] projectPathname = DataTypeManagerHandler.parseProjectPathname(filepath);
|
||||
String[] projectPathname = DataTypeManagerPlugin.parseProjectPathname(filepath);
|
||||
if (projectPathname == null) {
|
||||
return filepath;
|
||||
}
|
||||
@@ -111,16 +112,17 @@ public class RecentlyOpenedArchiveAction extends DockingAction {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
ArchiveManager archiveManager = plugin.getArchiveManager();
|
||||
if (projectName == null) {
|
||||
DataTypeManagerHandler archiveManager = plugin.getDataTypeManagerHandler();
|
||||
Path path = new Path(archivePath);
|
||||
OpenArchiveTask task = new OpenArchiveTask(archiveManager, path);
|
||||
new TaskLauncher(task, plugin.getProvider().getComponent());
|
||||
ResourceFile file = path.getPath();
|
||||
archiveManager.openFileArchiveInTask(file, false, Upgrade.ASK, true);
|
||||
}
|
||||
else {
|
||||
DomainFile df = plugin.getProjectArchiveFile(projectName, archivePath);
|
||||
if (df != null) {
|
||||
plugin.openArchive(df);
|
||||
archiveManager.openProjectArchiveInTask(df, DomainFile.DEFAULT_VERSION, Upgrade.ASK,
|
||||
Recover.ASK, true);
|
||||
}
|
||||
else {
|
||||
Msg.showError(this, null, "Project Archive Open Error",
|
||||
@@ -129,25 +131,4 @@ public class RecentlyOpenedArchiveAction extends DockingAction {
|
||||
}
|
||||
}
|
||||
|
||||
private class OpenArchiveTask extends Task {
|
||||
private final Path taskArchivePath;
|
||||
private final DataTypeManagerHandler archiveManager;
|
||||
|
||||
OpenArchiveTask(DataTypeManagerHandler archiveManager, Path archivePath) {
|
||||
super("Opening Archive " + archivePath.getPath().getName(), false, false, true);
|
||||
this.archiveManager = archiveManager;
|
||||
this.taskArchivePath = archivePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(ghidra.util.task.TaskMonitor monitor) {
|
||||
try {
|
||||
archiveManager.openArchive(taskArchivePath.getPath(), false, true);
|
||||
}
|
||||
catch (Exception e) {
|
||||
DataTypeManagerHandler.handleArchiveFileException(plugin, taskArchivePath.getPath(),
|
||||
e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+18
-9
@@ -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,8 +15,11 @@
|
||||
*/
|
||||
package ghidra.app.plugin.core.datamgr.actions;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.program.model.data.StandAloneDataTypeManager;
|
||||
import ghidra.program.model.dtarchive.PersistentDataTypeArchive;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
public class RedoArchiveTransactionAction extends AbstractUndoRedoArchiveTransactionAction {
|
||||
|
||||
@@ -28,18 +31,24 @@ public class RedoArchiveTransactionAction extends AbstractUndoRedoArchiveTransac
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canExecute(StandAloneDataTypeManager dtm) {
|
||||
return dtm.canRedo();
|
||||
protected boolean canExecute(PersistentDataTypeArchive dta) {
|
||||
return dta.canRedo();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getNextName(StandAloneDataTypeManager dtm) {
|
||||
return dtm.getRedoName();
|
||||
protected String getNextName(PersistentDataTypeArchive dta) {
|
||||
return dta.getRedoName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void execute(StandAloneDataTypeManager dtm) {
|
||||
dtm.redo();
|
||||
protected void execute(PersistentDataTypeArchive dta) {
|
||||
try {
|
||||
dta.redo();
|
||||
}
|
||||
catch (IOException e) {
|
||||
Msg.showError(this, null, "Archive Redo Failed",
|
||||
"Failed to redo last transaction: " + dta.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+11
-8
@@ -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.
|
||||
@@ -24,12 +24,15 @@ import docking.widgets.OptionDialog;
|
||||
import docking.widgets.tree.GTree;
|
||||
import docking.widgets.tree.GTreeNode;
|
||||
import generic.theme.GThemeDefaults.Colors.Messages;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypesActionContext;
|
||||
import ghidra.app.plugin.core.datamgr.archive.*;
|
||||
import ghidra.app.plugin.core.datamgr.*;
|
||||
import ghidra.app.plugin.core.datamgr.archive.InvalidArchive;
|
||||
import ghidra.app.plugin.core.datamgr.tree.InvalidArchiveNode;
|
||||
import ghidra.util.HTMLUtilities;
|
||||
|
||||
/**
|
||||
* Removes a SourceArchive from a program and removes any datatype associations to that source
|
||||
* archive.
|
||||
*/
|
||||
public class RemoveInvalidArchiveFromProgramAction extends DockingAction {
|
||||
|
||||
private DataTypeManagerPlugin plugin;
|
||||
@@ -86,8 +89,8 @@ public class RemoveInvalidArchiveFromProgramAction extends DockingAction {
|
||||
return;
|
||||
}
|
||||
|
||||
Archive archive = invalidArchiveNode.getArchive();
|
||||
DataTypeManagerHandler dataTypeManagerHandler = plugin.getDataTypeManagerHandler();
|
||||
dataTypeManagerHandler.removeInvalidArchive((InvalidFileArchive) archive);
|
||||
InvalidArchive archive = invalidArchiveNode.getInvalidArchive();
|
||||
ArchiveManager archiveManager = plugin.getArchiveManager();
|
||||
archiveManager.removeInvalidArchiveFromProgram(archive);
|
||||
}
|
||||
}
|
||||
|
||||
+7
-3
@@ -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.
|
||||
@@ -26,6 +26,9 @@ import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypesActionContext;
|
||||
import ghidra.app.plugin.core.datamgr.tree.*;
|
||||
|
||||
/**
|
||||
* Renames objects in the datatypes tree if they support being renamed
|
||||
*/
|
||||
public class RenameAction extends DockingAction {
|
||||
|
||||
public RenameAction(DataTypeManagerPlugin plugin) {
|
||||
@@ -37,7 +40,8 @@ public class RenameAction extends DockingAction {
|
||||
@Override
|
||||
public boolean isAddToPopup(ActionContext context) {
|
||||
GTreeNode node = getSelectedNode(context);
|
||||
if (node == null || node instanceof ArchiveRootNode || node instanceof ArchiveNode) {
|
||||
if (node == null || node instanceof ArchiveRootNode || node instanceof DataTypeStoreNode ||
|
||||
node instanceof InvalidArchiveNode) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
+9
-11
@@ -24,15 +24,13 @@ import docking.action.MenuData;
|
||||
import docking.widgets.label.GLabel;
|
||||
import docking.widgets.tree.GTree;
|
||||
import docking.widgets.tree.GTreeNode;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypesActionContext;
|
||||
import ghidra.app.plugin.core.datamgr.archive.Archive;
|
||||
import ghidra.app.plugin.core.datamgr.archive.DataTypeManagerHandler;
|
||||
import ghidra.app.plugin.core.datamgr.*;
|
||||
import ghidra.app.plugin.core.datamgr.tree.*;
|
||||
import ghidra.app.util.datatype.DataTypeSelectionDialog;
|
||||
import ghidra.app.util.datatype.DataTypeSelectionEditor;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.dtarchive.DataTypeStore;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.data.DataTypeParser.AllowedDataTypes;
|
||||
import ghidra.util.layout.VerticalLayout;
|
||||
@@ -134,14 +132,14 @@ public class ReplaceDataTypeAction extends DockingAction {
|
||||
return; // cancelled
|
||||
}
|
||||
|
||||
DataTypeManagerHandler dtmHandler = plugin.getDataTypeManagerHandler();
|
||||
ArchiveManager archiveManager = plugin.getArchiveManager();
|
||||
DataTypeManager newDtm = newDt.getDataTypeManager();
|
||||
Archive sourceArchive = dtmHandler.getArchive(newDtm);
|
||||
Archive destinationArchive = findArchive(node);
|
||||
DataTypeStore sourceStore = newDtm.getDataStore();
|
||||
DataTypeStore destinationStore = findArchive(node);
|
||||
|
||||
DataType oldDt = ((DataTypeNode) node).getDataType();
|
||||
DataTypeManager dtm = oldDt.getDataTypeManager();
|
||||
if (sourceArchive != destinationArchive) {
|
||||
if (sourceStore != destinationStore) {
|
||||
oldDt = oldDt.clone(oldDt.getDataTypeManager());
|
||||
}
|
||||
|
||||
@@ -158,10 +156,10 @@ public class ReplaceDataTypeAction extends DockingAction {
|
||||
}
|
||||
}
|
||||
|
||||
private Archive findArchive(GTreeNode node) {
|
||||
private DataTypeStore findArchive(GTreeNode node) {
|
||||
while (node != null) {
|
||||
if (node instanceof ArchiveNode) {
|
||||
return ((ArchiveNode) node).getArchive();
|
||||
if (node instanceof DataTypeStoreNode archiveNode) {
|
||||
return archiveNode.getDataTypeStore();
|
||||
}
|
||||
node = node.getParent();
|
||||
}
|
||||
|
||||
+15
-48
@@ -1,13 +1,12 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* 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.
|
||||
@@ -16,14 +15,6 @@
|
||||
*/
|
||||
package ghidra.app.plugin.core.datamgr.actions;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypesActionContext;
|
||||
import ghidra.app.plugin.core.datamgr.archive.*;
|
||||
import ghidra.app.plugin.core.datamgr.tree.*;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import docking.ActionContext;
|
||||
@@ -31,7 +22,13 @@ import docking.action.DockingAction;
|
||||
import docking.action.MenuData;
|
||||
import docking.widgets.tree.GTree;
|
||||
import docking.widgets.tree.GTreeNode;
|
||||
import ghidra.app.plugin.core.datamgr.*;
|
||||
import ghidra.app.plugin.core.datamgr.tree.*;
|
||||
import ghidra.program.model.dtarchive.PersistentDataTypeArchive;
|
||||
|
||||
/**
|
||||
* Actions for saving datatype archives that support saving.
|
||||
*/
|
||||
public class SaveArchiveAction extends DockingAction {
|
||||
private final DataTypeManagerPlugin plugin;
|
||||
|
||||
@@ -39,7 +36,6 @@ public class SaveArchiveAction extends DockingAction {
|
||||
super("Save", plugin.getName());
|
||||
this.plugin = plugin;
|
||||
|
||||
// ACTIONS - auto generated
|
||||
setPopupMenuData(new MenuData(new String[] { "Save Archive" }, null, "File"));
|
||||
|
||||
setEnabled(true);
|
||||
@@ -97,10 +93,9 @@ public class SaveArchiveAction extends DockingAction {
|
||||
}
|
||||
|
||||
private boolean canSave(GTreeNode node) {
|
||||
if ((node instanceof FileArchiveNode) || (node instanceof ProjectArchiveNode)) {
|
||||
ArchiveNode archiveNode = (ArchiveNode) node;
|
||||
Archive archive = archiveNode.getArchive();
|
||||
return archive.isChanged() && archive.isSavable();
|
||||
if (node instanceof ArchiveNode archiveNode) {
|
||||
PersistentDataTypeArchive archive = archiveNode.getArchive();
|
||||
return archive.isChanged();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -112,41 +107,13 @@ public class SaveArchiveAction extends DockingAction {
|
||||
TreePath[] selectionPaths = gTree.getSelectionPaths();
|
||||
for (TreePath path : selectionPaths) {
|
||||
Object node = path.getLastPathComponent();
|
||||
if (node instanceof ArchiveNode) {
|
||||
ArchiveNode archiveNode = (ArchiveNode) node;
|
||||
Archive archive = archiveNode.getArchive();
|
||||
if (node instanceof ArchiveNode archiveNode) {
|
||||
PersistentDataTypeArchive archive = archiveNode.getArchive();
|
||||
if (archive.isChanged()) {
|
||||
saveArchive(archive);
|
||||
ArchiveManager archiveManager = plugin.getArchiveManager();
|
||||
archiveManager.save(archive);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void saveFileArchive(FileArchive archive) {
|
||||
try {
|
||||
archive.save();
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
Msg.showError(this, plugin.getProvider().getComponent(), "Unable to Save File",
|
||||
"Unexpected exception attempting to save archive: " + archive, ioe);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveProjectArchive(ProjectArchive archive) {
|
||||
DataTypeManagerHandler dtmHandler = plugin.getDataTypeManagerHandler();
|
||||
dtmHandler.save(archive.getDomainObject());
|
||||
}
|
||||
|
||||
private void saveArchive(Archive archive) {
|
||||
if (archive instanceof ProjectArchive) {
|
||||
saveProjectArchive((ProjectArchive) archive);
|
||||
}
|
||||
else if (archive instanceof FileArchive) {
|
||||
saveFileArchive((FileArchive) archive);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException(archive.getName() +
|
||||
" must be Project or File archive.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+18
-34
@@ -1,13 +1,12 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* 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.
|
||||
@@ -16,15 +15,6 @@
|
||||
*/
|
||||
package ghidra.app.plugin.core.datamgr.actions;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypesActionContext;
|
||||
import ghidra.app.plugin.core.datamgr.archive.*;
|
||||
import ghidra.app.plugin.core.datamgr.tree.*;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.DuplicateFileException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import docking.ActionContext;
|
||||
@@ -32,11 +22,17 @@ import docking.action.DockingAction;
|
||||
import docking.action.MenuData;
|
||||
import docking.widgets.tree.GTree;
|
||||
import docking.widgets.tree.GTreeNode;
|
||||
import ghidra.app.plugin.core.datamgr.*;
|
||||
import ghidra.app.plugin.core.datamgr.tree.ArchiveNode;
|
||||
import ghidra.program.model.dtarchive.*;
|
||||
|
||||
public class SaveAsAction extends DockingAction {
|
||||
/**
|
||||
* Action for saving a ProjectDataTypeArchive or a FileDataTypeArchive to a new storage location.
|
||||
*/
|
||||
public class SaveArchiveAsAction extends DockingAction {
|
||||
private DataTypeManagerPlugin plugin;
|
||||
|
||||
public SaveAsAction(DataTypeManagerPlugin plugin) {
|
||||
public SaveArchiveAsAction(DataTypeManagerPlugin plugin) {
|
||||
super("Save As", plugin.getName());
|
||||
|
||||
this.plugin = plugin;
|
||||
@@ -58,7 +54,7 @@ public class SaveAsAction extends DockingAction {
|
||||
}
|
||||
|
||||
GTreeNode node = (GTreeNode) selectionPaths[0].getLastPathComponent();
|
||||
if ((node instanceof FileArchiveNode) || (node instanceof ProjectArchiveNode)) {
|
||||
if (node instanceof ArchiveNode) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -68,29 +64,17 @@ public class SaveAsAction extends DockingAction {
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
GTree gtree = (GTree) context.getContextObject();
|
||||
|
||||
ArchiveManager archiveManager = plugin.getArchiveManager();
|
||||
TreePath[] selectionPaths = gtree.getSelectionPaths();
|
||||
ArchiveNode node = (ArchiveNode) selectionPaths[0].getLastPathComponent();
|
||||
Archive archive = node.getArchive();
|
||||
PersistentDataTypeArchive archive = node.getArchive();
|
||||
|
||||
try {
|
||||
if (node instanceof FileArchiveNode) {
|
||||
FileArchive fa = (FileArchive) archive;
|
||||
ArchiveUtils.saveAs(gtree, fa);
|
||||
plugin.addRecentlyOpenedArchiveFile(fa.getFile());
|
||||
}
|
||||
else if (node instanceof ProjectArchiveNode) {
|
||||
ProjectArchive pa = (ProjectArchive) archive;
|
||||
pa.saveAs(gtree);
|
||||
plugin.addRecentlyOpenedProjectArchive(pa);
|
||||
}
|
||||
archiveManager.saveAs(archive);
|
||||
if (archive instanceof FileDataTypeArchive fa) {
|
||||
plugin.addRecentlyOpenedArchiveFile(fa.getFile());
|
||||
}
|
||||
catch (DuplicateFileException de) {
|
||||
Msg.showError(this, gtree, "Unable to Save File", "Archive already exists: " + archive);
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
Msg.showError(this, gtree, "Unable to Save File",
|
||||
"Unexpected exception attempting to save archive: " + archive, ioe);
|
||||
else if (archive instanceof ProjectDataTypeArchive pa) {
|
||||
plugin.addRecentlyOpenedProjectArchive(pa);
|
||||
}
|
||||
}
|
||||
}
|
||||
+42
-69
File diff suppressed because it is too large
Load Diff
+18
-9
@@ -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,8 +15,11 @@
|
||||
*/
|
||||
package ghidra.app.plugin.core.datamgr.actions;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.program.model.data.StandAloneDataTypeManager;
|
||||
import ghidra.program.model.dtarchive.PersistentDataTypeArchive;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
public class UndoArchiveTransactionAction extends AbstractUndoRedoArchiveTransactionAction {
|
||||
|
||||
@@ -28,18 +31,24 @@ public class UndoArchiveTransactionAction extends AbstractUndoRedoArchiveTransac
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canExecute(StandAloneDataTypeManager dtm) {
|
||||
return dtm.canUndo();
|
||||
protected boolean canExecute(PersistentDataTypeArchive dta) {
|
||||
return dta.canUndo();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getNextName(StandAloneDataTypeManager dtm) {
|
||||
return dtm.getUndoName();
|
||||
protected String getNextName(PersistentDataTypeArchive dta) {
|
||||
return dta.getUndoName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void execute(StandAloneDataTypeManager dtm) {
|
||||
dtm.undo();
|
||||
protected void execute(PersistentDataTypeArchive dta) {
|
||||
try {
|
||||
dta.undo();
|
||||
}
|
||||
catch (IOException e) {
|
||||
Msg.showError(this, null, "Archive Undo Failed",
|
||||
"Failed to undo last transaction: " + dta.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-96
@@ -1,96 +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.datamgr.actions;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypesActionContext;
|
||||
import ghidra.app.plugin.core.datamgr.archive.DataTypeManagerHandler;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.SourceArchive;
|
||||
import ghidra.util.HelpLocation;
|
||||
import docking.ActionContext;
|
||||
import docking.action.DockingAction;
|
||||
import docking.action.MenuData;
|
||||
|
||||
public class UpdateSourceArchiveNamesAction extends DockingAction {
|
||||
|
||||
public static final String NAME = "Update Source Archive Names";
|
||||
|
||||
private final DataTypeManagerPlugin plugin;
|
||||
private final DataTypeManager dtm;
|
||||
|
||||
public UpdateSourceArchiveNamesAction(DataTypeManagerPlugin plugin, DataTypeManager dtm) {
|
||||
super(NAME, plugin.getName());
|
||||
this.plugin = plugin;
|
||||
this.dtm = dtm;
|
||||
|
||||
setPopupMenuData(new MenuData(new String[] { NAME }));
|
||||
setHelpLocation(new HelpLocation(plugin.getName(), "Update_Source_Archive_Names"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
if (!(context instanceof DataTypesActionContext)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DataTypeManagerHandler handler = plugin.getDataTypeManagerHandler();
|
||||
|
||||
// TODO: nothing can be done to protect against dtm being closed
|
||||
// Must ensure that dtm closing must trigger associated Archive
|
||||
// close and cleanup from tree
|
||||
|
||||
for (SourceArchive archive : dtm.getSourceArchives()) {
|
||||
DataTypeManager archiveDtm = handler.getDataTypeManager(archive);
|
||||
if (archiveDtm == null) {
|
||||
continue;
|
||||
}
|
||||
String archiveName = archiveDtm.getName();
|
||||
if (!archive.getName().equals(archiveName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
|
||||
DataTypeManagerHandler handler = plugin.getDataTypeManagerHandler();
|
||||
|
||||
// TODO: nothing can be done to protect against dtm being closed
|
||||
// Must ensure that dtm closing must trigger associated Archive
|
||||
// close and cleanup from tree
|
||||
|
||||
int txId = dtm.startTransaction(NAME);
|
||||
try {
|
||||
for (SourceArchive archive : dtm.getSourceArchives()) {
|
||||
DataTypeManager archiveDtm = handler.getDataTypeManager(archive);
|
||||
if (archiveDtm == null) {
|
||||
continue;
|
||||
}
|
||||
String archiveName = archiveDtm.getName();
|
||||
if (!archive.getName().equals(archiveName)) {
|
||||
archive.setName(archiveName);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
dtm.endTransaction(txId, true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+34
-32
@@ -34,13 +34,15 @@ import docking.widgets.list.GComboBoxCellRenderer;
|
||||
import docking.widgets.tree.GTreeNode;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypesActionContext;
|
||||
import ghidra.app.plugin.core.datamgr.archive.*;
|
||||
import ghidra.app.plugin.core.datamgr.tree.ArchiveNode;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeNode;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeStoreNode;
|
||||
import ghidra.app.plugin.core.datamgr.util.DataTypeTreeCopyMoveTask;
|
||||
import ghidra.app.plugin.core.datamgr.util.DataTypeTreeCopyMoveTask.ActionType;
|
||||
import ghidra.app.plugin.core.datamgr.util.DataTypeUtils;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.dtarchive.PersistentDataTypeArchive;
|
||||
import ghidra.program.model.dtarchive.DataTypeStore;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.layout.PairLayout;
|
||||
import ghidra.util.task.TaskLauncher;
|
||||
@@ -70,12 +72,12 @@ public class AssociateDataTypeAction extends DockingAction {
|
||||
if (dtNodes.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
Archive singleDTArchive = getSingleDTArchive(dtNodes);
|
||||
DataTypeStore singleDataTypeStore = getSingleDataTypeStore(dtNodes);
|
||||
|
||||
// NOTE: We only support program-to-archive since other cases become rather complicated
|
||||
// when considering dependencies that must get copied and how their associations shuold be
|
||||
// when considering dependencies that must get copied and how their associations should be
|
||||
// handled.
|
||||
return singleDTArchive instanceof ProgramArchive;
|
||||
return singleDataTypeStore instanceof Program;
|
||||
}
|
||||
|
||||
private List<GTreeNode> getDataTypeNodes(DataTypesActionContext ctx) {
|
||||
@@ -91,11 +93,11 @@ public class AssociateDataTypeAction extends DockingAction {
|
||||
return !nodes.isEmpty();
|
||||
}
|
||||
|
||||
private Archive getSingleDTArchive(List<GTreeNode> nodes) {
|
||||
private DataTypeStore getSingleDataTypeStore(List<GTreeNode> nodes) {
|
||||
|
||||
Archive dtArchive = null;
|
||||
DataTypeStore dtArchive = null;
|
||||
for (GTreeNode node : nodes) {
|
||||
Archive archive = findArchive(node);
|
||||
DataTypeStore archive = findDataStore(node);
|
||||
if (dtArchive == null) {
|
||||
dtArchive = archive;
|
||||
continue;
|
||||
@@ -108,23 +110,21 @@ public class AssociateDataTypeAction extends DockingAction {
|
||||
return dtArchive;
|
||||
}
|
||||
|
||||
private static Archive findArchive(GTreeNode node) {
|
||||
private static DataTypeStore findDataStore(GTreeNode node) {
|
||||
while (node != null) {
|
||||
if (node instanceof ArchiveNode) {
|
||||
return ((ArchiveNode) node).getArchive();
|
||||
if (node instanceof DataTypeStoreNode archiveNode) {
|
||||
return archiveNode.getDataTypeStore();
|
||||
}
|
||||
node = node.getParent();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<Archive> getDestinationArchives(Archive excludedArchive) {
|
||||
private List<PersistentDataTypeArchive> getDestinationArchives(DataTypeStore excluded) {
|
||||
|
||||
List<Archive> archives = plugin.getAllArchives();
|
||||
List<Archive> destArchives = archives.stream()
|
||||
.filter(a -> !(a instanceof ProgramArchive))
|
||||
.filter(a -> !(a instanceof BuiltInArchive))
|
||||
.filter(a -> !a.equals(excludedArchive))
|
||||
List<PersistentDataTypeArchive> archives = plugin.getArchiveManager().getOpenArchives();
|
||||
List<PersistentDataTypeArchive> destArchives = archives.stream()
|
||||
.filter(a -> !a.equals(excluded))
|
||||
.sorted((a1, a2) -> a1.getName().compareToIgnoreCase(a2.getName()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
@@ -138,14 +138,14 @@ public class AssociateDataTypeAction extends DockingAction {
|
||||
if (dtNodes.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Archive dtArchive = getSingleDTArchive(dtNodes);
|
||||
if (dtArchive == null) {
|
||||
DataTypeStore dtStore = getSingleDataTypeStore(dtNodes);
|
||||
if (dtStore == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dtArchive.isModifiable()) {
|
||||
if (!dtStore.isChangeable()) {
|
||||
DataTypeUtils.showUnmodifiableArchiveErrorMessage(context.getSourceComponent(),
|
||||
"Disassociate Failed", dtArchive.getDataTypeManager());
|
||||
"Disassociate Failed", dtStore.getDataTypeManager());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ public class AssociateDataTypeAction extends DockingAction {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Archive> archives = getDestinationArchives(dtArchive);
|
||||
List<PersistentDataTypeArchive> archives = getDestinationArchives(dtStore);
|
||||
if (archives.isEmpty()) {
|
||||
Msg.showInfo(this, getProviderComponent(), "No Source Archives Open",
|
||||
"No source archives open. Please open the desired source archive.");
|
||||
@@ -169,7 +169,7 @@ public class AssociateDataTypeAction extends DockingAction {
|
||||
return;
|
||||
}
|
||||
|
||||
Archive destinationArchive = dialog.getArchive();
|
||||
PersistentDataTypeArchive destinationArchive = dialog.getArchive();
|
||||
Category destinationCategory = dialog.getCategory();
|
||||
|
||||
DataTypeTreeCopyMoveTask task =
|
||||
@@ -186,15 +186,15 @@ public class AssociateDataTypeAction extends DockingAction {
|
||||
private class ChooseArchiveDialog extends DialogComponentProvider {
|
||||
|
||||
private Category category;
|
||||
private Archive archive;
|
||||
private PersistentDataTypeArchive archive;
|
||||
|
||||
// default to true to handle the case the user presses Escape or presses the x button
|
||||
private boolean isCancelled = true;
|
||||
|
||||
private GhidraComboBox<Archive> archivesBox = new GhidraComboBox<>();
|
||||
private GhidraComboBox<PersistentDataTypeArchive> archivesBox = new GhidraComboBox<>();
|
||||
private JTextField categoryField = new JTextField(20);
|
||||
|
||||
ChooseArchiveDialog(List<Archive> archives) {
|
||||
ChooseArchiveDialog(List<PersistentDataTypeArchive> archives) {
|
||||
super("Choose New Source Archive", true);
|
||||
|
||||
addWorkPanel(buildWorkPanel());
|
||||
@@ -211,12 +211,14 @@ public class AssociateDataTypeAction extends DockingAction {
|
||||
archivesBox.setRenderer(new GComboBoxCellRenderer<>() {
|
||||
|
||||
@Override
|
||||
public Component getListCellRendererComponent(JList<? extends Archive> list,
|
||||
Archive value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
public Component getListCellRendererComponent(
|
||||
JList<? extends PersistentDataTypeArchive> list,
|
||||
PersistentDataTypeArchive value, int index, boolean isSelected,
|
||||
boolean cellHasFocus) {
|
||||
|
||||
JLabel renderer = (JLabel) super.getListCellRendererComponent(list, value,
|
||||
index, isSelected, cellHasFocus);
|
||||
Archive a = value;
|
||||
PersistentDataTypeArchive a = value;
|
||||
renderer.setText(a.getName());
|
||||
return renderer;
|
||||
}
|
||||
@@ -244,13 +246,13 @@ public class AssociateDataTypeAction extends DockingAction {
|
||||
|
||||
clearStatusText();
|
||||
|
||||
archive = (Archive) archivesBox.getSelectedItem();
|
||||
archive = archivesBox.getSelectedItem();
|
||||
if (archive == null) {
|
||||
setStatusText("Please choose an archive");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!archive.isModifiable()) {
|
||||
if (!archive.isChangeable()) {
|
||||
setStatusText(
|
||||
"Archive is not modifiable. You must first open this archive for edit.");
|
||||
return;
|
||||
@@ -318,7 +320,7 @@ public class AssociateDataTypeAction extends DockingAction {
|
||||
DockingWindowManager.showDialog(parent, this);
|
||||
}
|
||||
|
||||
Archive getArchive() {
|
||||
PersistentDataTypeArchive getArchive() {
|
||||
return archive;
|
||||
}
|
||||
|
||||
|
||||
+6
-7
@@ -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.
|
||||
@@ -19,8 +19,7 @@ import java.util.List;
|
||||
|
||||
import docking.action.MenuData;
|
||||
import ghidra.app.plugin.core.datamgr.*;
|
||||
import ghidra.app.plugin.core.datamgr.archive.DataTypeManagerHandler;
|
||||
import ghidra.app.plugin.core.datamgr.tree.ArchiveNode;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeStoreNode;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.SourceArchive;
|
||||
import ghidra.util.HelpLocation;
|
||||
@@ -29,11 +28,11 @@ public class CommitAction extends SyncAction {
|
||||
|
||||
public static final String MENU_NAME = "Commit Data Types To";
|
||||
|
||||
public CommitAction(DataTypeManagerPlugin plugin, DataTypeManagerHandler dataTypeManagerHandler,
|
||||
DataTypeManager dtm, ArchiveNode archiveNode, SourceArchive sourceArchive,
|
||||
public CommitAction(DataTypeManagerPlugin plugin, ArchiveManager archiveManager,
|
||||
DataTypeManager dtm, DataTypeStoreNode archiveNode, SourceArchive sourceArchive,
|
||||
boolean isEnabled) {
|
||||
|
||||
super("Commit Changes To Archive", plugin, dataTypeManagerHandler, dtm, archiveNode,
|
||||
super("Commit Changes To Archive", plugin, archiveManager, dtm, archiveNode,
|
||||
sourceArchive, isEnabled);
|
||||
setPopupMenuData(new MenuData(new String[] { MENU_NAME, sourceArchive.getName() }));
|
||||
setHelpLocation(new HelpLocation(plugin.getName(), getHelpTopic()));
|
||||
|
||||
+9
-9
@@ -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.
|
||||
@@ -26,7 +26,6 @@ import docking.widgets.tree.GTree;
|
||||
import docking.widgets.tree.GTreeNode;
|
||||
import generic.theme.GIcon;
|
||||
import ghidra.app.plugin.core.datamgr.*;
|
||||
import ghidra.app.plugin.core.datamgr.archive.DataTypeManagerHandler;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeNode;
|
||||
import ghidra.app.plugin.core.datamgr.util.DataTypeUtils;
|
||||
import ghidra.program.model.data.*;
|
||||
@@ -70,8 +69,8 @@ public class CommitSingleDataTypeAction extends DockingAction {
|
||||
}
|
||||
DataTypeNode dataTypeNode = (DataTypeNode) node;
|
||||
DataType dataType = dataTypeNode.getDataType();
|
||||
DataTypeManagerHandler handler = plugin.getDataTypeManagerHandler();
|
||||
DataTypeSyncState syncStatus = DataTypeSynchronizer.getSyncStatus(handler, dataType);
|
||||
ArchiveManager archiveManager = plugin.getArchiveManager();
|
||||
DataTypeSyncState syncStatus = DataTypeSynchronizer.getSyncStatus(archiveManager, dataType);
|
||||
|
||||
switch (syncStatus) {
|
||||
case UNKNOWN:
|
||||
@@ -101,8 +100,8 @@ public class CommitSingleDataTypeAction extends DockingAction {
|
||||
DataTypeNode dataTypeNode = (DataTypeNode) node;
|
||||
DataType dataType = dataTypeNode.getDataType();
|
||||
DataTypeManager dtm = dataType.getDataTypeManager();
|
||||
DataTypeManagerHandler handler = plugin.getDataTypeManagerHandler();
|
||||
DataTypeSyncState syncStatus = DataTypeSynchronizer.getSyncStatus(handler, dataType);
|
||||
ArchiveManager archiveManager = plugin.getArchiveManager();
|
||||
DataTypeSyncState syncStatus = DataTypeSynchronizer.getSyncStatus(archiveManager, dataType);
|
||||
|
||||
if (syncStatus == DataTypeSyncState.CONFLICT) {
|
||||
int result = OptionDialog.showOptionDialog(gTree, "Lose Changes in Archive?",
|
||||
@@ -115,7 +114,7 @@ public class CommitSingleDataTypeAction extends DockingAction {
|
||||
}
|
||||
SourceArchive sourceArchive = dataType.getSourceArchive();
|
||||
DataTypeManager sourceDTM =
|
||||
plugin.getDataTypeManagerHandler().getDataTypeManager(sourceArchive);
|
||||
plugin.getArchiveManager().getDataTypeManager(sourceArchive);
|
||||
if (sourceDTM == null) {
|
||||
Msg.showInfo(getClass(), gTree, "Commit Failed",
|
||||
"Source Archive not open: " + sourceArchive.getName());
|
||||
@@ -133,7 +132,8 @@ public class CommitSingleDataTypeAction extends DockingAction {
|
||||
plugin.commit(dataType);
|
||||
|
||||
// Source archive data type manager was already checked for null above.
|
||||
DataTypeSynchronizer synchronizer = new DataTypeSynchronizer(handler, dtm, sourceArchive);
|
||||
DataTypeSynchronizer synchronizer =
|
||||
new DataTypeSynchronizer(archiveManager, dtm, sourceArchive);
|
||||
synchronizer.reSyncOutOfSyncInTimeOnlyDataTypes();
|
||||
}
|
||||
}
|
||||
|
||||
+10
-10
@@ -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.
|
||||
@@ -25,8 +25,7 @@ import docking.action.MenuData;
|
||||
import docking.widgets.OptionDialog;
|
||||
import docking.widgets.tree.GTreeState;
|
||||
import ghidra.app.plugin.core.datamgr.*;
|
||||
import ghidra.app.plugin.core.datamgr.archive.DataTypeManagerHandler;
|
||||
import ghidra.app.plugin.core.datamgr.tree.ArchiveNode;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeStoreNode;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeArchiveGTree;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.SourceArchive;
|
||||
@@ -39,15 +38,15 @@ public class DisassociateAction extends DockingAction {
|
||||
|
||||
private final SourceArchive sourceArchive;
|
||||
private final DataTypeManager dtm;
|
||||
private final DataTypeManagerHandler handler;
|
||||
private final ArchiveManager achiveManager;
|
||||
private final DataTypeManagerPlugin plugin;
|
||||
private final ArchiveNode archiveNode;
|
||||
private final DataTypeStoreNode archiveNode;
|
||||
|
||||
public DisassociateAction(DataTypeManagerPlugin plugin, DataTypeManagerHandler handler,
|
||||
DataTypeManager dtm, ArchiveNode archiveNode, SourceArchive sourceArchive) {
|
||||
public DisassociateAction(DataTypeManagerPlugin plugin, ArchiveManager archiveManager,
|
||||
DataTypeManager dtm, DataTypeStoreNode archiveNode, SourceArchive sourceArchive) {
|
||||
super("Disassociate Archive", plugin.getName());
|
||||
this.plugin = plugin;
|
||||
this.handler = handler;
|
||||
this.achiveManager = archiveManager;
|
||||
this.dtm = dtm;
|
||||
this.archiveNode = archiveNode;
|
||||
this.sourceArchive = sourceArchive;
|
||||
@@ -70,7 +69,8 @@ public class DisassociateAction extends DockingAction {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
DataTypeSynchronizer synchronizer = new DataTypeSynchronizer(handler, dtm, sourceArchive);
|
||||
DataTypeSynchronizer synchronizer =
|
||||
new DataTypeSynchronizer(achiveManager, dtm, sourceArchive);
|
||||
|
||||
if (!dtm.isUpdatable()) {
|
||||
showRequiresArchiveOpenMessage(dtm.getName());
|
||||
|
||||
+5
-5
@@ -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.
|
||||
@@ -29,7 +29,6 @@ import docking.widgets.OptionDialog;
|
||||
import docking.widgets.tree.*;
|
||||
import ghidra.app.plugin.core.datamgr.*;
|
||||
import ghidra.app.plugin.core.datamgr.archive.BuiltInSourceArchive;
|
||||
import ghidra.app.plugin.core.datamgr.archive.DataTypeManagerHandler;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeArchiveGTree;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeNode;
|
||||
import ghidra.app.plugin.core.datamgr.util.DataTypeUtils;
|
||||
@@ -217,11 +216,12 @@ public class DisassociateDataTypeAction extends DockingAction {
|
||||
|
||||
monitor.setMessage("Disassociating types from " + dtm.getName());
|
||||
monitor.initialize(dataTypes.size());
|
||||
DataTypeManagerHandler handler = plugin.getDataTypeManagerHandler();
|
||||
ArchiveManager archiveManager = plugin.getArchiveManager();
|
||||
for (Entry<SourceArchive, List<DataType>> entry : sourceToTypes.entrySet()) {
|
||||
SourceArchive source = entry.getKey();
|
||||
List<DataType> types = entry.getValue();
|
||||
DataTypeSynchronizer synchronizer = new DataTypeSynchronizer(handler, dtm, source);
|
||||
DataTypeSynchronizer synchronizer =
|
||||
new DataTypeSynchronizer(archiveManager, dtm, source);
|
||||
disassociate(synchronizer, dtm, types, monitor);
|
||||
}
|
||||
}
|
||||
|
||||
+7
-9
@@ -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.
|
||||
@@ -18,10 +18,8 @@ package ghidra.app.plugin.core.datamgr.actions.associate;
|
||||
import java.util.List;
|
||||
|
||||
import docking.action.MenuData;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeSyncInfo;
|
||||
import ghidra.app.plugin.core.datamgr.archive.DataTypeManagerHandler;
|
||||
import ghidra.app.plugin.core.datamgr.tree.ArchiveNode;
|
||||
import ghidra.app.plugin.core.datamgr.*;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeStoreNode;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.SourceArchive;
|
||||
import ghidra.util.HelpLocation;
|
||||
@@ -30,11 +28,11 @@ public class RevertAction extends SyncAction {
|
||||
|
||||
public static final String MENU_NAME = "Revert Data Types From";
|
||||
|
||||
public RevertAction(DataTypeManagerPlugin plugin, DataTypeManagerHandler dataTypeManagerHandler,
|
||||
DataTypeManager dtm, ArchiveNode archiveNode, SourceArchive sourceArchive,
|
||||
public RevertAction(DataTypeManagerPlugin plugin, ArchiveManager archiveManager,
|
||||
DataTypeManager dtm, DataTypeStoreNode archiveNode, SourceArchive sourceArchive,
|
||||
boolean isEnabled) {
|
||||
|
||||
super("Revert Data Type Changes", plugin, dataTypeManagerHandler, dtm, archiveNode,
|
||||
super("Revert Data Type Changes", plugin, archiveManager, dtm, archiveNode,
|
||||
sourceArchive, isEnabled);
|
||||
setPopupMenuData(new MenuData(new String[] { MENU_NAME, sourceArchive.getName() }));
|
||||
setHelpLocation(new HelpLocation(plugin.getName(), getHelpTopic()));
|
||||
|
||||
+8
-8
@@ -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,7 +23,6 @@ import docking.action.MenuData;
|
||||
import docking.widgets.tree.GTree;
|
||||
import docking.widgets.tree.GTreeNode;
|
||||
import ghidra.app.plugin.core.datamgr.*;
|
||||
import ghidra.app.plugin.core.datamgr.archive.DataTypeManagerHandler;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeNode;
|
||||
import ghidra.app.plugin.core.datamgr.util.DataTypeUtils;
|
||||
import ghidra.program.model.data.*;
|
||||
@@ -60,8 +59,8 @@ public class RevertDataTypeAction extends DockingAction {
|
||||
|
||||
DataTypeNode dataTypeNode = (DataTypeNode) node;
|
||||
DataType dataType = dataTypeNode.getDataType();
|
||||
DataTypeManagerHandler handler = plugin.getDataTypeManagerHandler();
|
||||
DataTypeSyncState syncStatus = DataTypeSynchronizer.getSyncStatus(handler, dataType);
|
||||
ArchiveManager archiveManager = plugin.getArchiveManager();
|
||||
DataTypeSyncState syncStatus = DataTypeSynchronizer.getSyncStatus(archiveManager, dataType);
|
||||
|
||||
switch (syncStatus) {
|
||||
case UNKNOWN:
|
||||
@@ -90,13 +89,13 @@ public class RevertDataTypeAction extends DockingAction {
|
||||
DataTypeNode dataTypeNode = (DataTypeNode) node;
|
||||
DataType dataType = dataTypeNode.getDataType();
|
||||
DataTypeManager dtm = dataType.getDataTypeManager();
|
||||
DataTypeManagerHandler handler = plugin.getDataTypeManagerHandler();
|
||||
ArchiveManager archiveManager = plugin.getArchiveManager();
|
||||
SourceArchive sourceArchive = dataType.getSourceArchive();
|
||||
if (!dtm.isUpdatable()) {
|
||||
DataTypeUtils.showUnmodifiableArchiveErrorMessage(gTree, "Revert Failed", dtm);
|
||||
return;
|
||||
}
|
||||
DataTypeManager sourceDTM = handler.getDataTypeManager(sourceArchive);
|
||||
DataTypeManager sourceDTM = archiveManager.getDataTypeManager(sourceArchive);
|
||||
if (sourceDTM == null) {
|
||||
Msg.showInfo(getClass(), gTree, "Revert Failed",
|
||||
"Source Archive not open: " + sourceArchive.getName());
|
||||
@@ -105,7 +104,8 @@ public class RevertDataTypeAction extends DockingAction {
|
||||
plugin.revert(dataType);
|
||||
|
||||
// Source archive data type manager was already checked for null above.
|
||||
DataTypeSynchronizer synchronizer = new DataTypeSynchronizer(handler, dtm, sourceArchive);
|
||||
DataTypeSynchronizer synchronizer =
|
||||
new DataTypeSynchronizer(archiveManager, dtm, sourceArchive);
|
||||
synchronizer.reSyncOutOfSyncInTimeOnlyDataTypes();
|
||||
}
|
||||
|
||||
|
||||
+9
-9
@@ -24,8 +24,7 @@ import docking.action.DockingAction;
|
||||
import docking.widgets.OptionDialog;
|
||||
import docking.widgets.tree.GTreeState;
|
||||
import ghidra.app.plugin.core.datamgr.*;
|
||||
import ghidra.app.plugin.core.datamgr.archive.DataTypeManagerHandler;
|
||||
import ghidra.app.plugin.core.datamgr.tree.ArchiveNode;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeStoreNode;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeArchiveGTree;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.SourceArchive;
|
||||
@@ -38,16 +37,16 @@ public abstract class SyncAction extends DockingAction implements Comparable<Syn
|
||||
|
||||
private final SourceArchive sourceArchive;
|
||||
private final DataTypeManager dtm;
|
||||
private final DataTypeManagerHandler handler;
|
||||
private final ArchiveManager archiveManager;
|
||||
private final DataTypeManagerPlugin plugin;
|
||||
private final ArchiveNode archiveNode;
|
||||
private final DataTypeStoreNode archiveNode;
|
||||
|
||||
SyncAction(String name, DataTypeManagerPlugin plugin, DataTypeManagerHandler handler,
|
||||
DataTypeManager dtm, ArchiveNode archiveNode, SourceArchive sourceArchive,
|
||||
SyncAction(String name, DataTypeManagerPlugin plugin, ArchiveManager archiveManager,
|
||||
DataTypeManager dtm, DataTypeStoreNode archiveNode, SourceArchive sourceArchive,
|
||||
boolean isEnabled) {
|
||||
super(name, plugin.getName());
|
||||
this.plugin = plugin;
|
||||
this.handler = handler;
|
||||
this.archiveManager = archiveManager;
|
||||
this.dtm = dtm;
|
||||
this.archiveNode = archiveNode;
|
||||
this.sourceArchive = sourceArchive;
|
||||
@@ -89,7 +88,7 @@ public abstract class SyncAction extends DockingAction implements Comparable<Syn
|
||||
return;
|
||||
}
|
||||
|
||||
DataTypeManager sourceDTM = handler.getDataTypeManager(sourceArchive);
|
||||
DataTypeManager sourceDTM = archiveManager.getDataTypeManager(sourceArchive);
|
||||
if (sourceDTM == null) {
|
||||
Msg.showInfo(getClass(), plugin.getTool().getToolFrame(),
|
||||
"Cannot Access Source Archive",
|
||||
@@ -102,7 +101,8 @@ public abstract class SyncAction extends DockingAction implements Comparable<Syn
|
||||
return;
|
||||
}
|
||||
|
||||
DataTypeSynchronizer synchronizer = new DataTypeSynchronizer(handler, dtm, sourceArchive);
|
||||
DataTypeSynchronizer synchronizer =
|
||||
new DataTypeSynchronizer(archiveManager, dtm, sourceArchive);
|
||||
|
||||
//@formatter:off
|
||||
TaskBuilder.withTask(new SyncTask(synchronizer))
|
||||
|
||||
+7
-8
@@ -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.
|
||||
@@ -20,8 +20,7 @@ import docking.action.DockingAction;
|
||||
import docking.action.MenuData;
|
||||
import docking.widgets.tree.GTreeState;
|
||||
import ghidra.app.plugin.core.datamgr.*;
|
||||
import ghidra.app.plugin.core.datamgr.archive.DataTypeManagerHandler;
|
||||
import ghidra.app.plugin.core.datamgr.tree.ArchiveNode;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeStoreNode;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeArchiveGTree;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.SourceArchive;
|
||||
@@ -31,16 +30,16 @@ import ghidra.util.Msg;
|
||||
public class SyncRefreshAction extends DockingAction {
|
||||
|
||||
public static final String MENU_NAME = "Refresh Sync Indicators For";
|
||||
private DataTypeManagerHandler dataTypeManagerHandler;
|
||||
private ArchiveManager dataTypeManagerHandler;
|
||||
private final DataTypeManager dtm;
|
||||
private final SourceArchive sourceArchive;
|
||||
private final DataTypeManagerPlugin plugin;
|
||||
private DataTypeSynchronizer synchronizer;
|
||||
private ArchiveNode archiveNode;
|
||||
private DataTypeStoreNode archiveNode;
|
||||
|
||||
public SyncRefreshAction(DataTypeManagerPlugin plugin,
|
||||
DataTypeManagerHandler dataTypeManagerHandler, DataTypeManager dtm,
|
||||
ArchiveNode archiveNode, SourceArchive sourceArchive, boolean isEnabled) {
|
||||
ArchiveManager dataTypeManagerHandler, DataTypeManager dtm,
|
||||
DataTypeStoreNode archiveNode, SourceArchive sourceArchive, boolean isEnabled) {
|
||||
|
||||
super("Refresh The Sync Indicators For Archive", plugin.getName());
|
||||
this.plugin = plugin;
|
||||
|
||||
+5
-6
@@ -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.
|
||||
@@ -19,8 +19,7 @@ import java.util.List;
|
||||
|
||||
import docking.action.MenuData;
|
||||
import ghidra.app.plugin.core.datamgr.*;
|
||||
import ghidra.app.plugin.core.datamgr.archive.DataTypeManagerHandler;
|
||||
import ghidra.app.plugin.core.datamgr.tree.ArchiveNode;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeStoreNode;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.SourceArchive;
|
||||
import ghidra.util.HelpLocation;
|
||||
@@ -28,8 +27,8 @@ import ghidra.util.HelpLocation;
|
||||
public class UpdateAction extends SyncAction {
|
||||
public static final String MENU_NAME = "Update Data Types From";
|
||||
|
||||
public UpdateAction(DataTypeManagerPlugin plugin, DataTypeManagerHandler dataTypeManagerHandler,
|
||||
DataTypeManager dtm, ArchiveNode archiveNode, SourceArchive sourceArchive,
|
||||
public UpdateAction(DataTypeManagerPlugin plugin, ArchiveManager dataTypeManagerHandler,
|
||||
DataTypeManager dtm, DataTypeStoreNode archiveNode, SourceArchive sourceArchive,
|
||||
boolean isEnabled) {
|
||||
|
||||
super("Update Data Types From Archive", plugin, dataTypeManagerHandler, dtm, archiveNode,
|
||||
|
||||
+8
-9
@@ -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.
|
||||
@@ -26,7 +26,6 @@ import docking.widgets.tree.GTree;
|
||||
import docking.widgets.tree.GTreeNode;
|
||||
import generic.theme.GIcon;
|
||||
import ghidra.app.plugin.core.datamgr.*;
|
||||
import ghidra.app.plugin.core.datamgr.archive.DataTypeManagerHandler;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeNode;
|
||||
import ghidra.app.plugin.core.datamgr.util.DataTypeUtils;
|
||||
import ghidra.program.model.data.*;
|
||||
@@ -68,8 +67,8 @@ public class UpdateSingleDataTypeAction extends DockingAction {
|
||||
}
|
||||
DataTypeNode dataTypeNode = (DataTypeNode) node;
|
||||
DataType dataType = dataTypeNode.getDataType();
|
||||
DataTypeManagerHandler handler = plugin.getDataTypeManagerHandler();
|
||||
DataTypeSyncState syncStatus = DataTypeSynchronizer.getSyncStatus(handler, dataType);
|
||||
ArchiveManager archiveManager = plugin.getArchiveManager();
|
||||
DataTypeSyncState syncStatus = DataTypeSynchronizer.getSyncStatus(archiveManager, dataType);
|
||||
|
||||
switch (syncStatus) {
|
||||
case UNKNOWN:
|
||||
@@ -101,9 +100,9 @@ public class UpdateSingleDataTypeAction extends DockingAction {
|
||||
DataTypeNode dataTypeNode = (DataTypeNode) node;
|
||||
DataType dataType = dataTypeNode.getDataType();
|
||||
DataTypeManager dtm = dataType.getDataTypeManager();
|
||||
DataTypeManagerHandler handler = plugin.getDataTypeManagerHandler();
|
||||
ArchiveManager archiveManager = plugin.getArchiveManager();
|
||||
SourceArchive sourceArchive = dataType.getSourceArchive();
|
||||
DataTypeSyncState syncStatus = DataTypeSynchronizer.getSyncStatus(handler, dataType);
|
||||
DataTypeSyncState syncStatus = DataTypeSynchronizer.getSyncStatus(archiveManager, dataType);
|
||||
if (syncStatus == DataTypeSyncState.CONFLICT) {
|
||||
int result = OptionDialog.showOptionDialog(gTree, "Lose Local Changes?",
|
||||
"This data type has local changes that will be\n" +
|
||||
@@ -119,10 +118,10 @@ public class UpdateSingleDataTypeAction extends DockingAction {
|
||||
}
|
||||
plugin.update(dataType);
|
||||
|
||||
DataTypeManager sourceDTM = handler.getDataTypeManager(sourceArchive);
|
||||
DataTypeManager sourceDTM = archiveManager.getDataTypeManager(sourceArchive);
|
||||
if (sourceDTM != null) {
|
||||
DataTypeSynchronizer synchronizer =
|
||||
new DataTypeSynchronizer(handler, dtm, sourceArchive);
|
||||
new DataTypeSynchronizer(archiveManager, dtm, sourceArchive);
|
||||
synchronizer.reSyncOutOfSyncInTimeOnlyDataTypes();
|
||||
}
|
||||
}
|
||||
|
||||
-84
@@ -1,84 +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.datamgr.archive;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
||||
import ghidra.app.merge.DataTypeManagerOwner;
|
||||
import ghidra.util.exception.DuplicateFileException;
|
||||
|
||||
/**
|
||||
* This is an interface for data type archives.
|
||||
*/
|
||||
public interface Archive extends DataTypeManagerOwner, Comparable<Archive> {
|
||||
|
||||
/**
|
||||
* Gets the name for this data type archive.
|
||||
* This is the name to be presented to the user for this archive.
|
||||
* @return the name or null if closed
|
||||
*/
|
||||
public String getName();
|
||||
|
||||
/**
|
||||
* Closes this archive. Some archives cannot be closed (i.e. BuiltIn data type archive.)
|
||||
*/
|
||||
public void close();
|
||||
|
||||
/**
|
||||
* Determines if this is a modifiable archive like a program archive, a non-versioned
|
||||
* project archive, a checked out versioned project archive or a locked (open for editing)
|
||||
* file archive.
|
||||
* @return true if it is a modifiable archive and can have its contents changed.
|
||||
*/
|
||||
public boolean isModifiable();
|
||||
|
||||
/**
|
||||
* Determines if this archive can be saved. Some archives cannot be saved.
|
||||
* @return true if the archive can be saved.
|
||||
*/
|
||||
public boolean isSavable();
|
||||
|
||||
/**
|
||||
* Determines if this archive has been changed. Some archives cannot be changed.
|
||||
* @return true if the archive contains unsaved changes.
|
||||
*/
|
||||
public boolean isChanged();
|
||||
|
||||
/**
|
||||
* Saves this archive. Some archives cannot be saved.
|
||||
* @throws DuplicateFileException if there is an exception saving
|
||||
* @throws IOException if there is an exception saving
|
||||
*/
|
||||
public void save() throws DuplicateFileException, IOException;
|
||||
|
||||
/**
|
||||
* Saves this archive to a newly named file.
|
||||
* @param component the parent component the any dialogs shown
|
||||
* @throws IOException if there is an exception saving
|
||||
*/
|
||||
public void saveAs(Component component) throws IOException;
|
||||
|
||||
/**
|
||||
* Gets the icon representing this archive.
|
||||
* @param expanded true means show the icon for this archive as an expanded (open) tree node.
|
||||
* false indicates the node is closed.
|
||||
* @return the archive's icon.
|
||||
*/
|
||||
public Icon getIcon(boolean expanded);
|
||||
}
|
||||
-44
@@ -1,44 +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.datamgr.archive;
|
||||
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
|
||||
public interface ArchiveManagerListener {
|
||||
/**
|
||||
* Called when a new Archive is opened.
|
||||
* @param archive the new archive that was opened.
|
||||
*/
|
||||
void archiveOpened(Archive archive);
|
||||
|
||||
/**
|
||||
* Called when an archive is closed.
|
||||
* @param archive the archive that was closed.
|
||||
*/
|
||||
void archiveClosed(Archive archive);
|
||||
|
||||
/**
|
||||
* Called when the edited state of the archive has changed, for example, when an archive
|
||||
* has had a data type or category added or removed.
|
||||
*/
|
||||
public void archiveStateChanged(Archive archive);
|
||||
|
||||
/**
|
||||
* Called when the {@link DataTypeManager} of the archive has changed. This can happen when
|
||||
* an archive is locked or unlocked.
|
||||
*/
|
||||
public void archiveDataTypeManagerChanged(Archive archive);
|
||||
}
|
||||
-215
File diff suppressed because it is too large
Load Diff
+215
File diff suppressed because it is too large
Load Diff
-89
@@ -1,89 +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.datamgr.archive;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
||||
import generic.theme.GIcon;
|
||||
import ghidra.program.model.data.BuiltInDataTypeManager;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.util.exception.DuplicateFileException;
|
||||
|
||||
public class BuiltInArchive implements Archive {
|
||||
|
||||
private static Icon CLOSED_ICON = new GIcon("icon.plugin.datatypes.archive.built.in.closed");
|
||||
private static Icon OPEN_ICON = new GIcon("icon.plugin.datatypes.archive.built.in.open");
|
||||
private DataTypeManagerHandler archiveManager;
|
||||
private BuiltInDataTypeManager dataTypeManager;
|
||||
|
||||
BuiltInArchive(DataTypeManagerHandler archiveManager, BuiltInDataTypeManager dataTypeManager) {
|
||||
this.archiveManager = archiveManager;
|
||||
this.dataTypeManager = dataTypeManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeManager getDataTypeManager() {
|
||||
return dataTypeManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return dataTypeManager.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Archive archive) {
|
||||
return -1; // Built-ins are always at the top
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isModifiable() {
|
||||
return false; // Can't change the data types that are in Built-Ins.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
// Not allowed to close the Built In Data Type Manager.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChanged() {
|
||||
return false; // Can't change.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSavable() {
|
||||
return false; // Can't save.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save() throws DuplicateFileException, IOException {
|
||||
// Can't "Save" so do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAs(Component component) throws IOException {
|
||||
// Can't "Save As" so do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getIcon(boolean expanded) {
|
||||
return expanded ? OPEN_ICON : CLOSED_ICON;
|
||||
}
|
||||
}
|
||||
-1810
File diff suppressed because it is too large
Load Diff
-236
File diff suppressed because it is too large
Load Diff
-330
File diff suppressed because it is too large
Load Diff
+9
-10
@@ -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,14 +15,13 @@
|
||||
*/
|
||||
package ghidra.app.plugin.core.datamgr.archive;
|
||||
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.program.model.data.ArchiveType;
|
||||
import ghidra.util.UniversalID;
|
||||
|
||||
public interface DomainFileArchive extends Archive {
|
||||
/**
|
||||
* Record for storing info about a SourceArchive from a program that couldn't be found and opened.
|
||||
* It provides a handle for actions to remove the datatype references to a missing archive.
|
||||
*/
|
||||
public record InvalidArchive(String name, UniversalID id, ArchiveType type, String domainFileID) {
|
||||
|
||||
public abstract DomainFile getDomainFile();
|
||||
|
||||
public abstract DomainObject getDomainObject();
|
||||
|
||||
public abstract boolean hasExclusiveAccess();
|
||||
}
|
||||
-110
@@ -1,110 +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.datamgr.archive;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
||||
import generic.theme.GIcon;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.UniversalID;
|
||||
import ghidra.util.exception.DuplicateFileException;
|
||||
|
||||
public class InvalidFileArchive implements Archive {
|
||||
|
||||
private static final Icon INVALID_ARCHIVE_ICON =
|
||||
new GIcon("icon.plugin.datatypes.archive.invalid");
|
||||
private DataTypeManagerHandler archiveManager;
|
||||
private UniversalID universalID;
|
||||
private ArchiveType archiveType;
|
||||
private String name;
|
||||
private String domainFileID;
|
||||
|
||||
InvalidFileArchive(DataTypeManagerHandler archiveManager, SourceArchive sourceArchive) {
|
||||
this.archiveManager = archiveManager;
|
||||
this.universalID = sourceArchive.getSourceArchiveID();
|
||||
this.archiveType = sourceArchive.getArchiveType();
|
||||
this.name = sourceArchive.getName();
|
||||
this.domainFileID = sourceArchive.getDomainFileID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeManager getDataTypeManager() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isModifiable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Archive archive) {
|
||||
if (archive instanceof InvalidFileArchive) {
|
||||
return getName().compareToIgnoreCase(archive.getName());
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
public ArchiveType getArchiveType() {
|
||||
return archiveType;
|
||||
}
|
||||
|
||||
public String getDomainFileID() {
|
||||
return domainFileID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
archiveManager.archiveClosed(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChanged() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSavable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save() throws DuplicateFileException, IOException {
|
||||
// Can't "Save" so do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAs(Component component) throws IOException {
|
||||
// Can't "Save As" so do nothing.
|
||||
}
|
||||
|
||||
public UniversalID getUniversalID() {
|
||||
return universalID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getIcon(boolean expanded) {
|
||||
return INVALID_ARCHIVE_ICON;
|
||||
}
|
||||
}
|
||||
-135
@@ -1,135 +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.datamgr.archive;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
||||
import generic.theme.GIcon;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.DataTypeManagerChangeListener;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.exception.DuplicateFileException;
|
||||
|
||||
public class ProgramArchive implements DomainFileArchive {
|
||||
|
||||
private static Icon CLOSED_ICON = new GIcon("icon.plugin.datatypes.archive.program.closed");
|
||||
private static Icon OPEN_ICON = new GIcon("icon.plugin.datatypes.archive.program.open");
|
||||
private final Program program;
|
||||
DataTypeManagerChangeListener categoryListener; // hold on to since it is stored in a weak set
|
||||
private DataTypeManager dataTypeManager;
|
||||
|
||||
ProgramArchive(Program program) {
|
||||
this.program = program;
|
||||
this.dataTypeManager = program.getDataTypeManager();
|
||||
}
|
||||
|
||||
public Program getProgram() {
|
||||
return program;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeManager getDataTypeManager() {
|
||||
return dataTypeManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return dataTypeManager.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return program.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ProgramArchive other = (ProgramArchive) obj;
|
||||
return Objects.equals(program, other.program);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Archive archive) {
|
||||
if (archive instanceof BuiltInArchive) {
|
||||
return 1;
|
||||
}
|
||||
return -1; // Programs are always before everything else except for built-ins
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isModifiable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
// Can't directly close the program archive. Instead you must close the Program.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasExclusiveAccess() {
|
||||
return program.hasExclusiveAccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChanged() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSavable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save() throws DuplicateFileException, IOException {
|
||||
// Can't "Save" so do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAs(Component component) throws IOException {
|
||||
// Can't "Save As" so do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainFile getDomainFile() {
|
||||
return program.getDomainFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Program getDomainObject() {
|
||||
return program;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getIcon(boolean expanded) {
|
||||
return expanded ? OPEN_ICON : CLOSED_ICON;
|
||||
}
|
||||
}
|
||||
-231
File diff suppressed because it is too large
Load Diff
+2
-17
@@ -24,11 +24,11 @@ import ghidra.app.plugin.core.compositeeditor.*;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.actions.AbstractFindReferencesToFieldAction;
|
||||
import ghidra.app.plugin.core.function.AbstractEditFunctionSignatureDialog;
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.Enum;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.FunctionSignature;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.exception.*;
|
||||
|
||||
@@ -458,21 +458,6 @@ public class DataTypeEditorManager implements EditorListener {
|
||||
dismissEditors(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the indicated domain object can be closed. The user will be prompted
|
||||
* to save any editor changes. If the user cancels when prompted to save then the domain
|
||||
* object should not close.
|
||||
* @param dObj the domain object
|
||||
* @return true if it can close.
|
||||
*/
|
||||
protected boolean canCloseDomainObject(DomainObject dObj) {
|
||||
if (dObj instanceof Program) {
|
||||
Program p = (Program) dObj;
|
||||
return checkEditors(p.getListing().getDataTypeManager(), true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean showStructureNumbersInHex() {
|
||||
return editorOptionMgr.showStructureNumbersInHex();
|
||||
}
|
||||
|
||||
+15
-12
@@ -1,30 +1,33 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* 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.framework.main.datatree;
|
||||
package ghidra.app.plugin.core.datamgr.tree;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.archive.Archive;
|
||||
import java.util.Comparator;
|
||||
|
||||
import java.util.List;
|
||||
import ghidra.program.model.dtarchive.DataTypeStore;
|
||||
|
||||
/**
|
||||
* An interface to be implemented by any class that can return a list of Archives.
|
||||
* For example, the tool's data type manager can return a list of archives within the project.
|
||||
*/
|
||||
public interface ArchiveProvider {
|
||||
public class ArchiveComparator implements Comparator<DataTypeStore> {
|
||||
|
||||
@Override
|
||||
public int compare(DataTypeStore a1, DataTypeStore a2) {
|
||||
int result = Integer.compare(a1.getArchiveType().sortOrder, a2.getArchiveType().sortOrder);
|
||||
if (result == 0) {
|
||||
result = a1.getName().compareTo(a2.getName());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<Archive> getArchives();
|
||||
}
|
||||
+34
-494
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user