From ff5d7a12d61247711bf8f7c8143daecf0471c098 Mon Sep 17 00:00:00 2001
From: ghidragon <106987263+ghidragon@users.noreply.github.com>
Date: Fri, 1 May 2026 14:49:47 -0400
Subject: [PATCH] GP-6779 Refactoring DataTypeManagers/Archives
---
.../main/java/ghidra/dbg/isf/IsfServer.java | 7 +-
.../ghidra/trace/database/DBTraceManager.java | 8 +-
.../database/data/DBTraceDataTypeManager.java | 46 +-
.../guest/DBTracePlatformManager.java | 6 +-
.../database/program/DBTraceProgramView.java | 11 +-
.../DBTraceProgramViewFunctionManager.java | 8 +-
.../main/java/ghidra/trace/model/Trace.java | 5 +-
.../data/DBTraceDataTypeManagerTest.java | 19 +-
.../Base/ghidra_scripts/CompareGDTs.java | 79 +-
.../CreateDefaultGDTArchivesScript.java | 2396 +++++++++--------
.../CreateExampleGDTArchiveScript.java | 808 +++---
.../CreateUEFIGDTArchivesScript.java | 77 +-
.../FixupCompositeDataTypesScript.java | 27 +-
.../SynchronizeGDTCategoryPaths.java | 57 +-
.../data_type_manager_description.htm | 31 +-
.../foundation/FoundationInitializer.java | 5 +-
.../merge/DataTypeArchiveMergeManager.java | 39 +-
.../DataTypeArchiveMergeManagerPlugin.java | 8 +-
.../java/ghidra/app/merge/MergeManager.java | 27 +-
.../merge/ProgramMultiUserMergeManager.java | 40 +-
.../merge/datatypes/DataTypeMergeManager.java | 78 +-
.../analysis/ApplyDataArchiveAnalyzer.java | 12 +-
.../DefaultDataTypeManagerService.java | 4 +-
.../CompositeEditorDtArchiveDB.java | 109 +
.../compositeeditor/CompositeEditorModel.java | 14 +-
.../CompositeViewerDataTypeManager.java | 121 +-
.../app/plugin/core/cparser/CParserTask.java | 68 +-
.../app/plugin/core/cparser/ParseDialog.java | 34 +-
.../core/datamgr/ActiveDataTypeStores.java | 572 ++++
.../{archive => }/ArchiveFileChooser.java | 24 +-
.../plugin/core/datamgr/ArchiveManager.java | 826 ++++++
.../core/datamgr/ArchiveManagerListener.java | 73 +
.../datamgr/ArchiveUndoCheckoutTask.java} | 123 +-
.../datamgr/CreateProjectArchiveDialog.java | 87 +
.../core/datamgr/DataTypeArchiveSaveTask.java | 105 +
.../{archive => }/DataTypeIndexer.java | 2 +-
.../core/datamgr/DataTypeManagerPlugin.java | 636 +++--
.../core/datamgr/DataTypePropertyManager.java | 22 +-
.../core/datamgr/DataTypeSynchronizer.java | 29 +-
.../core/datamgr/DataTypesActionContext.java | 25 +-
.../core/datamgr/DataTypesProvider.java | 208 +-
.../core/datamgr/OpenDomainFileTask.java | 239 --
.../core/datamgr/OpenFileArchiveTask.java | 117 +
.../core/datamgr/OpenProjectArchiveTask.java | 162 ++
.../datamgr/ProjectArchiveSaveAsDialog.java | 137 +
...tractUndoRedoArchiveTransactionAction.java | 43 +-
.../CaptureFunctionDataTypesAction.java | 12 +-
.../ClearArchiveArchitectureAction.java | 66 +-
.../datamgr/actions/CloseArchiveAction.java | 81 +-
...java => CloseArchiveForEditingAction.java} | 78 +-
.../core/datamgr/actions/CopyAction.java | 2 +-
.../datamgr/actions/CreateArchiveAction.java | 12 +-
.../datamgr/actions/CreateCategoryAction.java | 13 +-
.../datamgr/actions/CreatePointerAction.java | 2 +-
.../actions/CreateProjectArchiveAction.java | 17 +-
.../datamgr/actions/CreateTypeDefAction.java | 8 +-
.../core/datamgr/actions/DeleteAction.java | 4 +-
.../datamgr/actions/DeleteArchiveAction.java | 15 +-
.../actions/DerivativeDataTypeInfo.java | 18 +-
.../actions/EditArchivePathAction.java | 14 +-
.../datamgr/actions/OpenArchiveAction.java | 45 +-
....java => OpenArchiveForEditingAction.java} | 46 +-
.../actions/OpenProjectArchiveAction.java | 39 +-
.../core/datamgr/actions/PasteAction.java | 4 +-
.../actions/RecentlyOpenedArchiveAction.java | 45 +-
.../actions/RedoArchiveTransactionAction.java | 27 +-
...RemoveInvalidArchiveFromProgramAction.java | 19 +-
.../core/datamgr/actions/RenameAction.java | 10 +-
.../actions/ReplaceDataTypeAction.java | 20 +-
.../datamgr/actions/SaveArchiveAction.java | 63 +-
...AsAction.java => SaveArchiveAsAction.java} | 52 +-
.../actions/SetArchiveArchitectureAction.java | 111 +-
.../actions/UndoArchiveTransactionAction.java | 27 +-
.../UpdateSourceArchiveNamesAction.java | 96 -
.../associate/AssociateDataTypeAction.java | 66 +-
.../actions/associate/CommitAction.java | 13 +-
.../associate/CommitSingleDataTypeAction.java | 18 +-
.../actions/associate/DisassociateAction.java | 20 +-
.../associate/DisassociateDataTypeAction.java | 10 +-
.../actions/associate/RevertAction.java | 16 +-
.../associate/RevertDataTypeAction.java | 16 +-
.../datamgr/actions/associate/SyncAction.java | 18 +-
.../actions/associate/SyncRefreshAction.java | 15 +-
.../actions/associate/UpdateAction.java | 11 +-
.../associate/UpdateSingleDataTypeAction.java | 17 +-
.../plugin/core/datamgr/archive/Archive.java | 84 -
.../archive/ArchiveManagerListener.java | 44 -
.../core/datamgr/archive/ArchiveUtils.java | 215 --
.../archive/BasicDataTypeArchiveService.java | 215 ++
.../core/datamgr/archive/BuiltInArchive.java | 89 -
.../archive/DataTypeManagerHandler.java | 1810 -------------
.../DefaultDataTypeArchiveService.java | 236 --
.../core/datamgr/archive/FileArchive.java | 330 ---
...inFileArchive.java => InvalidArchive.java} | 19 +-
.../datamgr/archive/InvalidFileArchive.java | 110 -
.../core/datamgr/archive/ProgramArchive.java | 135 -
.../core/datamgr/archive/ProjectArchive.java | 231 --
.../datamgr/editor/DataTypeEditorManager.java | 19 +-
.../core/datamgr/tree/ArchiveComparator.java} | 27 +-
.../plugin/core/datamgr/tree/ArchiveNode.java | 528 +---
.../core/datamgr/tree/ArchiveRootNode.java | 197 +-
.../datamgr/tree/ArchiveRootNodeListener.java | 4 +-
.../core/datamgr/tree/BuiltInArchiveNode.java | 16 +-
.../core/datamgr/tree/CategoryNode.java | 6 +-
.../datamgr/tree/DataTypeArchiveGTree.java | 51 +-
.../tree/DataTypeDragNDropHandler.java | 20 +-
.../core/datamgr/tree/DataTypeNode.java | 4 +-
.../core/datamgr/tree/DataTypeStoreNode.java | 447 +++
.../core/datamgr/tree/DataTypeTreeNode.java | 6 +-
.../core/datamgr/tree/FileArchiveNode.java | 36 +-
.../core/datamgr/tree/InvalidArchiveNode.java | 41 +-
.../core/datamgr/tree/ProgramArchiveNode.java | 72 +-
.../core/datamgr/tree/ProjectArchiveNode.java | 97 +-
...FileArchiveNode.java => VersionState.java} | 130 +-
.../core/datamgr/tree/VersionedNode.java | 45 +
.../datamgr/util/DataTypeArchiveUtility.java | 12 +-
.../datamgr/util/DataTypeChooserDialog.java | 13 +-
.../util/DataTypeTreeCopyMoveTask.java | 39 +-
.../datamgr/util/DataTypeTreeDeleteTask.java | 22 +-
.../core/datamgr/util/DataTypeUtils.java | 42 +-
.../datapreview/DataTypePreviewPlugin.java | 7 +-
.../core/stackeditor/StackEditorModel.java | 2 +-
.../app/services/DataTypeArchiveService.java | 193 +-
.../java/ghidra/app/services/Recover.java} | 16 +-
.../java/ghidra/app/services/Upgrade.java | 26 +
.../golang/structmapping/DataTypeMapper.java | 30 +-
.../app/util/cparser/C/CParserUtils.java | 197 +-
.../ghidra/app/util/exporter/GdtExporter.java | 4 +-
.../ghidra/app/util/opinion/GdtLoader.java | 46 +-
.../main/OpenVersionedFileDialog.java | 5 +
...draDataTypeArchiveMergeManagerFactory.java | 35 +-
...raProgramMultiUserMergeManagerFactory.java | 25 +-
.../program/flatapi/FlatProgramAPI.java | 32 +
.../ghidra/program/util/DataTypeCleaner.java | 7 +-
.../src/main/java/ghidra/test/TestEnv.java | 8 +-
.../support/ProcessorEmulatorTestAdapter.java | 22 +-
.../javacc/ghidra/app/util/cparser/C/C.jj | 23 +-
.../app/merge/DummyArchiveMergeManager.java | 24 +-
.../core/compositeeditor/CommonTestData.java | 234 +-
.../StructureEditorArchiveTest.java | 2 +-
.../ParseDialogParsingAndPromptsTest.java | 25 +-
.../core/data/ApplyDataTypeToBrowserTest.java | 7 +-
.../datamgr/AbstractCreateArchiveTest.java | 21 +-
.../datamgr/ArchiveRemappedHeadedTest.java | 101 +-
.../datamgr/ArchiveRemappedHeadlessTest.java | 18 +-
.../core/datamgr/CreateArchive1Test.java | 35 +-
.../datamgr/CreateEnumFromSelectionTest.java | 8 +-
.../datamgr/CreateLabelsFromEnumsTest.java | 8 +-
.../core/datamgr/DataTypeArchiveIDTest.java | 72 +-
.../datamgr/DataTypeCopyMoveDragTest.java | 8 +-
.../datamgr/DataTypeManagerPluginTest.java | 28 +-
.../core/datamgr/DataTypeTestUtils.java | 94 +-
.../core/datamgr/FavoritesAndMiscTest.java | 10 +-
.../FileArchiveEnumEditorUndoRedoTest.java | 21 +-
.../ProjectArchiveEnumEditorUndoRedoTest.java | 35 +-
.../dwarf/DWARFConflictHandlerTest.java | 8 +-
.../datatype/DataTypeSelectionDialogTest.java | 48 +-
.../DataTypeSelectionTextFieldTest.java | 19 +-
.../database/code/CodeUnitIteratorTest.java | 13 +-
.../database/data/ConflictHandlerTest.java | 2 +-
.../database/data/DataManagerTest.java | 18 +-
.../TestDoubleDataTypeManagerService.java | 37 +-
.../ghidra/app/util/cparser/CParserTest.java | 185 +-
.../app/util/cparser/PreProcessorTest.java | 117 +-
.../database/MergeTestFacilitator.java | 6 +-
.../model/data/AbstractCompositeTest.java | 7 +-
.../model/data/StructureDataTypeTest.java | 3 +-
.../program/model/data/UnionDataTypeTest.java | 3 +-
.../pdbapplicator/CppCompositeTypeTest.java | 9 +-
.../datamgr/RustDataTypeArchiveIDTest.java | 21 +-
.../EmuLinuxAmd64SyscallUseropLibrary.java | 16 +-
.../EmuLinuxX86SyscallUseropLibrary.java | 16 +-
.../ghidra/pcode/struct/StructuredSleigh.java | 5 +-
.../feature/vt/api/util/EmptyVTSession.java | 5 +
.../framework/data/DomainFileProxy.java | 25 +-
.../framework/data/DomainObjectAdapter.java | 6 +-
.../framework/data/DomainObjectDbModule.java | 73 +
.../ghidra/framework/data/GhidraFileData.java | 131 +-
.../framework/data/TransientDataManager.java | 16 +-
.../DomainFileProviderContextAction.java | 6 +-
.../main/datatree/VersionControlDialog.java | 6 +-
.../ghidra/framework/model/DomainObject.java | 6 +
.../framework/model/RuntimeIOException.java | 13 +-
.../framework/project/DefaultProject.java | 5 +-
.../program/database/DataTypeArchiveDB.java | 575 ----
.../database/ProgramAddressFactory.java | 4 +-
.../database/ProgramContentHandler.java | 5 +-
.../ghidra/program/database/ProgramDB.java | 18 +-
.../{ManagerDB.java => ProgramDBModule.java} | 43 +-
.../ProgramMultiUserMergeManagerFactory.java | 19 +-
.../database/ProgramOverlayAddressSpace.java | 7 +-
.../database/ProjectDataTypeManager.java | 322 ---
.../database/bookmark/BookmarkDBManager.java | 6 +-
.../program/database/code/CodeManager.java | 6 +-
.../data/ArchiveDataTypeManagerDB.java | 428 +++
.../database/data/BitFieldDBDataType.java | 2 +-
.../data/BuiltInDataTypeManagerDB.java | 136 +
.../program/database/data/CategoryDB.java | 1 -
.../DataTypeArchiveMergeManagerFactory.java | 23 +-
.../data/DataTypeArchiveTransformer.java | 165 +-
.../data/DataTypeArchiveTransformerPanel.java | 7 +-
.../database/data/DataTypeIDConverter.java | 31 +-
.../database/data/DataTypeManagerDB.java | 322 +--
.../database/data/FileDataTypeManagerDB.java | 187 ++
.../data/ProgramBasedDataTypeManagerDB.java | 11 +-
.../database/data/ProgramDataTypeManager.java | 44 +-
.../data/ProjectDataTypeManagerDB.java | 107 +
.../database/data/SourceArchiveDB.java | 3 +-
.../data/TransientDataTypeManager.java | 141 +
.../program/database/data/TypedefDB.java | 2 +-
.../dtarchive/BuiltInDtArchiveDB.java | 173 ++
.../DataTypeArchiveContentHandler.java | 61 +-
.../database/dtarchive/DataTypeArchiveDB.java | 1024 +++++++
.../DataTypeArchiveDBChangeSet.java | 6 +-
.../dtarchive/DataTypeArchiveFactory.java | 311 +++
.../DataTypeArchiveLinkContentHandler.java | 6 +-
.../dtarchive/DataTypeStoreDBModule.java} | 15 +-
.../database/dtarchive/DefaultConsumer.java | 29 +
.../database/dtarchive/FileDtArchiveDB.java | 429 +++
.../dtarchive/ProjectDtArchiveDB.java | 302 +++
.../dtarchive/TransientDtArchiveDB.java | 80 +
.../database/external/ExternalManagerDB.java | 8 +-
.../database/function/FunctionManagerDB.java | 4 +-
.../program/database/mem/MemoryMapDB.java | 6 +-
.../program/database/module/TreeManager.java | 8 +-
.../properties/DBPropertyMapManager.java | 8 +-
.../references/ReferenceDBManager.java | 6 +-
.../register/OldProgramContextDB.java | 8 +-
.../register/ProgramRegisterContextDB.java | 8 +-
.../database/reloc/RelocationManager.java | 8 +-
.../sourcemap/SourceFileManagerDB.java | 8 +-
.../database/symbol/EquateManager.java | 6 +-
.../database/symbol/NamespaceManager.java | 8 +-
.../symbol/SymbolDatabaseAdapterV0.java | 2 +-
.../database/symbol/SymbolManager.java | 6 +-
.../model/data/ArchiveDataTypeManager.java | 130 +
.../program/model/data/ArchiveType.java | 21 +-
.../model/data/BuiltInDataTypeManager.java | 202 +-
.../model/data/DataTypeArchiveIdDumper.java | 21 +-
.../model/data/DataTypeConflictHandler.java | 22 +-
.../program/model/data/DataTypeManager.java | 44 +-
.../data/DataTypeManagerDomainObject.java | 22 -
.../model/data/FileDataTypeManager.java | 395 +--
.../data/ProgramBasedDataTypeManager.java | 10 +-
.../ProjectArchiveBasedDataTypeManager.java | 24 -
.../model/data/StandAloneDataTypeManager.java | 1095 +-------
.../model/dtarchive/ArchiveWarning.java | 88 +
.../model/dtarchive/DataTypeArchive.java | 176 ++
.../model/dtarchive/DataTypeStore.java | 54 +
.../model/dtarchive/FileDataTypeArchive.java | 90 +
.../dtarchive/PersistentDataTypeArchive.java | 46 +
.../dtarchive/ProjectDataTypeArchive.java | 32 +
.../dtarchive/TransientDataTypeArchive.java} | 24 +-
.../model/lang/ProgramArchitecture.java | 32 +-
.../model/listing/DataTypeArchive.java | 68 -
.../model/listing/FunctionManager.java | 4 +-
.../ghidra/program/model/listing/Program.java | 53 +-
.../program/util/DtArchiveChangeRecord.java | 52 +
.../DtArchiveEvent.java} | 21 +-
.../database/data/DataTypeUtilitiesTest.java | 5 +-
.../ghidra/program/model/data/EnumTest.java | 18 +-
.../model/data/FileDataTypeManagerTest.java | 101 +-
.../data/FunctionDefinitionDataTypeTest.java | 15 +-
.../database/data/BitFieldDBDataTypeTest.java | 22 +-
.../database/data/DataTypeDBReplaceTest.java | 23 +-
.../database/data/StructureDBTest.java | 12 +-
.../program/database/data/TypedefDBTest.java | 28 +-
.../program/database/data/UnionDBTest.java | 43 +-
.../database/data/merge/EnumMergerTest.java | 10 +-
.../data/merge/StructureMergerTest.java | 6 +-
.../database/data/merge/UnionMergerTest.java | 6 +-
.../program/database/mem/MemBlockDBTest.java | 6 +-
.../program/model/StubFunctionManager.java | 8 +-
.../ghidra/program/model/StubProgram.java | 35 +
.../model/data/TestDoubleDataTypeManager.java | 20 +-
.../model/data/TestDummyDataTypeManager.java | 21 +-
.../CreateAVR8GDTArchiveScript.java | 25 +-
.../CreateJNIGDTArchivesScript.java | 160 +-
.../javaclass/test/DescriptorDecoderTest.java | 36 +-
.../core/analysis/eBPFHelperDataTypes.java | 10 +-
.../DataTypeManagerPluginScreenShots.java | 48 +-
.../screenshot/RepositoryScreenShots.java | 4 +-
.../datatree/ProjectLinkFileStatusTest.java | 10 +-
.../model/lang/AbstractProtoModelTest.java | 28 +-
284 files changed, 13132 insertions(+), 11825 deletions(-)
create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorDtArchiveDB.java
create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/ActiveDataTypeStores.java
rename Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/{archive => }/ArchiveFileChooser.java (87%)
create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/ArchiveManager.java
create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/ArchiveManagerListener.java
rename Ghidra/Features/Base/src/main/java/ghidra/{framework/main/datatree/VersionControlDataTypeArchiveUndoCheckoutAction.java => app/plugin/core/datamgr/ArchiveUndoCheckoutTask.java} (66%)
create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/CreateProjectArchiveDialog.java
create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeArchiveSaveTask.java
rename Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/{archive => }/DataTypeIndexer.java (99%)
delete mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/OpenDomainFileTask.java
create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/OpenFileArchiveTask.java
create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/OpenProjectArchiveTask.java
create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/ProjectArchiveSaveAsDialog.java
rename Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/{UnlockArchiveAction.java => CloseArchiveForEditingAction.java} (66%)
rename Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/{LockArchiveAction.java => OpenArchiveForEditingAction.java} (77%)
rename Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/{SaveAsAction.java => SaveArchiveAsAction.java} (59%)
delete mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/UpdateSourceArchiveNamesAction.java
delete mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/Archive.java
delete mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ArchiveManagerListener.java
delete mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ArchiveUtils.java
create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/BasicDataTypeArchiveService.java
delete mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/BuiltInArchive.java
delete mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DataTypeManagerHandler.java
delete mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DefaultDataTypeArchiveService.java
delete mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/FileArchive.java
rename Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/{DomainFileArchive.java => InvalidArchive.java} (62%)
delete mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/InvalidFileArchive.java
delete mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ProgramArchive.java
delete mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ProjectArchive.java
rename Ghidra/Features/Base/src/main/java/ghidra/{framework/main/datatree/ArchiveProvider.java => app/plugin/core/datamgr/tree/ArchiveComparator.java} (55%)
create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeStoreNode.java
rename Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/{DomainFileArchiveNode.java => VersionState.java} (58%)
create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/VersionedNode.java
rename Ghidra/{Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FileArchiveBasedDataTypeManager.java => Features/Base/src/main/java/ghidra/app/services/Recover.java} (55%)
create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/services/Upgrade.java
create mode 100644 Ghidra/Framework/Project/src/main/java/ghidra/framework/data/DomainObjectDbModule.java
delete mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/DataTypeArchiveDB.java
rename Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/{ManagerDB.java => ProgramDBModule.java} (53%)
delete mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProjectDataTypeManager.java
create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ArchiveDataTypeManagerDB.java
create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/BuiltInDataTypeManagerDB.java
rename Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/{ => data}/DataTypeArchiveMergeManagerFactory.java (62%)
create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/FileDataTypeManagerDB.java
create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ProjectDataTypeManagerDB.java
create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TransientDataTypeManager.java
create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/dtarchive/BuiltInDtArchiveDB.java
rename Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/{ => dtarchive}/DataTypeArchiveContentHandler.java (83%)
create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/dtarchive/DataTypeArchiveDB.java
rename Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/{ => dtarchive}/DataTypeArchiveDBChangeSet.java (99%)
create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/dtarchive/DataTypeArchiveFactory.java
rename Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/{ => dtarchive}/DataTypeArchiveLinkContentHandler.java (91%)
rename Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/{model/data/FileBasedDataTypeManager.java => database/dtarchive/DataTypeStoreDBModule.java} (68%)
create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/dtarchive/DefaultConsumer.java
create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/dtarchive/FileDtArchiveDB.java
create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/dtarchive/ProjectDtArchiveDB.java
create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/dtarchive/TransientDtArchiveDB.java
create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ArchiveDataTypeManager.java
delete mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManagerDomainObject.java
delete mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ProjectArchiveBasedDataTypeManager.java
create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/dtarchive/ArchiveWarning.java
create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/dtarchive/DataTypeArchive.java
create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/dtarchive/DataTypeStore.java
create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/dtarchive/FileDataTypeArchive.java
create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/dtarchive/PersistentDataTypeArchive.java
create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/dtarchive/ProjectDataTypeArchive.java
rename Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/{app/merge/DataTypeManagerOwner.java => program/model/dtarchive/TransientDataTypeArchive.java} (59%)
delete mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/DataTypeArchive.java
create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/DtArchiveChangeRecord.java
rename Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/{model/data/DomainFileBasedDataTypeManager.java => util/DtArchiveEvent.java} (59%)
diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/dbg/isf/IsfServer.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/dbg/isf/IsfServer.java
index aeba8d0941..86b4b0f6bb 100644
--- a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/dbg/isf/IsfServer.java
+++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/dbg/isf/IsfServer.java
@@ -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 {
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTraceManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTraceManager.java
index b2e149559f..e4a4b93e39 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTraceManager.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTraceManager.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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);
}
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/data/DBTraceDataTypeManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/data/DBTraceDataTypeManager.java
index d59a9fe049..69b1d8408c 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/data/DBTraceDataTypeManager.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/data/DBTraceDataTypeManager.java
@@ -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() {
/**
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/guest/DBTracePlatformManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/guest/DBTracePlatformManager.java
index 15afbf3003..eb313a20f7 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/guest/DBTracePlatformManager.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/guest/DBTracePlatformManager.java
@@ -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;
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramView.java
index 721a5808e8..7afb967734 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramView.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramView.java
@@ -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 extends
- PairingIteratorMerger, Entry,
- Entry> {
+ PairingIteratorMerger, Entry, Entry> {
protected static Iterable, Entry>> iter(
Iterable> left, Iterable> right) {
@@ -1565,4 +1563,9 @@ public class DBTraceProgramView implements TraceProgramView {
}
return queues;
}
+
+ @Override
+ public ArchiveType getArchiveType() {
+ return ArchiveType.PROGRAM;
+ }
}
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewFunctionManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewFunctionManager.java
index 96a007dc64..2ebf2d1886 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewFunctionManager.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewFunctionManager.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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();
}
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/Trace.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/Trace.java
index 1e8c51a7b7..ab2e8131e5 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/Trace.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/Trace.java
@@ -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();
}
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/data/DBTraceDataTypeManagerTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/data/DBTraceDataTypeManagerTest.java
index fae5d7d1a8..9e6399122c 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/data/DBTraceDataTypeManagerTest.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/data/DBTraceDataTypeManagerTest.java
@@ -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
diff --git a/Ghidra/Features/Base/ghidra_scripts/CompareGDTs.java b/Ghidra/Features/Base/ghidra_scripts/CompareGDTs.java
index d2dac13c92..98e756d34d 100644
--- a/Ghidra/Features/Base/ghidra_scripts/CompareGDTs.java
+++ b/Ghidra/Features/Base/ghidra_scripts/CompareGDTs.java
@@ -27,7 +27,8 @@ import java.util.*;
import ghidra.app.script.GhidraScript;
import ghidra.program.model.data.*;
import ghidra.program.model.data.Enum;
-import ghidra.program.model.data.StandAloneDataTypeManager.ArchiveWarning;
+import ghidra.program.model.dtarchive.ArchiveWarning;
+import ghidra.program.model.dtarchive.FileDataTypeArchive;
import ghidra.util.UniversalID;
public class CompareGDTs extends GhidraScript {
@@ -35,8 +36,10 @@ public class CompareGDTs extends GhidraScript {
private File firstFile;
private File secondFile;
private File outputFile;
- private FileDataTypeManager firstArchive;
- private FileDataTypeManager secondArchive;
+ private FileDataTypeArchive archive1;
+ private FileDataTypeArchive archive2;
+ private DataTypeManager dtm1;
+ private DataTypeManager dtm2;
private PrintWriter printWriter;
boolean matchByName;
boolean checkPointers;
@@ -57,23 +60,24 @@ public class CompareGDTs extends GhidraScript {
}
}
- firstArchive = openDataTypeArchive(firstFile, false);
- if (firstArchive.getWarning() != ArchiveWarning.NONE) {
+ archive1 = openFileDataTypeArchive(firstFile, false);
+ if (archive1.getWarning() != ArchiveWarning.NONE) {
popup(
"An architecture language error occured while opening archive (see log for details)\n" +
firstFile.getPath());
return;
}
- secondArchive = openDataTypeArchive(secondFile, false);
- if (secondArchive.getWarning() != ArchiveWarning.NONE) {
+ archive2 = openFileDataTypeArchive(secondFile, false);
+ if (archive2.getWarning() != ArchiveWarning.NONE) {
popup(
"An architecture language error occured while opening archive (see log for details)\n" +
secondFile.getPath());
- firstArchive.close();
+ archive1.release(this);
return;
}
-
+ dtm1 = archive1.getDataTypeManager();
+ dtm2 = archive2.getDataTypeManager();
matchByName = askYesNo("Match Data Types By Path Name?",
"Do you want to match data types by their path names (rather than by Universal ID)?");
checkPointers = askYesNo("Check Pointers?", "Do you want to check Pointers?");
@@ -85,8 +89,8 @@ public class CompareGDTs extends GhidraScript {
}
finally {
printWriter.close();
- firstArchive.close();
- secondArchive.close();
+ archive1.release(this);
+ archive2.release(this);
}
}
@@ -100,30 +104,30 @@ public class CompareGDTs extends GhidraScript {
secondFile.getAbsolutePath() + ".");
output("\nThe following data types are only in " + firstFile.getAbsolutePath() + ".");
- long onlyInFirst = outputEachDataTypeOnlyInFirst(firstArchive, secondArchive);
+ long onlyInFirst = outputEachDataTypeOnlyInFirst(dtm1, dtm2);
output(onlyInFirst + " data types that were only in first archive.");
output("\nThe following data types are only in " + secondFile.getAbsolutePath() + ".");
- long onlyInSecond = outputEachDataTypeOnlyInFirst(secondArchive, firstArchive);
+ long onlyInSecond = outputEachDataTypeOnlyInFirst(dtm2, dtm1);
output(onlyInSecond + " data types that were only in second archive.");
output("\nThe following are different kinds of data types.");
- long differentKinds = outputWhereTypesDiffer(firstArchive, secondArchive);
+ long differentKinds = outputWhereTypesDiffer(dtm1, dtm2);
output(differentKinds + " data types had different types.");
output("\nThe following data types are defined differently.");
- long differentDefinitions = outputWhereDefinitionsDiffer(firstArchive, secondArchive);
+ long differentDefinitions = outputWhereDefinitionsDiffer(dtm1, dtm2);
output(differentDefinitions + " data types had different definitions.");
output("\nThe following data types are different sizes");
- long differentSizes = outputWhereSizesDiffer(firstArchive, secondArchive);
+ long differentSizes = outputWhereSizesDiffer(dtm1, dtm2);
output(differentSizes + " data types had different sizes.");
output("\n");
}
- private long outputEachDataTypeOnlyInFirst(FileDataTypeManager dtmArchive1,
- FileDataTypeManager dtmArchive2) {
+ private long outputEachDataTypeOnlyInFirst(DataTypeManager dtmArchive1,
+ DataTypeManager dtmArchive2) {
long missingCount = 0;
Iterator allDataTypes = dtmArchive1.getAllDataTypes();
@@ -136,7 +140,7 @@ public class CompareGDTs extends GhidraScript {
return missingCount;
}
- private boolean outputIfMissingDataType(DataType dataType, FileDataTypeManager dtmArchive) {
+ private boolean outputIfMissingDataType(DataType dataType, DataTypeManager dtmArchive) {
if (!checkPointers && dataType instanceof Pointer) {
return false;
@@ -155,7 +159,7 @@ public class CompareGDTs extends GhidraScript {
return false;
}
- private DataType getMatchingDataType(DataType dataType, FileDataTypeManager dtmArchive) {
+ private DataType getMatchingDataType(DataType dataType, DataTypeManager dtmArchive) {
if (!matchByName) {
UniversalID universalID = dataType.getUniversalID();
@@ -172,17 +176,20 @@ public class CompareGDTs extends GhidraScript {
// find by name
List list = new ArrayList();
- dtmArchive.findDataTypes(dataType.getName(), list );
+ dtmArchive.findDataTypes(dataType.getName(), list);
for (DataType dtc : list) {
- if (dataType.getCategoryPath().getPath().toLowerCase().equals(dtc.getCategoryPath().getPath().toLowerCase())) {
+ if (dataType.getCategoryPath()
+ .getPath()
+ .toLowerCase()
+ .equals(dtc.getCategoryPath().getPath().toLowerCase())) {
return dtc;
}
}
return null;
}
- private long outputWhereTypesDiffer(FileDataTypeManager dtmArchive1,
- FileDataTypeManager dtmArchive2) {
+ private long outputWhereTypesDiffer(DataTypeManager dtmArchive1,
+ DataTypeManager dtmArchive2) {
long differCount = 0;
Iterator allDataTypes = dtmArchive1.getAllDataTypes();
@@ -195,8 +202,8 @@ public class CompareGDTs extends GhidraScript {
return differCount;
}
- private long outputWhereSizesDiffer(FileDataTypeManager dtmArchive1,
- FileDataTypeManager dtmArchive2) {
+ private long outputWhereSizesDiffer(DataTypeManager dtmArchive1,
+ DataTypeManager dtmArchive2) {
long differCount = 0;
Iterator allDataTypes = dtmArchive1.getAllDataTypes();
@@ -209,7 +216,7 @@ public class CompareGDTs extends GhidraScript {
return differCount;
}
- private boolean outputIfDifferentTypes(DataType dataType, FileDataTypeManager dtmArchive) {
+ private boolean outputIfDifferentTypes(DataType dataType, DataTypeManager dtmArchive) {
if (!checkPointers && dataType instanceof Pointer) {
return false;
@@ -233,8 +240,8 @@ public class CompareGDTs extends GhidraScript {
return false;
}
- private long outputWhereDefinitionsDiffer(FileDataTypeManager dtmArchive1,
- FileDataTypeManager dtmArchive2) {
+ private long outputWhereDefinitionsDiffer(DataTypeManager dtmArchive1,
+ DataTypeManager dtmArchive2) {
long differCount = 0;
Iterator allDataTypes = dtmArchive1.getAllDataTypes();
@@ -248,7 +255,7 @@ public class CompareGDTs extends GhidraScript {
}
private boolean outputIfDifferentDefinitions(DataType dataType,
- FileDataTypeManager dtmArchive) {
+ DataTypeManager dtmArchive) {
if (!checkPointers && dataType instanceof Pointer) {
return false;
@@ -263,7 +270,7 @@ public class CompareGDTs extends GhidraScript {
Class> dtClass = dataType.getClass();
Class> sameNamedDtClass = matchingDataType.getClass();
if (dtClass == sameNamedDtClass) {
- if (dataType instanceof Enum && (((Enum) dataType).getCount()==1)) {
+ if (dataType instanceof Enum && (((Enum) dataType).getCount() == 1)) {
// don't check single entry enums. Size will vary, and they are extracted defines
return checkEnum((Enum) dataType, (Enum) matchingDataType);
}
@@ -283,18 +290,18 @@ public class CompareGDTs extends GhidraScript {
return true;
}
// Check that the name is the same
- if (! e1.getNames()[0].equals(e2.getNames()[0])) {
+ if (!e1.getNames()[0].equals(e2.getNames()[0])) {
return true;
}
// Check the value is the same
if (e1.getValues()[0] != e2.getValues()[0]) {
return true;
- }
-
+ }
+
return false;
}
- private boolean outputIfDifferentSizes(DataType dataType, FileDataTypeManager dtmArchive) {
+ private boolean outputIfDifferentSizes(DataType dataType, DataTypeManager dtmArchive) {
if (!checkPointers && dataType instanceof Pointer) {
return false;
@@ -309,7 +316,7 @@ public class CompareGDTs extends GhidraScript {
Class> dtClass = dataType.getClass();
Class> sameNamedDtClass = matchingDataType.getClass();
if (dtClass == sameNamedDtClass) {
- if (dataType instanceof Enum && (((Enum) dataType).getCount()==1)) {
+ if (dataType instanceof Enum && (((Enum) dataType).getCount() == 1)) {
// don't check single entry enums. Size will vary, and they are extracted defines
return checkEnum((Enum) dataType, (Enum) matchingDataType);
}
diff --git a/Ghidra/Features/Base/ghidra_scripts/CreateDefaultGDTArchivesScript.java b/Ghidra/Features/Base/ghidra_scripts/CreateDefaultGDTArchivesScript.java
index 18adfc1438..47e0f7c707 100644
--- a/Ghidra/Features/Base/ghidra_scripts/CreateDefaultGDTArchivesScript.java
+++ b/Ghidra/Features/Base/ghidra_scripts/CreateDefaultGDTArchivesScript.java
@@ -32,13 +32,15 @@ import java.io.IOException;
import ghidra.app.script.GhidraScript;
import ghidra.app.util.cparser.C.CParserUtils;
import ghidra.app.util.cparser.C.ParseException;
+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.util.task.TaskMonitor;
public class CreateDefaultGDTArchivesScript extends GhidraScript {
private File outputDirectory;
-
+
private static String headerFilePath = "/data/HeaderFiles";
@Override
@@ -47,34 +49,37 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
parseGDT_CLIB32();
parseGDT_CLIB64();
-
+
parseGDT_VS12_32();
parseGDT_VS12_64();
-
+
parseGDT_WinVS22();
parseGDT_WinVS22_WDK();
}
-
- 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.close();
+ FileDataTypeArchive archive = CParserUtils.parseHeaderFiles(filenames,
+ includePaths, args, f.getAbsolutePath(), languageID, compiler, openTypes, this,
+ monitor);
+
+ archive.release(this);
}
/**
@@ -96,230 +101,9 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
}
return f;
}
-
- public void parseGDT_VS12_32() throws Exception {
-
- String filenames[] = {
- "sdkddkver.h",
- "sal.h",
- "assert.h",
- "conio.h",
- "crtdefs.h",
- "crtdbg.h",
- "crtwrn.h",
- "ctype.h",
- "basetsd.h",
- "WinDef.h",
- "WinNT.h",
- "delayimp.h",
- "direct.h",
- "dos.h",
- "errno.h",
- "excpt.h",
- "fcntl.h",
- "float.h",
- "fpieee.h",
- "io.h",
- "iso646.h",
- "limits.h",
- "locale.h",
- "malloc.h",
- "math.h",
- "mbctype.h",
- "mbstring.h",
- "memory.h",
- "minmax.h",
- "new.h",
- "omp.h",
- "pgobootrun.h",
- "process.h",
- "rtcapi.h",
- "search.h",
- "setjmp.h",
- "setjmpex.h",
- "share.h",
- "signal.h",
- "srv.h",
- "stdarg.h",
- "stddef.h",
- "stdexcpt.h",
- "stdio.h",
- "stdlib.h",
- "string.h",
- "tchar.h",
- "time.h",
- "use_ansi.h",
- "vadefs.h",
- "varargs.h",
- "wchar.h",
- "wctype.h",
- "xlocinfo.h",
- "xmath.h",
- "ymath.h",
- "yvals.h",
- "CommDlg.h",
- "WinUser.h",
- "WinNls.h",
- "internal.h",
- "strsafe.h",
- "align.h",
- "awint.h",
- "crtversion.h",
- "cruntime.h",
- "ctime.h",
- "cvt.h",
- "dbgint.h",
- "ehdata.h",
- "emmintrin.h",
- "errmsg.h",
- "fenv.h",
- "file2.h",
- "fltintrn.h",
- "immintrin.h",
- "internal_securecrt.h",
- "inttypes.h",
- "isa_availability.h",
- "mbdata.h",
- "msdos.h",
- "mtdll.h",
- "nlsdownlevel.h",
- "nlsint.h",
- "nmmintrin.h",
- "oscalls.h",
- "pmmintrin.h",
- "rtcsup.h",
- "rterr.h",
- "sect_attribs.h",
- "setlocal.h",
- "smmintrin.h",
- "stdbool.h",
- "stdint.h",
- "syserr.h",
- "targetver.h",
- "tmmintrin.h",
- "winheap.h",
- "wmmintrin.h",
- "wrapwin.h",
- "xkeycheck.h",
- "xmmintrin.h",
- "xmtx.h",
- "xtgmath.h",
- "xxcctype.h",
- "xxdftype.h",
- "xxfftype.h",
- "xxlftype.h",
- "xxwctype.h",
- "xxxprec.h",
- "shlobj.h",
- "evntprov.h",
- "uiautomation.h",
- "aclapi.h",
- "appcompatapi.h",
- "capi.h",
- "clusapi.h",
- "cryptuiapi.h",
- "cscapi.h",
- "devpropdef.h",
- "dhcpsapi.h",
- "dwmapi.h",
- "ehstorapi.h",
- "functiondiscoveryapi.h",
- "ipexport.h",
- "icmpapi.h",
- "iepmapi.h",
- "imapi.h",
- "ksopmapi.h",
- "locationapi.h",
- "lpmapi.h",
- "mapi.h",
- "mbnapi.h",
- "mfapi.h",
- "mgmtapi.h",
- "mmdeviceapi.h",
- "mprapi.h",
- "msctfmonitorapi.h",
- "ndfapi.h",
- "winsock2.h",
- "ws2tcpip.h",
- "iphlpapi.h",
- "netioapi.h",
- "npapi.h",
- "nspapi.h",
- "ntdsapi.h",
- "ntmsapi.h",
- "ntsecapi.h",
- "patchapi.h",
- "portabledeviceapi.h",
- "portabledeviceconnectapi.h",
- "propapi.h",
- "psapi.h",
- "rdpencomapi.h",
- "resapi.h",
- "sapi.h",
- "searchapi.h",
- "sensapi.h",
- "sensorsapi.h",
- "setupapi.h",
- "shellapi.h",
- "shlwapi.h",
- "srrestoreptapi.h",
- "svrapi.h",
- "t2embapi.h",
- "tapi.h",
- "uiautomationcoreapi.h",
- "wcnapi.h",
- "wdsclientapi.h",
- "werapi.h",
- "windowssideshowapi.h",
- "wlanapi.h",
- "wpapi.h",
- "wpcapi.h",
- "wscapi.h",
- "wsdapi.h",
- "rpcproxy.h",
- };
-
- String includePaths[] = {
- headerFilePath+"/VC/VS12/src",
- headerFilePath+"/VC/VS12/include",
- headerFilePath+"/VC/SDK/v7.1A/Include",
- };
-
- String args[] = {
- "-D_M_IX86=300",
- "-D_MSC_VER=1200",
- "-D_INTEGRAL_MAX_BITS=32",
- "-DNTDDI_VERSION=0x09000000",
- "-DWINVER=0x0900",
- "-D_X86_",
- "-D_WIN32",
- "-DCRTDLL",
- "-D_USE_ATTRIBUTES_FOR_SAL",
- "-D_CRTBLD",
- "-D_OPENMP_NOFORCE_MANIFEST",
- "-DLPSKBINFO=LPARAM",
- "-DCONST=const",
- "-D_CRT_SECURE_NO_WARNINGS",
- "-D_CRT_NONSTDC_NO_DEPRECATE",
- "-D_CRT_NONSTDC_NO_WARNINGS",
- "-D_CRT_OBSOLETE_NO_DEPRECATE",
- "-D_ALLOW_KEYWORD_MACROS",
- "-D_ASSERT_OK",
- "-DSTRSAFE_NO_DEPRECATE",
- "-D__possibly_notnullterminated",
- "-Dtype_info=\"void *\"",
- "-D_ThrowInfo=ThrowInfo",
- "-v0",
- "-D__inner_checkReturn=",
- };
-
- parseHeaderFilesToGDT(outputDirectory, "windows_vs12_32_new", "x86:LE:32:default", "windows", filenames, includePaths, args);
- }
-
-
- public void parseGDT_VS12_64() throws Exception {
-
+ public void parseGDT_VS12_32() throws Exception {
+
String filenames[] = {
"sdkddkver.h",
"sal.h",
@@ -459,10 +243,11 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"mmdeviceapi.h",
"mprapi.h",
"msctfmonitorapi.h",
- "ndfapi.h",
+ "ndfapi.h",
"winsock2.h",
"ws2tcpip.h",
- "iphlpapi.h",
+ "iphlpapi.h",
+ "netioapi.h",
"npapi.h",
"nspapi.h",
"ntdsapi.h",
@@ -493,995 +278,1220 @@ public class CreateDefaultGDTArchivesScript extends GhidraScript {
"windowssideshowapi.h",
"wlanapi.h",
"wpapi.h",
- "wpcapi.h",
+ "wpcapi.h",
"wscapi.h",
"wsdapi.h",
"rpcproxy.h",
};
-
+
String includePaths[] = {
- headerFilePath+"/VC/VS12/src",
- headerFilePath+"/VC/VS12/include",
- headerFilePath+"/VC/SDK/v7.1A/Include",
+ headerFilePath + "/VC/VS12/src",
+ headerFilePath + "/VC/VS12/include",
+ headerFilePath + "/VC/SDK/v7.1A/Include",
};
-
+
String args[] = {
- "-D_MSC_VER=1200",
- "-D_INTEGRAL_MAX_BITS=64",
- "-D_WIN32_WINNT=0x601",
- "-DNTDDI_VERSION=0x06010000",
- "-DWINVER=0x0900",
- "-D_AMD64_",
- "-D_M_AMD64",
- "-D_M_X64",
- "-D_WIN64",
- "-D_WIN32",
- "-D_USE_ATTRIBUTES_FOR_SAL",
- "-D_CRTBLD",
- "-D_OPENMP_NOFORCE_MANIFEST",
- "-DLPSKBINFO=LPARAM",
- "-DCONST=const",
- "-D_CRT_SECURE_NO_WARNINGS",
- "-D_CRT_NONSTDC_NO_DEPRECATE",
- "-D_CRT_NONSTDC_NO_WARNINGS",
- "-D_CRT_OBSOLETE_NO_DEPRECATE",
- "-D_ALLOW_KEYWORD_MACROS",
- "-D_ASSERT_OK",
- "-DSTRSAFE_NO_DEPRECATE",
- "-D__possibly_notnullterminated",
- "-Dtype_info=\"void *\"",
- "-D_ThrowInfo=ThrowInfo",
- "-D__unaligned=",
- "-v0",
- "-D__inner_checkReturn=",
+ "-D_M_IX86=300",
+ "-D_MSC_VER=1200",
+ "-D_INTEGRAL_MAX_BITS=32",
+ "-DNTDDI_VERSION=0x09000000",
+ "-DWINVER=0x0900",
+ "-D_X86_",
+ "-D_WIN32",
+ "-DCRTDLL",
+ "-D_USE_ATTRIBUTES_FOR_SAL",
+ "-D_CRTBLD",
+ "-D_OPENMP_NOFORCE_MANIFEST",
+ "-DLPSKBINFO=LPARAM",
+ "-DCONST=const",
+ "-D_CRT_SECURE_NO_WARNINGS",
+ "-D_CRT_NONSTDC_NO_DEPRECATE",
+ "-D_CRT_NONSTDC_NO_WARNINGS",
+ "-D_CRT_OBSOLETE_NO_DEPRECATE",
+ "-D_ALLOW_KEYWORD_MACROS",
+ "-D_ASSERT_OK",
+ "-DSTRSAFE_NO_DEPRECATE",
+ "-D__possibly_notnullterminated",
+ "-Dtype_info=\"void *\"",
+ "-D_ThrowInfo=ThrowInfo",
+ "-v0",
+ "-D__inner_checkReturn=",
};
-
- parseHeaderFilesToGDT(outputDirectory, "windows_vs12_64_new", "x86:LE:64:default", "windows", filenames, includePaths, args);
+
+ parseHeaderFilesToGDT(outputDirectory, "windows_vs12_32_new", "x86:LE:32:default",
+ "windows", filenames, includePaths, args);
}
-
-
+
+ public void parseGDT_VS12_64() throws Exception {
+
+ String filenames[] = {
+ "sdkddkver.h",
+ "sal.h",
+ "assert.h",
+ "conio.h",
+ "crtdefs.h",
+ "crtdbg.h",
+ "crtwrn.h",
+ "ctype.h",
+ "basetsd.h",
+ "WinDef.h",
+ "WinNT.h",
+ "delayimp.h",
+ "direct.h",
+ "dos.h",
+ "errno.h",
+ "excpt.h",
+ "fcntl.h",
+ "float.h",
+ "fpieee.h",
+ "io.h",
+ "iso646.h",
+ "limits.h",
+ "locale.h",
+ "malloc.h",
+ "math.h",
+ "mbctype.h",
+ "mbstring.h",
+ "memory.h",
+ "minmax.h",
+ "new.h",
+ "omp.h",
+ "pgobootrun.h",
+ "process.h",
+ "rtcapi.h",
+ "search.h",
+ "setjmp.h",
+ "setjmpex.h",
+ "share.h",
+ "signal.h",
+ "srv.h",
+ "stdarg.h",
+ "stddef.h",
+ "stdexcpt.h",
+ "stdio.h",
+ "stdlib.h",
+ "string.h",
+ "tchar.h",
+ "time.h",
+ "use_ansi.h",
+ "vadefs.h",
+ "varargs.h",
+ "wchar.h",
+ "wctype.h",
+ "xlocinfo.h",
+ "xmath.h",
+ "ymath.h",
+ "yvals.h",
+ "CommDlg.h",
+ "WinUser.h",
+ "WinNls.h",
+ "internal.h",
+ "strsafe.h",
+ "align.h",
+ "awint.h",
+ "crtversion.h",
+ "cruntime.h",
+ "ctime.h",
+ "cvt.h",
+ "dbgint.h",
+ "ehdata.h",
+ "emmintrin.h",
+ "errmsg.h",
+ "fenv.h",
+ "file2.h",
+ "fltintrn.h",
+ "immintrin.h",
+ "internal_securecrt.h",
+ "inttypes.h",
+ "isa_availability.h",
+ "mbdata.h",
+ "msdos.h",
+ "mtdll.h",
+ "nlsdownlevel.h",
+ "nlsint.h",
+ "nmmintrin.h",
+ "oscalls.h",
+ "pmmintrin.h",
+ "rtcsup.h",
+ "rterr.h",
+ "sect_attribs.h",
+ "setlocal.h",
+ "smmintrin.h",
+ "stdbool.h",
+ "stdint.h",
+ "syserr.h",
+ "targetver.h",
+ "tmmintrin.h",
+ "winheap.h",
+ "wmmintrin.h",
+ "wrapwin.h",
+ "xkeycheck.h",
+ "xmmintrin.h",
+ "xmtx.h",
+ "xtgmath.h",
+ "xxcctype.h",
+ "xxdftype.h",
+ "xxfftype.h",
+ "xxlftype.h",
+ "xxwctype.h",
+ "xxxprec.h",
+ "shlobj.h",
+ "evntprov.h",
+ "uiautomation.h",
+ "aclapi.h",
+ "appcompatapi.h",
+ "capi.h",
+ "clusapi.h",
+ "cryptuiapi.h",
+ "cscapi.h",
+ "devpropdef.h",
+ "dhcpsapi.h",
+ "dwmapi.h",
+ "ehstorapi.h",
+ "functiondiscoveryapi.h",
+ "ipexport.h",
+ "icmpapi.h",
+ "iepmapi.h",
+ "imapi.h",
+ "ksopmapi.h",
+ "locationapi.h",
+ "lpmapi.h",
+ "mapi.h",
+ "mbnapi.h",
+ "mfapi.h",
+ "mgmtapi.h",
+ "mmdeviceapi.h",
+ "mprapi.h",
+ "msctfmonitorapi.h",
+ "ndfapi.h",
+ "winsock2.h",
+ "ws2tcpip.h",
+ "iphlpapi.h",
+ "npapi.h",
+ "nspapi.h",
+ "ntdsapi.h",
+ "ntmsapi.h",
+ "ntsecapi.h",
+ "patchapi.h",
+ "portabledeviceapi.h",
+ "portabledeviceconnectapi.h",
+ "propapi.h",
+ "psapi.h",
+ "rdpencomapi.h",
+ "resapi.h",
+ "sapi.h",
+ "searchapi.h",
+ "sensapi.h",
+ "sensorsapi.h",
+ "setupapi.h",
+ "shellapi.h",
+ "shlwapi.h",
+ "srrestoreptapi.h",
+ "svrapi.h",
+ "t2embapi.h",
+ "tapi.h",
+ "uiautomationcoreapi.h",
+ "wcnapi.h",
+ "wdsclientapi.h",
+ "werapi.h",
+ "windowssideshowapi.h",
+ "wlanapi.h",
+ "wpapi.h",
+ "wpcapi.h",
+ "wscapi.h",
+ "wsdapi.h",
+ "rpcproxy.h",
+ };
+
+ String includePaths[] = {
+ headerFilePath + "/VC/VS12/src",
+ headerFilePath + "/VC/VS12/include",
+ headerFilePath + "/VC/SDK/v7.1A/Include",
+ };
+
+ String args[] = {
+ "-D_MSC_VER=1200",
+ "-D_INTEGRAL_MAX_BITS=64",
+ "-D_WIN32_WINNT=0x601",
+ "-DNTDDI_VERSION=0x06010000",
+ "-DWINVER=0x0900",
+ "-D_AMD64_",
+ "-D_M_AMD64",
+ "-D_M_X64",
+ "-D_WIN64",
+ "-D_WIN32",
+ "-D_USE_ATTRIBUTES_FOR_SAL",
+ "-D_CRTBLD",
+ "-D_OPENMP_NOFORCE_MANIFEST",
+ "-DLPSKBINFO=LPARAM",
+ "-DCONST=const",
+ "-D_CRT_SECURE_NO_WARNINGS",
+ "-D_CRT_NONSTDC_NO_DEPRECATE",
+ "-D_CRT_NONSTDC_NO_WARNINGS",
+ "-D_CRT_OBSOLETE_NO_DEPRECATE",
+ "-D_ALLOW_KEYWORD_MACROS",
+ "-D_ASSERT_OK",
+ "-DSTRSAFE_NO_DEPRECATE",
+ "-D__possibly_notnullterminated",
+ "-Dtype_info=\"void *\"",
+ "-D_ThrowInfo=ThrowInfo",
+ "-D__unaligned=",
+ "-v0",
+ "-D__inner_checkReturn=",
+ };
+
+ parseHeaderFilesToGDT(outputDirectory, "windows_vs12_64_new", "x86:LE:64:default",
+ "windows", filenames, includePaths, args);
+ }
+
public void parseGDT_CLIB64() throws Exception {
-
+
String filenames[] = {
- "sys/types.h",
- "types.h",
- "stddef.h",
- "stddef.h",
- "openssl/opensslconf.h",
- "openssl/bn.h",
- "openssl/ssl.h",
- "openssl/asn1_mac.h",
- "openssl/asn1t.h",
- "openssl/blowfish.h",
- "openssl/camellia.h",
- "openssl/cast.h",
- "openssl/cmac.h",
- "openssl/cms.h",
- "openssl/conf_api.h",
- "openssl/des.h",
- "openssl/dso.h",
- "openssl/engine.h",
- "openssl/fips_rand.h",
- "openssl/idea.h",
- "openssl/krb5_asn.h",
- "openssl/md2.h",
- "openssl/md4.h",
- "openssl/md5.h",
- "openssl/ocsp.h",
- "openssl/pkcs12.h",
- "openssl/rc2.h",
- "openssl/rc4.h",
- "openssl/ripemd.h",
- "openssl/seed.h",
- "openssl/ssl3.h",
- "openssl/txt_db.h",
- "openssl/whrlpool.h",
- "aio.h",
- "arpa/inet.h",
- "cpio.h",
- "dirent.h",
- "fcntl.h",
- "fmtmsg.h",
- "fnmatch.h",
- "ftw.h",
- "glob.h",
- "grp.h",
- "iconv.h",
- "langinfo.h",
- "libgen.h",
- "monetary.h",
- "mqueue.h",
- "ndbm.h",
- "net/if.h",
- "netdb.h",
- "netinet/in.h",
- "netinet/tcp.h",
- "nl_types.h",
- "poll.h",
- "pthread.h",
- "pwd.h",
- "regex.h",
- "sched.h",
- "search.h",
- "semaphore.h",
- "spawn.h",
- "strings.h",
- "stropts.h",
- "sys/ipc.h",
- "sys/mman.h",
- "sys/msg.h",
- "sys/resource.h",
- "sys/select.h",
- "sys/sem.h",
- "sys/shm.h",
- "sys/socket.h",
- "sys/stat.h",
- "sys/statvfs.h",
- "sys/time.h",
- "sys/times.h",
- "sys/types.h",
- "sys/uio.h",
- "sys/un.h",
- "sys/utsname.h",
- "sys/wait.h",
- "syslog.h",
- "tar.h",
- "termios.h",
- "trace.h",
- "ulimit.h",
- "unistd.h",
- "utime.h",
- "utmpx.h",
- "wordexp.h",
- "assert.h",
- "complex.h",
- "ctype.h",
- "fenv.h",
- "float.h",
- "inttypes.h",
- "iso646.h",
- "limits.h",
- "locale.h",
- "math.h",
- "setjmp.h",
- "signal.h",
- "stdarg.h",
- "stdbool.h",
- "stddef.h",
- "stdint.h",
- "stdio.h",
- "stdlib.h",
- "string.h",
- "time.h",
- "wchar.h",
- "wctype.h",
- "sys/acct.h",
- "sys/debugreg.h",
- "sys/epoll.h",
- "sys/eventfd.h",
- "sys/fcntl.h",
- "sys/fsuid.h",
- "sys/gmon.h",
- "sys/gmon_out.h",
- "sys/inotify.h",
- "sys/io.h",
- "sys/kd.h",
- "sys/kdaemon.h",
- "sys/klog.h",
- "sys/mount.h",
- "sys/mtio.h",
- "sys/pci.h",
- "sys/perm.h",
- "sys/personality.h",
- "sys/prctl.h",
- "sys/profil.h",
- "sys/ptrace.h",
- "sys/quota.h",
- "sys/raw.h",
- "sys/reboot.h",
- "sys/reg.h",
- "sys/sem.h",
- "sys/sendfile.h",
- "sys/signal.h",
- "sys/signalfd.h",
- "sys/socketvar.h",
- "sys/soundcard.h",
- "sys/statvfs.h",
- "sys/swap.h",
- "sys/sysctl.h",
- "sys/sysinfo.h",
- "sys/termios.h",
- "sys/timerfd.h",
- "sys/ttychars.h",
- "sys/ultrasound.h",
- "sys/unistd.h",
- "sys/ustat.h",
- "sys/vfs.h",
- "sys/vlimit.h",
- "sys/vt.h",
- "sys/vtimes.h",
- "sys/xattr.h",
- "errno.h",
- "mathcalls.h",
- "net/ethernet.h",
- "net/if_arp.h",
- "net/if_ppp.h",
- "net/if_slip.h",
- "net/ppp_defs.h",
- "net/if.h",
- "net/if_packet.h",
- "net/if_shaper.h",
- "net/ppp-comp.h",
- "net/route.h",
- "netinet/ether.h",
- "netinet/if_fddi.h",
- "netinet/in.h ",
- "netinet/ip6.h",
- "netinet/udp.h",
- "netinet/icmp6.h",
- "netinet/if_tr.h",
- "netinet/in_systm.h",
- "netinet/ip_icmp.h",
- "netinet/if_ether.h",
- "netinet/igmp.h",
- "netinet/ip.h",
- "netinet/tcp.h",
- "rpc/types.h",
- "rpc/auth.h",
- "rpc/des_crypt.h",
- "rpc/pmap_prot.h",
- "rpc/rpc_msg.h",
- "rpc/xdr.h",
- "rpc/auth_des.h",
- "rpc/key_prot.h",
- "rpc/pmap_rmt.h",
- "rpc/svc.h",
- "rpc/auth_unix.h",
- "rpc/netdb.h",
- "rpc/rpc.h",
- "rpc/svc_auth.h",
- "rpc/clnt.h",
- "rpc/pmap_clnt.h",
- "rpc/rpc_des.h",
- "rpcsvc/bootparam.h",
- "rpcsvc/nis_callback.h",
- "rpcsvc/yp_prot.h",
- "rpcsvc/rstat.h",
- "rpcsvc/rusers.h",
- "rpcsvc/spray.h",
- "rpcsvc/ypupd.h",
- "rpcsvc/mount.h",
- "rpcsvc/nis.h",
- "protocols/routed.h",
- "protocols/rwhod.h",
- "protocols/talkd.h",
- "protocols/timed.h",
- "arpa/ftp.h",
- "arpa/inet.h",
- "arpa/nameser.h",
- "arpa/nameser_compat.h",
- "arpa/telnet.h",
- "arpa/tftp.h",
+ "sys/types.h",
+ "types.h",
+ "stddef.h",
+ "stddef.h",
+ "openssl/opensslconf.h",
+ "openssl/bn.h",
+ "openssl/ssl.h",
+ "openssl/asn1_mac.h",
+ "openssl/asn1t.h",
+ "openssl/blowfish.h",
+ "openssl/camellia.h",
+ "openssl/cast.h",
+ "openssl/cmac.h",
+ "openssl/cms.h",
+ "openssl/conf_api.h",
+ "openssl/des.h",
+ "openssl/dso.h",
+ "openssl/engine.h",
+ "openssl/fips_rand.h",
+ "openssl/idea.h",
+ "openssl/krb5_asn.h",
+ "openssl/md2.h",
+ "openssl/md4.h",
+ "openssl/md5.h",
+ "openssl/ocsp.h",
+ "openssl/pkcs12.h",
+ "openssl/rc2.h",
+ "openssl/rc4.h",
+ "openssl/ripemd.h",
+ "openssl/seed.h",
+ "openssl/ssl3.h",
+ "openssl/txt_db.h",
+ "openssl/whrlpool.h",
+ "aio.h",
+ "arpa/inet.h",
+ "cpio.h",
+ "dirent.h",
+ "fcntl.h",
+ "fmtmsg.h",
+ "fnmatch.h",
+ "ftw.h",
+ "glob.h",
+ "grp.h",
+ "iconv.h",
+ "langinfo.h",
+ "libgen.h",
+ "monetary.h",
+ "mqueue.h",
+ "ndbm.h",
+ "net/if.h",
+ "netdb.h",
+ "netinet/in.h",
+ "netinet/tcp.h",
+ "nl_types.h",
+ "poll.h",
+ "pthread.h",
+ "pwd.h",
+ "regex.h",
+ "sched.h",
+ "search.h",
+ "semaphore.h",
+ "spawn.h",
+ "strings.h",
+ "stropts.h",
+ "sys/ipc.h",
+ "sys/mman.h",
+ "sys/msg.h",
+ "sys/resource.h",
+ "sys/select.h",
+ "sys/sem.h",
+ "sys/shm.h",
+ "sys/socket.h",
+ "sys/stat.h",
+ "sys/statvfs.h",
+ "sys/time.h",
+ "sys/times.h",
+ "sys/types.h",
+ "sys/uio.h",
+ "sys/un.h",
+ "sys/utsname.h",
+ "sys/wait.h",
+ "syslog.h",
+ "tar.h",
+ "termios.h",
+ "trace.h",
+ "ulimit.h",
+ "unistd.h",
+ "utime.h",
+ "utmpx.h",
+ "wordexp.h",
+ "assert.h",
+ "complex.h",
+ "ctype.h",
+ "fenv.h",
+ "float.h",
+ "inttypes.h",
+ "iso646.h",
+ "limits.h",
+ "locale.h",
+ "math.h",
+ "setjmp.h",
+ "signal.h",
+ "stdarg.h",
+ "stdbool.h",
+ "stddef.h",
+ "stdint.h",
+ "stdio.h",
+ "stdlib.h",
+ "string.h",
+ "time.h",
+ "wchar.h",
+ "wctype.h",
+ "sys/acct.h",
+ "sys/debugreg.h",
+ "sys/epoll.h",
+ "sys/eventfd.h",
+ "sys/fcntl.h",
+ "sys/fsuid.h",
+ "sys/gmon.h",
+ "sys/gmon_out.h",
+ "sys/inotify.h",
+ "sys/io.h",
+ "sys/kd.h",
+ "sys/kdaemon.h",
+ "sys/klog.h",
+ "sys/mount.h",
+ "sys/mtio.h",
+ "sys/pci.h",
+ "sys/perm.h",
+ "sys/personality.h",
+ "sys/prctl.h",
+ "sys/profil.h",
+ "sys/ptrace.h",
+ "sys/quota.h",
+ "sys/raw.h",
+ "sys/reboot.h",
+ "sys/reg.h",
+ "sys/sem.h",
+ "sys/sendfile.h",
+ "sys/signal.h",
+ "sys/signalfd.h",
+ "sys/socketvar.h",
+ "sys/soundcard.h",
+ "sys/statvfs.h",
+ "sys/swap.h",
+ "sys/sysctl.h",
+ "sys/sysinfo.h",
+ "sys/termios.h",
+ "sys/timerfd.h",
+ "sys/ttychars.h",
+ "sys/ultrasound.h",
+ "sys/unistd.h",
+ "sys/ustat.h",
+ "sys/vfs.h",
+ "sys/vlimit.h",
+ "sys/vt.h",
+ "sys/vtimes.h",
+ "sys/xattr.h",
+ "errno.h",
+ "mathcalls.h",
+ "net/ethernet.h",
+ "net/if_arp.h",
+ "net/if_ppp.h",
+ "net/if_slip.h",
+ "net/ppp_defs.h",
+ "net/if.h",
+ "net/if_packet.h",
+ "net/if_shaper.h",
+ "net/ppp-comp.h",
+ "net/route.h",
+ "netinet/ether.h",
+ "netinet/if_fddi.h",
+ "netinet/in.h ",
+ "netinet/ip6.h",
+ "netinet/udp.h",
+ "netinet/icmp6.h",
+ "netinet/if_tr.h",
+ "netinet/in_systm.h",
+ "netinet/ip_icmp.h",
+ "netinet/if_ether.h",
+ "netinet/igmp.h",
+ "netinet/ip.h",
+ "netinet/tcp.h",
+ "rpc/types.h",
+ "rpc/auth.h",
+ "rpc/des_crypt.h",
+ "rpc/pmap_prot.h",
+ "rpc/rpc_msg.h",
+ "rpc/xdr.h",
+ "rpc/auth_des.h",
+ "rpc/key_prot.h",
+ "rpc/pmap_rmt.h",
+ "rpc/svc.h",
+ "rpc/auth_unix.h",
+ "rpc/netdb.h",
+ "rpc/rpc.h",
+ "rpc/svc_auth.h",
+ "rpc/clnt.h",
+ "rpc/pmap_clnt.h",
+ "rpc/rpc_des.h",
+ "rpcsvc/bootparam.h",
+ "rpcsvc/nis_callback.h",
+ "rpcsvc/yp_prot.h",
+ "rpcsvc/rstat.h",
+ "rpcsvc/rusers.h",
+ "rpcsvc/spray.h",
+ "rpcsvc/ypupd.h",
+ "rpcsvc/mount.h",
+ "rpcsvc/nis.h",
+ "protocols/routed.h",
+ "protocols/rwhod.h",
+ "protocols/talkd.h",
+ "protocols/timed.h",
+ "arpa/ftp.h",
+ "arpa/inet.h",
+ "arpa/nameser.h",
+ "arpa/nameser_compat.h",
+ "arpa/telnet.h",
+ "arpa/tftp.h",
};
-
+
String includePaths[] = {
- headerFilePath+"/linux/include",
- headerFilePath+"/linux/include/sys",
- headerFilePath+"/linux/gcc/include",
- headerFilePath+"/linux/include/openssl",
- headerFilePath+"/linux/x86_64-redhat-linux5E/include",
- headerFilePath+"/linux/x86_64-redhat-linux5E/include/sys",
+ headerFilePath + "/linux/include",
+ headerFilePath + "/linux/include/sys",
+ headerFilePath + "/linux/gcc/include",
+ headerFilePath + "/linux/include/openssl",
+ headerFilePath + "/linux/x86_64-redhat-linux5E/include",
+ headerFilePath + "/linux/x86_64-redhat-linux5E/include/sys",
};
-
+
String args[] = {
- "-D_X86_",
- "-D__x86_64__",
- "-D__STDC__",
- "-D_GNU_SOURCE",
- "-D__WORDSIZE=64",
- "-D__builtin_va_list=void *",
- "-D__DO_NOT_DEFINE_COMPILE",
- "-D_Complex",
- "-D__NO_STRING_INLINES",
- "-D__signed__",
- "-D__extension__=",
- "-D__GLIBC_HAVE_LONG_LONG=1",
- "-D__need_sigset_t",
- "-Daligned_u64=uint64_t",
+ "-D_X86_",
+ "-D__x86_64__",
+ "-D__STDC__",
+ "-D_GNU_SOURCE",
+ "-D__WORDSIZE=64",
+ "-D__builtin_va_list=void *",
+ "-D__DO_NOT_DEFINE_COMPILE",
+ "-D_Complex",
+ "-D__NO_STRING_INLINES",
+ "-D__signed__",
+ "-D__extension__=",
+ "-D__GLIBC_HAVE_LONG_LONG=1",
+ "-D__need_sigset_t",
+ "-Daligned_u64=uint64_t",
};
-
- parseHeaderFilesToGDT(outputDirectory, "generic_clib_64_new", "x86:LE:64:default", "gcc", filenames, includePaths, args);
+
+ parseHeaderFilesToGDT(outputDirectory, "generic_clib_64_new", "x86:LE:64:default", "gcc",
+ filenames, includePaths, args);
}
-
-
+
public void parseGDT_CLIB32() throws Exception {
-
- String filenames[] = {
- "sys/types.h",
- "types.h",
- "stddef.h",
- "stddef.h",
- "openssl/opensslconf.h",
- "openssl/des.h",
- "openssl/bn.h",
- "openssl/ssl.h",
- "openssl/asn1_mac.h",
- "openssl/asn1t.h",
- "openssl/blowfish.h",
- "openssl/camellia.h",
- "openssl/cast.h",
- "openssl/cmac.h",
- "openssl/cms.h",
- "openssl/conf_api.h",
- "openssl/dso.h",
- "openssl/engine.h",
- "openssl/fips_rand.h",
- "openssl/idea.h",
- "openssl/krb5_asn.h",
- "openssl/md2.h",
- "openssl/md4.h",
- "openssl/md5.h",
- "openssl/ocsp.h",
- "openssl/pkcs12.h",
- "openssl/rc2.h",
- "openssl/rc4.h",
- "openssl/ripemd.h",
- "openssl/seed.h",
- "openssl/ssl3.h",
- "openssl/txt_db.h",
- "openssl/whrlpool.h",
- "aio.h",
- "arpa/inet.h",
- "cpio.h",
- "dirent.h",
- "fcntl.h",
- "fmtmsg.h",
- "fnmatch.h",
- "ftw.h",
- "glob.h",
- "grp.h",
- "iconv.h",
- "langinfo.h",
- "libgen.h",
- "monetary.h",
- "mqueue.h",
- "ndbm.h",
- "net/if.h",
- "netdb.h",
- "netinet/in.h",
- "netinet/tcp.h",
- "nl_types.h",
- "poll.h",
- "pthread.h",
- "pwd.h",
- "regex.h",
- "sched.h",
- "search.h",
- "semaphore.h",
- "spawn.h",
- "strings.h",
- "stropts.h",
- "sys/ipc.h",
- "sys/mman.h",
- "sys/msg.h",
- "sys/resource.h",
- "sys/select.h",
- "sys/sem.h",
- "sys/shm.h",
- "sys/socket.h",
- "sys/stat.h",
- "sys/statvfs.h",
- "sys/time.h",
- "sys/times.h",
- "sys/types.h",
- "sys/uio.h",
- "sys/un.h",
- "sys/utsname.h",
- "sys/wait.h",
- "syslog.h",
- "tar.h",
- "termios.h",
- "trace.h",
- "ulimit.h",
- "unistd.h",
- "utime.h",
- "utmpx.h",
- "wordexp.h",
- "assert.h",
- "complex.h",
- "ctype.h",
- "fenv.h",
- "float.h",
- "inttypes.h",
- "iso646.h",
- "limits.h",
- "locale.h",
- "math.h",
- "setjmp.h",
- "signal.h",
- "stdarg.h",
- "stdbool.h",
- "stddef.h",
- "stdint.h",
- "stdio.h",
- "stdlib.h",
- "string.h",
- "time.h",
- "wchar.h",
- "wctype.h",
- "sys/acct.h",
- "sys/debugreg.h",
- "sys/epoll.h",
- "sys/eventfd.h",
- "sys/fcntl.h",
- "sys/fsuid.h",
- "sys/gmon.h",
- "sys/gmon_out.h",
- "sys/inotify.h",
- "sys/io.h",
- "sys/kd.h",
- "sys/kdaemon.h",
- "sys/klog.h",
- "sys/mount.h",
- "sys/mtio.h",
- "sys/pci.h",
- "sys/perm.h",
- "sys/personality.h",
- "sys/prctl.h",
- "sys/profil.h",
- "sys/ptrace.h",
- "sys/quota.h",
- "sys/raw.h",
- "sys/reboot.h",
- "sys/reg.h",
- "sys/sem.h",
- "sys/sendfile.h",
- "sys/signal.h",
- "sys/signalfd.h",
- "sys/socketvar.h",
- "sys/soundcard.h",
- "sys/statvfs.h",
- "sys/swap.h",
- "sys/sysctl.h",
- "sys/sysinfo.h",
- "sys/termios.h",
- "sys/timerfd.h",
- "sys/ttychars.h",
- "sys/ultrasound.h",
- "sys/unistd.h",
- "sys/ustat.h",
- "sys/vfs.h",
- "sys/vlimit.h",
- "sys/vt.h",
- "sys/vtimes.h",
- "sys/xattr.h",
- "errno.h",
- "mathcalls.h",
- "net/ethernet.h",
- "net/if_arp.h",
- "net/if_ppp.h",
- "net/if_slip.h",
- "net/ppp_defs.h",
- "net/if.h",
- "net/if_packet.h",
- "net/if_shaper.h",
- "net/ppp-comp.h",
- "net/route.h",
- "netinet/ether.h",
- "netinet/if_fddi.h",
- "netinet/in.h ",
- "netinet/ip6.h",
- "netinet/udp.h",
- "netinet/icmp6.h",
- "netinet/if_tr.h",
- "netinet/in_systm.h",
- "netinet/ip_icmp.h",
- "netinet/if_ether.h",
- "netinet/igmp.h",
- "netinet/ip.h",
- "netinet/tcp.h",
- "rpc/types.h",
- "rpc/auth.h",
- "rpc/des_crypt.h",
- "rpc/pmap_prot.h",
- "rpc/rpc_msg.h",
- "rpc/xdr.h",
- "rpc/auth_des.h",
- "rpc/key_prot.h",
- "rpc/pmap_rmt.h",
- "rpc/svc.h",
- "rpc/auth_unix.h",
- "rpc/netdb.h",
- "rpc/rpc.h",
- "rpc/svc_auth.h",
- "rpc/clnt.h",
- "rpc/pmap_clnt.h",
- "rpc/rpc_des.h",
- "rpcsvc/bootparam.h",
- "rpcsvc/nis_callback.h",
- "rpcsvc/yp_prot.h",
- "rpcsvc/rstat.h",
- "rpcsvc/rusers.h",
- "rpcsvc/spray.h",
- "rpcsvc/ypupd.h",
- "rpcsvc/mount.h",
- "rpcsvc/nis.h",
- "protocols/routed.h",
- "protocols/rwhod.h",
- "protocols/talkd.h",
- "protocols/timed.h",
- "arpa/ftp.h",
- "arpa/inet.h",
- "arpa/nameser.h",
- "arpa/nameser_compat.h",
- "arpa/telnet.h",
- "arpa/tftp.h",
- };
-
- String includePaths[] = {
- headerFilePath+"/linux/include",
- headerFilePath+"/linux/include/sys",
- headerFilePath+"/linux/gcc/include",
- headerFilePath+"/linux/include/openssl",
- headerFilePath+"/linux/x86_64-redhat-linux5E/include",
- headerFilePath+"/linux/x86_64-redhat-linux5E/include/sys",
- };
-
- String args[] = {
- "-D_X86_",
- "-D__i386__",
- "-D__STDC__",
- "-D_GNU_SOURCE",
- "-D__WORDSIZE=32",
- "-D__builtin_va_list=void *",
- "-D__DO_NOT_DEFINE_COMPILE",
- "-D_Complex",
- "-D__NO_STRING_INLINES",
- "-D__NO_LONG_DOUBLE_MATH",
- "-D__signed__",
- "-D__extension__=",
- "-D__GLIBC_HAVE_LONG_LONG=1",
- "-Daligned_u64=uint64_t",
- };
-
- parseHeaderFilesToGDT(outputDirectory, "generic_clib_new", "x86:LE:32:default", "gcc", filenames, includePaths, args);
- }
-
- public void parseGDT_WinVS22() throws Exception {
-
String filenames[] = {
- "# Core necessary files",
- "winapifamily.h",
- "winpackagefamily.h",
- "sdkddkver.h",
- "sal.h",
- "no_sal2.h",
- "corecrt.h",
- "wtypes.h",
- "winnt.h",
- "winternl.h",
- "#ntdef.h",
-
- "# Common headers ",
- "dos.h",
- "errno.h",
- "malloc.h",
- "signal.h",
- "stdalign.h",
- "stddef.h",
- "stdio.h",
- "stdlib.h",
- "assert.h",
- "crtdbg.h",
- "ctype.h",
- "conio.h",
- "direct.h",
- "fcntl.h",
- "float.h",
- "fpieee.h",
- "inttypes.h",
- "io.h",
- "locale.h",
- "complex.h",
- "math.h",
- "mbctype.h",
- "mbstring.h",
- "memory.h",
- "minmax.h",
- "new.h",
- "process.h",
- "search.h",
- "share.h",
- "winbase.h",
- "winuser.h",
- "Windows.h",
-
- "# Security and identity (https://docs.microsoft.com/en-us/windows/win32/api/_security/)",
- "accctrl.h",
- "aclapi.h",
- "aclui.h",
- "adtgen.h",
- "authz.h",
- "azroles.h",
- "bcrypt.h",
- "casetup.h",
- "ccgplugins.h",
- "celib.h",
- "ntlsa.h",
- "sspi.h",
- "ntsecapi.h",
- "ntsecpkg.h",
- "schannel.h",
- "certadm.h",
- "certbcli.h",
- "certcli.h",
- "certenroll.h",
- "certexit.h",
- "certif.h",
- "certmod.h",
- "certpol.h",
- "CertPolEng.h",
- "certsrv.h",
- "certview.h",
- "credssp.h",
- "cryptdlg.h",
- "cryptuiapi.h",
- "cryptxml.h",
- "diagnosticdataquery.h",
- "diagnosticdataquerytypes.h",
- "dpapi.h",
- "dssec.h",
- "iads.h",
- "IdentityCommon.h",
- "IdentityProvider.h",
- "identitystore.h",
- "keycredmgr.h",
- "lmaccess.h",
- "lsalookup.h",
- "mmcobj.h",
- "mscat.h",
- "mssip.h",
- "namedpipeapi.h",
- "ncrypt.h",
- "ncryptprotect.h",
- "npapi.h",
- "processthreadsapi.h",
- "sas.h",
- "scesvc.h",
- "sddl.h",
- "securityappcontainer.h",
- "securitybaseapi.h",
- "slpublic.h",
- "subauth.h",
- "tokenbinding.h",
- "tpmvscmgr.h",
- "wincred.h",
- "wincrypt.h",
- "winnetwk.h",
- "winreg.h",
- "winsafer.h",
- "winscard.h",
- "winsvc.h",
- "wintrust.h",
- "winwlx.h",
- "xenroll.h",
-
- "# Windows sockets",
- "af_irda.h",
- "in6addr.h",
- "mstcpip.h",
- "winsock2.h",
- "nsemail.h",
- "nspapi.h",
- "socketapi.h",
- "# Nothing includes this; is it necessary?",
- "#sporder.h",
- "transportsettingcommon.h",
- "ws2atm.h",
- "ws2spi.h",
- "MSWSock.h",
- "ws2tcpip.h",
- "wsipv6ok.h",
- "WSNwLink.h",
- "wsrm.h",
- "mswsockdef.h",
-
- "# Remote Procedure Call (RPC)",
- "midles.h",
- "midlbase.h",
- "rpc.h",
- "rpcndr.h",
- "rpcasync.h",
- "rpcdcep.h",
- "rpcnsi.h",
- "rpcproxy.h",
- "rpcssl.h",
-
- "# COM",
- "accctrl.h",
- "callobj.h",
- "combaseapi.h",
- "comcat.h",
- "ctxtcall.h",
- "dmerror.h",
- "docobj.h",
- "eventsys.h",
- "initguid.h",
- "guiddef.h",
- "iaccess.h",
- "hstring.h",
- "IMessageDispatcher.h",
- "MessageDispatcherApi.h",
- "objbase.h",
- "objidlbase.h",
- "objidl.h",
- "ocidl.h",
- "ole.h",
- "ole2.h",
- "oledlg.h",
- "oleidl.h",
- "roapi.h",
- "rpcdce.h",
- "servprov.h",
- "shobjidl.h",
- "txlogpub.h",
- "unknwnbase.h",
- "unknwn.h",
- "urlmon.h",
- "vbinterf.h",
- "winddi.h",
- "winerror.h",
- "wtypesbase.h",
-
- "# COM+",
- "comadmin.h",
- "mtxdm.h",
-
- "# More",
- "inspectable.h",
-
- "# Windows Internet",
- "proofofpossessioncookieinfo.h",
- "wininet.h",
- "winineti.h",
-
- "# Windows HTTP Services",
- "winhttp.h",
-
- "# Compression",
- "compressapi.h",
-
- "# TraceLogging",
- "#traceloggingactivity.h",
- "#traceloggingprovider.h",
-
- "# Windows Error Reporting",
- "errorrep.h",
- "werapi.h",
-
- "# Windows and MEssages",
- "olectl.h",
- "windef.h",
- "windowsx.h",
-
- "# Shell",
- "appmgmt.h",
- "appnotify.h",
- "cpl.h",
- "credentialprovider.h",
- "dimm.h",
- "imagetranscode.h",
- "inputpanelconfiguration.h",
- "intsafe.h",
- "intshcut.h",
- "mobsync.h",
- "objectarray.h",
- "pathcch.h",
- "profinfo.h",
- "propkeydef.h",
- "scrnsave.h",
- "shappmgr.h",
- "shdeprecated.h",
- "shidfact.h",
- "shimgdata.h",
- "shlwapi.h",
- "shtypes.h",
- "storageprovider.h",
- "syncmgr.h",
- "thumbcache.h",
- "thumbnailstreamcache.h",
- "tlogstg.h",
- "UserEnv.h",
-
- "# Windows Controls",
- "commctrl.h",
- "commoncontrols.h",
- "dpa_dsa.h",
- "prsht.h",
- "richedit.h",
- "richole.h",
- "shlobj_core.h",
- "shlobj.h",
- "#textserv.h", // C++
- "tom.h",
- "uxtheme.h",
-
- "# Menus and other resources",
- "resourceindexer.h",
- "strsafe.h",
- "verrsrc.h",
- "winver.h",
-
- "# Windows Accessibility Features",
- "oleacc.h",
- "uiautomationcore.h",
- "uiautomationclient.h",
- "uiautomationcoreapi.h",
-
- "# Internationalization",
- "datetimeapi.h",
- "elscore.h",
- "gb18030.h",
- "imepad.h",
- "imm.h",
- "immdev.h",
- "msime.h",
- "msimeapi.h",
- "muiload.h",
- "spellcheck.h",
- "spellcheckprovider.h",
- "stringapiset.h",
- "usp10.h",
- "winnls.h",
-
- "# HTTP Server API",
- "#http.h", // included by something else
-
- "# IP Helper",
- "#icmpapi.h", // Something wrong with IP_ADDR
- "ifdef.h",
- "inaddr.h",
- "ip2string.h",
- "ipexport.h",
- "iphlpapi.h",
- "iprtrmib.h",
- "iptypes.h",
- "nldef.h",
- "tcpestats.h",
-
- "# Network Management",
- "atacct.h",
- "lmalert.h",
- "lmapibuf.h",
- "lmat.h",
- "lmaudit.h",
- "lmconfig.h",
- "lmerrlog.h",
- "lmjoin.h",
- "lmmsg.h",
- "lmremutl.h",
- "lmserver.h",
- "lmsvc.h",
- "lmuse.h",
- "lmwksta.h"
+ "sys/types.h",
+ "types.h",
+ "stddef.h",
+ "stddef.h",
+ "openssl/opensslconf.h",
+ "openssl/des.h",
+ "openssl/bn.h",
+ "openssl/ssl.h",
+ "openssl/asn1_mac.h",
+ "openssl/asn1t.h",
+ "openssl/blowfish.h",
+ "openssl/camellia.h",
+ "openssl/cast.h",
+ "openssl/cmac.h",
+ "openssl/cms.h",
+ "openssl/conf_api.h",
+ "openssl/dso.h",
+ "openssl/engine.h",
+ "openssl/fips_rand.h",
+ "openssl/idea.h",
+ "openssl/krb5_asn.h",
+ "openssl/md2.h",
+ "openssl/md4.h",
+ "openssl/md5.h",
+ "openssl/ocsp.h",
+ "openssl/pkcs12.h",
+ "openssl/rc2.h",
+ "openssl/rc4.h",
+ "openssl/ripemd.h",
+ "openssl/seed.h",
+ "openssl/ssl3.h",
+ "openssl/txt_db.h",
+ "openssl/whrlpool.h",
+ "aio.h",
+ "arpa/inet.h",
+ "cpio.h",
+ "dirent.h",
+ "fcntl.h",
+ "fmtmsg.h",
+ "fnmatch.h",
+ "ftw.h",
+ "glob.h",
+ "grp.h",
+ "iconv.h",
+ "langinfo.h",
+ "libgen.h",
+ "monetary.h",
+ "mqueue.h",
+ "ndbm.h",
+ "net/if.h",
+ "netdb.h",
+ "netinet/in.h",
+ "netinet/tcp.h",
+ "nl_types.h",
+ "poll.h",
+ "pthread.h",
+ "pwd.h",
+ "regex.h",
+ "sched.h",
+ "search.h",
+ "semaphore.h",
+ "spawn.h",
+ "strings.h",
+ "stropts.h",
+ "sys/ipc.h",
+ "sys/mman.h",
+ "sys/msg.h",
+ "sys/resource.h",
+ "sys/select.h",
+ "sys/sem.h",
+ "sys/shm.h",
+ "sys/socket.h",
+ "sys/stat.h",
+ "sys/statvfs.h",
+ "sys/time.h",
+ "sys/times.h",
+ "sys/types.h",
+ "sys/uio.h",
+ "sys/un.h",
+ "sys/utsname.h",
+ "sys/wait.h",
+ "syslog.h",
+ "tar.h",
+ "termios.h",
+ "trace.h",
+ "ulimit.h",
+ "unistd.h",
+ "utime.h",
+ "utmpx.h",
+ "wordexp.h",
+ "assert.h",
+ "complex.h",
+ "ctype.h",
+ "fenv.h",
+ "float.h",
+ "inttypes.h",
+ "iso646.h",
+ "limits.h",
+ "locale.h",
+ "math.h",
+ "setjmp.h",
+ "signal.h",
+ "stdarg.h",
+ "stdbool.h",
+ "stddef.h",
+ "stdint.h",
+ "stdio.h",
+ "stdlib.h",
+ "string.h",
+ "time.h",
+ "wchar.h",
+ "wctype.h",
+ "sys/acct.h",
+ "sys/debugreg.h",
+ "sys/epoll.h",
+ "sys/eventfd.h",
+ "sys/fcntl.h",
+ "sys/fsuid.h",
+ "sys/gmon.h",
+ "sys/gmon_out.h",
+ "sys/inotify.h",
+ "sys/io.h",
+ "sys/kd.h",
+ "sys/kdaemon.h",
+ "sys/klog.h",
+ "sys/mount.h",
+ "sys/mtio.h",
+ "sys/pci.h",
+ "sys/perm.h",
+ "sys/personality.h",
+ "sys/prctl.h",
+ "sys/profil.h",
+ "sys/ptrace.h",
+ "sys/quota.h",
+ "sys/raw.h",
+ "sys/reboot.h",
+ "sys/reg.h",
+ "sys/sem.h",
+ "sys/sendfile.h",
+ "sys/signal.h",
+ "sys/signalfd.h",
+ "sys/socketvar.h",
+ "sys/soundcard.h",
+ "sys/statvfs.h",
+ "sys/swap.h",
+ "sys/sysctl.h",
+ "sys/sysinfo.h",
+ "sys/termios.h",
+ "sys/timerfd.h",
+ "sys/ttychars.h",
+ "sys/ultrasound.h",
+ "sys/unistd.h",
+ "sys/ustat.h",
+ "sys/vfs.h",
+ "sys/vlimit.h",
+ "sys/vt.h",
+ "sys/vtimes.h",
+ "sys/xattr.h",
+ "errno.h",
+ "mathcalls.h",
+ "net/ethernet.h",
+ "net/if_arp.h",
+ "net/if_ppp.h",
+ "net/if_slip.h",
+ "net/ppp_defs.h",
+ "net/if.h",
+ "net/if_packet.h",
+ "net/if_shaper.h",
+ "net/ppp-comp.h",
+ "net/route.h",
+ "netinet/ether.h",
+ "netinet/if_fddi.h",
+ "netinet/in.h ",
+ "netinet/ip6.h",
+ "netinet/udp.h",
+ "netinet/icmp6.h",
+ "netinet/if_tr.h",
+ "netinet/in_systm.h",
+ "netinet/ip_icmp.h",
+ "netinet/if_ether.h",
+ "netinet/igmp.h",
+ "netinet/ip.h",
+ "netinet/tcp.h",
+ "rpc/types.h",
+ "rpc/auth.h",
+ "rpc/des_crypt.h",
+ "rpc/pmap_prot.h",
+ "rpc/rpc_msg.h",
+ "rpc/xdr.h",
+ "rpc/auth_des.h",
+ "rpc/key_prot.h",
+ "rpc/pmap_rmt.h",
+ "rpc/svc.h",
+ "rpc/auth_unix.h",
+ "rpc/netdb.h",
+ "rpc/rpc.h",
+ "rpc/svc_auth.h",
+ "rpc/clnt.h",
+ "rpc/pmap_clnt.h",
+ "rpc/rpc_des.h",
+ "rpcsvc/bootparam.h",
+ "rpcsvc/nis_callback.h",
+ "rpcsvc/yp_prot.h",
+ "rpcsvc/rstat.h",
+ "rpcsvc/rusers.h",
+ "rpcsvc/spray.h",
+ "rpcsvc/ypupd.h",
+ "rpcsvc/mount.h",
+ "rpcsvc/nis.h",
+ "protocols/routed.h",
+ "protocols/rwhod.h",
+ "protocols/talkd.h",
+ "protocols/timed.h",
+ "arpa/ftp.h",
+ "arpa/inet.h",
+ "arpa/nameser.h",
+ "arpa/nameser_compat.h",
+ "arpa/telnet.h",
+ "arpa/tftp.h",
};
String includePaths[] = {
- headerFilePath+"/VC/VS22/Community/VC/Tools/MSVC/14.29.30133/include",
- headerFilePath+"/VC/SDK/10/Include/10.0.22000.0/shared",
- headerFilePath+"/VC/SDK/10/Include/10.0.22000.0/um",
- headerFilePath+"/VC/SDK/10/Include/10.0.22000.0/km",
- headerFilePath+"/VC/VS22/10.0.19041.0/shared",
- headerFilePath+"/VC/VS22/10.0.19041.0/um",
- headerFilePath+"/VC/VS22/10.0.19041.0/ucrt",
- headerFilePath+"/VC/VS22/10.0.19041.0/winrt",
+ headerFilePath + "/linux/include",
+ headerFilePath + "/linux/include/sys",
+ headerFilePath + "/linux/gcc/include",
+ headerFilePath + "/linux/include/openssl",
+ headerFilePath + "/linux/x86_64-redhat-linux5E/include",
+ headerFilePath + "/linux/x86_64-redhat-linux5E/include/sys",
};
-
+
String args[] = {
- "-D_MSC_VER=1924",
- "-D_INTEGRAL_MAX_BITS=64",
- "-DWINVER=0x0a00",
- "-D_WIN32_WINNT=0x0a00",
- "-D_AMD64_",
- "-D_M_AMD64",
- "-D_M_X64",
- "-D_WIN64",
- "-D_WIN32",
- "-D_USE_ATTRIBUTES_FOR_SAL",
- "-D_CRTBLD",
- "-D_OPENMP_NOFORCE_MANIFEST",
- "-DLPSKBINFO=LPARAM",
- "-DCONST=const",
- "-D_CRT_SECURE_NO_WARNINGS",
- "-D_CRT_NONSTDC_NO_DEPRECATE",
- "-D_CRT_NONSTDC_NO_WARNINGS",
- "-D_CRT_OBSOLETE_NO_DEPRECATE",
- "-D_ALLOW_KEYWORD_MACROS",
- "-D_ASSERT_OK",
- "-DSTRSAFE_NO_DEPRECATE",
- "-D__possibly_notnullterminated",
- "-Dtype_info=\"void *\"",
- "-D_ThrowInfo=ThrowInfo",
- "-D__unaligned=",
- "-v0",
- "-D__inner_checkReturn=",
- "-DDECLSPEC_DEPRECATED_DDK",
- "-DWINAPI_PARTITION_APP=1",
- "-DWINAPI_PARTITION_SYSTEM=1",
- "-DWINAPI_PARTITION_GAMES=1",
- "-DSECURITY_WIN32",
- "-DSIZE_T=size_t",
+ "-D_X86_",
+ "-D__i386__",
+ "-D__STDC__",
+ "-D_GNU_SOURCE",
+ "-D__WORDSIZE=32",
+ "-D__builtin_va_list=void *",
+ "-D__DO_NOT_DEFINE_COMPILE",
+ "-D_Complex",
+ "-D__NO_STRING_INLINES",
+ "-D__NO_LONG_DOUBLE_MATH",
+ "-D__signed__",
+ "-D__extension__=",
+ "-D__GLIBC_HAVE_LONG_LONG=1",
+ "-Daligned_u64=uint64_t",
};
-
- parseHeaderFilesToGDT(outputDirectory, "windows_vs22_64_new", "x86:LE:64:default", "windows", filenames, includePaths, args);
+
+ parseHeaderFilesToGDT(outputDirectory, "generic_clib_new", "x86:LE:32:default", "gcc",
+ filenames, includePaths, args);
}
+ public void parseGDT_WinVS22() throws Exception {
+
+ String filenames[] = {
+ "# Core necessary files",
+ "winapifamily.h",
+ "winpackagefamily.h",
+ "sdkddkver.h",
+ "sal.h",
+ "no_sal2.h",
+ "corecrt.h",
+ "wtypes.h",
+ "winnt.h",
+ "winternl.h",
+ "#ntdef.h",
+
+ "# Common headers ",
+ "dos.h",
+ "errno.h",
+ "malloc.h",
+ "signal.h",
+ "stdalign.h",
+ "stddef.h",
+ "stdio.h",
+ "stdlib.h",
+ "assert.h",
+ "crtdbg.h",
+ "ctype.h",
+ "conio.h",
+ "direct.h",
+ "fcntl.h",
+ "float.h",
+ "fpieee.h",
+ "inttypes.h",
+ "io.h",
+ "locale.h",
+ "complex.h",
+ "math.h",
+ "mbctype.h",
+ "mbstring.h",
+ "memory.h",
+ "minmax.h",
+ "new.h",
+ "process.h",
+ "search.h",
+ "share.h",
+ "winbase.h",
+ "winuser.h",
+ "Windows.h",
+
+ "# Security and identity (https://docs.microsoft.com/en-us/windows/win32/api/_security/)",
+ "accctrl.h",
+ "aclapi.h",
+ "aclui.h",
+ "adtgen.h",
+ "authz.h",
+ "azroles.h",
+ "bcrypt.h",
+ "casetup.h",
+ "ccgplugins.h",
+ "celib.h",
+ "ntlsa.h",
+ "sspi.h",
+ "ntsecapi.h",
+ "ntsecpkg.h",
+ "schannel.h",
+ "certadm.h",
+ "certbcli.h",
+ "certcli.h",
+ "certenroll.h",
+ "certexit.h",
+ "certif.h",
+ "certmod.h",
+ "certpol.h",
+ "CertPolEng.h",
+ "certsrv.h",
+ "certview.h",
+ "credssp.h",
+ "cryptdlg.h",
+ "cryptuiapi.h",
+ "cryptxml.h",
+ "diagnosticdataquery.h",
+ "diagnosticdataquerytypes.h",
+ "dpapi.h",
+ "dssec.h",
+ "iads.h",
+ "IdentityCommon.h",
+ "IdentityProvider.h",
+ "identitystore.h",
+ "keycredmgr.h",
+ "lmaccess.h",
+ "lsalookup.h",
+ "mmcobj.h",
+ "mscat.h",
+ "mssip.h",
+ "namedpipeapi.h",
+ "ncrypt.h",
+ "ncryptprotect.h",
+ "npapi.h",
+ "processthreadsapi.h",
+ "sas.h",
+ "scesvc.h",
+ "sddl.h",
+ "securityappcontainer.h",
+ "securitybaseapi.h",
+ "slpublic.h",
+ "subauth.h",
+ "tokenbinding.h",
+ "tpmvscmgr.h",
+ "wincred.h",
+ "wincrypt.h",
+ "winnetwk.h",
+ "winreg.h",
+ "winsafer.h",
+ "winscard.h",
+ "winsvc.h",
+ "wintrust.h",
+ "winwlx.h",
+ "xenroll.h",
+
+ "# Windows sockets",
+ "af_irda.h",
+ "in6addr.h",
+ "mstcpip.h",
+ "winsock2.h",
+ "nsemail.h",
+ "nspapi.h",
+ "socketapi.h",
+ "# Nothing includes this; is it necessary?",
+ "#sporder.h",
+ "transportsettingcommon.h",
+ "ws2atm.h",
+ "ws2spi.h",
+ "MSWSock.h",
+ "ws2tcpip.h",
+ "wsipv6ok.h",
+ "WSNwLink.h",
+ "wsrm.h",
+ "mswsockdef.h",
+
+ "# Remote Procedure Call (RPC)",
+ "midles.h",
+ "midlbase.h",
+ "rpc.h",
+ "rpcndr.h",
+ "rpcasync.h",
+ "rpcdcep.h",
+ "rpcnsi.h",
+ "rpcproxy.h",
+ "rpcssl.h",
+
+ "# COM",
+ "accctrl.h",
+ "callobj.h",
+ "combaseapi.h",
+ "comcat.h",
+ "ctxtcall.h",
+ "dmerror.h",
+ "docobj.h",
+ "eventsys.h",
+ "initguid.h",
+ "guiddef.h",
+ "iaccess.h",
+ "hstring.h",
+ "IMessageDispatcher.h",
+ "MessageDispatcherApi.h",
+ "objbase.h",
+ "objidlbase.h",
+ "objidl.h",
+ "ocidl.h",
+ "ole.h",
+ "ole2.h",
+ "oledlg.h",
+ "oleidl.h",
+ "roapi.h",
+ "rpcdce.h",
+ "servprov.h",
+ "shobjidl.h",
+ "txlogpub.h",
+ "unknwnbase.h",
+ "unknwn.h",
+ "urlmon.h",
+ "vbinterf.h",
+ "winddi.h",
+ "winerror.h",
+ "wtypesbase.h",
+
+ "# COM+",
+ "comadmin.h",
+ "mtxdm.h",
+
+ "# More",
+ "inspectable.h",
+
+ "# Windows Internet",
+ "proofofpossessioncookieinfo.h",
+ "wininet.h",
+ "winineti.h",
+
+ "# Windows HTTP Services",
+ "winhttp.h",
+
+ "# Compression",
+ "compressapi.h",
+
+ "# TraceLogging",
+ "#traceloggingactivity.h",
+ "#traceloggingprovider.h",
+
+ "# Windows Error Reporting",
+ "errorrep.h",
+ "werapi.h",
+
+ "# Windows and MEssages",
+ "olectl.h",
+ "windef.h",
+ "windowsx.h",
+
+ "# Shell",
+ "appmgmt.h",
+ "appnotify.h",
+ "cpl.h",
+ "credentialprovider.h",
+ "dimm.h",
+ "imagetranscode.h",
+ "inputpanelconfiguration.h",
+ "intsafe.h",
+ "intshcut.h",
+ "mobsync.h",
+ "objectarray.h",
+ "pathcch.h",
+ "profinfo.h",
+ "propkeydef.h",
+ "scrnsave.h",
+ "shappmgr.h",
+ "shdeprecated.h",
+ "shidfact.h",
+ "shimgdata.h",
+ "shlwapi.h",
+ "shtypes.h",
+ "storageprovider.h",
+ "syncmgr.h",
+ "thumbcache.h",
+ "thumbnailstreamcache.h",
+ "tlogstg.h",
+ "UserEnv.h",
+
+ "# Windows Controls",
+ "commctrl.h",
+ "commoncontrols.h",
+ "dpa_dsa.h",
+ "prsht.h",
+ "richedit.h",
+ "richole.h",
+ "shlobj_core.h",
+ "shlobj.h",
+ "#textserv.h", // C++
+ "tom.h",
+ "uxtheme.h",
+
+ "# Menus and other resources",
+ "resourceindexer.h",
+ "strsafe.h",
+ "verrsrc.h",
+ "winver.h",
+
+ "# Windows Accessibility Features",
+ "oleacc.h",
+ "uiautomationcore.h",
+ "uiautomationclient.h",
+ "uiautomationcoreapi.h",
+
+ "# Internationalization",
+ "datetimeapi.h",
+ "elscore.h",
+ "gb18030.h",
+ "imepad.h",
+ "imm.h",
+ "immdev.h",
+ "msime.h",
+ "msimeapi.h",
+ "muiload.h",
+ "spellcheck.h",
+ "spellcheckprovider.h",
+ "stringapiset.h",
+ "usp10.h",
+ "winnls.h",
+
+ "# HTTP Server API",
+ "#http.h", // included by something else
+
+ "# IP Helper",
+ "#icmpapi.h", // Something wrong with IP_ADDR
+ "ifdef.h",
+ "inaddr.h",
+ "ip2string.h",
+ "ipexport.h",
+ "iphlpapi.h",
+ "iprtrmib.h",
+ "iptypes.h",
+ "nldef.h",
+ "tcpestats.h",
+
+ "# Network Management",
+ "atacct.h",
+ "lmalert.h",
+ "lmapibuf.h",
+ "lmat.h",
+ "lmaudit.h",
+ "lmconfig.h",
+ "lmerrlog.h",
+ "lmjoin.h",
+ "lmmsg.h",
+ "lmremutl.h",
+ "lmserver.h",
+ "lmsvc.h",
+ "lmuse.h",
+ "lmwksta.h"
+ };
+
+ String includePaths[] = {
+ headerFilePath + "/VC/VS22/Community/VC/Tools/MSVC/14.29.30133/include",
+ headerFilePath + "/VC/SDK/10/Include/10.0.22000.0/shared",
+ headerFilePath + "/VC/SDK/10/Include/10.0.22000.0/um",
+ headerFilePath + "/VC/SDK/10/Include/10.0.22000.0/km",
+ headerFilePath + "/VC/VS22/10.0.19041.0/shared",
+ headerFilePath + "/VC/VS22/10.0.19041.0/um",
+ headerFilePath + "/VC/VS22/10.0.19041.0/ucrt",
+ headerFilePath + "/VC/VS22/10.0.19041.0/winrt",
+ };
+
+ String args[] = {
+ "-D_MSC_VER=1924",
+ "-D_INTEGRAL_MAX_BITS=64",
+ "-DWINVER=0x0a00",
+ "-D_WIN32_WINNT=0x0a00",
+ "-D_AMD64_",
+ "-D_M_AMD64",
+ "-D_M_X64",
+ "-D_WIN64",
+ "-D_WIN32",
+ "-D_USE_ATTRIBUTES_FOR_SAL",
+ "-D_CRTBLD",
+ "-D_OPENMP_NOFORCE_MANIFEST",
+ "-DLPSKBINFO=LPARAM",
+ "-DCONST=const",
+ "-D_CRT_SECURE_NO_WARNINGS",
+ "-D_CRT_NONSTDC_NO_DEPRECATE",
+ "-D_CRT_NONSTDC_NO_WARNINGS",
+ "-D_CRT_OBSOLETE_NO_DEPRECATE",
+ "-D_ALLOW_KEYWORD_MACROS",
+ "-D_ASSERT_OK",
+ "-DSTRSAFE_NO_DEPRECATE",
+ "-D__possibly_notnullterminated",
+ "-Dtype_info=\"void *\"",
+ "-D_ThrowInfo=ThrowInfo",
+ "-D__unaligned=",
+ "-v0",
+ "-D__inner_checkReturn=",
+ "-DDECLSPEC_DEPRECATED_DDK",
+ "-DWINAPI_PARTITION_APP=1",
+ "-DWINAPI_PARTITION_SYSTEM=1",
+ "-DWINAPI_PARTITION_GAMES=1",
+ "-DSECURITY_WIN32",
+ "-DSIZE_T=size_t",
+ };
+
+ parseHeaderFilesToGDT(outputDirectory, "windows_vs22_64_new", "x86:LE:64:default",
+ "windows", filenames, includePaths, args);
+ }
public void parseGDT_WinVS22_WDK() throws Exception {
-
- String filenames[] = {
- "# Core necessary files",
- "# Windows Drivers WDK",
- "initguid.h",
- "ntddk.h",
- "ntintsafe.h",
- "wdf.h",
+ String filenames[] = {
+ "# Core necessary files",
+
+ "# Windows Drivers WDK",
+ "initguid.h",
+ "ntddk.h",
+ "ntintsafe.h",
+ "wdf.h",
};
String includePaths[] = {
- headerFilePath+"/VC/VS22/Community/VC/Tools/MSVC/14.29.30133/include",
- headerFilePath+"/VC/SDK/10/Include/10.0.22000.0/shared",
- headerFilePath+"/VC/SDK/10/Include/10.0.22000.0/um",
- headerFilePath+"/VC/SDK/10/Include/10.0.22000.0/km",
- headerFilePath+"/VC/SDK/10/Include/wdf/umdf/2.33",
- headerFilePath+"/VC/VS22/10.0.19041.0/shared",
- headerFilePath+"/VC/VS22/10.0.19041.0/um",
- headerFilePath+"/VC/VS22/10.0.19041.0/ucrt",
- headerFilePath+"/VC/VS22/10.0.19041.0/winrt",
+ headerFilePath + "/VC/VS22/Community/VC/Tools/MSVC/14.29.30133/include",
+ headerFilePath + "/VC/SDK/10/Include/10.0.22000.0/shared",
+ headerFilePath + "/VC/SDK/10/Include/10.0.22000.0/um",
+ headerFilePath + "/VC/SDK/10/Include/10.0.22000.0/km",
+ headerFilePath + "/VC/SDK/10/Include/wdf/umdf/2.33",
+ headerFilePath + "/VC/VS22/10.0.19041.0/shared",
+ headerFilePath + "/VC/VS22/10.0.19041.0/um",
+ headerFilePath + "/VC/VS22/10.0.19041.0/ucrt",
+ headerFilePath + "/VC/VS22/10.0.19041.0/winrt",
};
-
+
String args[] = {
- "-D_MSC_VER=1924",
- "-D_INTEGRAL_MAX_BITS=64",
- "-DWINVER=0x0a00",
- "-D_WIN32_WINNT=0x0a00",
- "-D_AMD64_",
- "-D_M_AMD64",
- "-D_M_X64",
- "-D_WIN64",
- "-D_WIN32",
- "-D_USE_ATTRIBUTES_FOR_SAL",
- "-D_CRTBLD",
- "-D_OPENMP_NOFORCE_MANIFEST",
- "-DLPSKBINFO=LPARAM",
- "-DCONST=const",
- "-D_CRT_SECURE_NO_WARNINGS",
- "-D_CRT_NONSTDC_NO_DEPRECATE",
- "-D_CRT_NONSTDC_NO_WARNINGS",
- "-D_CRT_OBSOLETE_NO_DEPRECATE",
- "-D_ALLOW_KEYWORD_MACROS",
- "-D_ASSERT_OK",
- "-DSTRSAFE_NO_DEPRECATE",
- "-D__possibly_notnullterminated",
- "-Dtype_info=\"void *\"",
- "-D_ThrowInfo=ThrowInfo",
- "-D__unaligned=",
- "-v0",
- "-D__inner_checkReturn=",
- "-DDECLSPEC_DEPRECATED_DDK",
- "-DWINAPI_PARTITION_APP=1",
- "-DWINAPI_PARTITION_SYSTEM=1",
- "-DWINAPI_PARTITION_GAMES=1",
- "-DSECURITY_WIN32",
- "-DSIZE_T=size_t",
+ "-D_MSC_VER=1924",
+ "-D_INTEGRAL_MAX_BITS=64",
+ "-DWINVER=0x0a00",
+ "-D_WIN32_WINNT=0x0a00",
+ "-D_AMD64_",
+ "-D_M_AMD64",
+ "-D_M_X64",
+ "-D_WIN64",
+ "-D_WIN32",
+ "-D_USE_ATTRIBUTES_FOR_SAL",
+ "-D_CRTBLD",
+ "-D_OPENMP_NOFORCE_MANIFEST",
+ "-DLPSKBINFO=LPARAM",
+ "-DCONST=const",
+ "-D_CRT_SECURE_NO_WARNINGS",
+ "-D_CRT_NONSTDC_NO_DEPRECATE",
+ "-D_CRT_NONSTDC_NO_WARNINGS",
+ "-D_CRT_OBSOLETE_NO_DEPRECATE",
+ "-D_ALLOW_KEYWORD_MACROS",
+ "-D_ASSERT_OK",
+ "-DSTRSAFE_NO_DEPRECATE",
+ "-D__possibly_notnullterminated",
+ "-Dtype_info=\"void *\"",
+ "-D_ThrowInfo=ThrowInfo",
+ "-D__unaligned=",
+ "-v0",
+ "-D__inner_checkReturn=",
+ "-DDECLSPEC_DEPRECATED_DDK",
+ "-DWINAPI_PARTITION_APP=1",
+ "-DWINAPI_PARTITION_SYSTEM=1",
+ "-DWINAPI_PARTITION_GAMES=1",
+ "-DSECURITY_WIN32",
+ "-DSIZE_T=size_t",
};
-
- File file = new File(outputDirectory+"/windows_vs22_64_new.gdt");
- DataTypeManager vsDTMgr = FileDataTypeManager.openFileArchive(file, false);
+
+ File file = new File(outputDirectory + "/windows_vs22_64_new.gdt");
+
+ FileDataTypeArchive archive =
+ DataTypeArchiveFactory.openReadOnly(file, this, TaskMonitor.DUMMY);
+
+ DataTypeManager vsDTMgr = archive.getDataTypeManager();
DataTypeManager openTypes[] = { vsDTMgr };
-
- parseHeaderFilesToGDT(openTypes, outputDirectory, "windows_vs22_wdk_64_new", "x86:LE:64:default", "windows", filenames, includePaths, args);
+
+ parseHeaderFilesToGDT(openTypes, outputDirectory, "windows_vs22_wdk_64_new",
+ "x86:LE:64:default", "windows", filenames, includePaths, args);
+ archive.release(this);
}
}
diff --git a/Ghidra/Features/Base/ghidra_scripts/CreateExampleGDTArchiveScript.java b/Ghidra/Features/Base/ghidra_scripts/CreateExampleGDTArchiveScript.java
index 09ad80ee16..1ea5ea1050 100644
--- a/Ghidra/Features/Base/ghidra_scripts/CreateExampleGDTArchiveScript.java
+++ b/Ghidra/Features/Base/ghidra_scripts/CreateExampleGDTArchiveScript.java
@@ -33,44 +33,47 @@ 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;
public class CreateExampleGDTArchiveScript extends GhidraScript {
private File outputDirectory;
-
+
// location of header files base directory
private static String headerFilePath = "/data/HeaderFiles";
@Override
protected void run() throws Exception {
outputDirectory = askDirectory("Select Directory for GDT files", "Select GDT Output Dir");
-
+
parseGDT_DirectX();
-
+
parseGDT_WinVS22();
}
-
- 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.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);
+
+ archive.release(this);
}
/**
@@ -92,404 +95,405 @@ public class CreateExampleGDTArchiveScript extends GhidraScript {
}
return f;
}
-
-
+
public void parseGDT_DirectX() throws Exception {
-
+
String filenames[] = {
- "SDKDDKVer.h",
- "Windows.h",
- "winnt.h",
-
- "windowsx.h",
- "ddraw.h",
- "d3d.h",
- "dinput.h",
- "mmreg.h",
- "dsound.h",
+ "SDKDDKVer.h",
+ "Windows.h",
+ "winnt.h",
+
+ "windowsx.h",
+ "ddraw.h",
+ "d3d.h",
+ "dinput.h",
+ "mmreg.h",
+ "dsound.h",
};
-
+
String includeFiles[] = {
- headerFilePath+"/VC/VS22/Community/VC/Tools/MSVC/14.29.30133/include",
- headerFilePath+"/VC/VS22/10.0.19041.0/shared",
- headerFilePath+"/VC/VS22/10.0.19041.0/ucrt",
- headerFilePath+"/VC/VS22/10.0.19041.0/um",
+ headerFilePath + "/VC/VS22/Community/VC/Tools/MSVC/14.29.30133/include",
+ headerFilePath + "/VC/VS22/10.0.19041.0/shared",
+ headerFilePath + "/VC/VS22/10.0.19041.0/ucrt",
+ headerFilePath + "/VC/VS22/10.0.19041.0/um",
};
-
+
String args[] = {
- "-D_AMD64_",
- "-D_M_AMD64",
- "-D_M_X64",
- "-D_WIN64",
- "-D_WIN32",
- "-v0",
+ "-D_AMD64_",
+ "-D_M_AMD64",
+ "-D_M_X64",
+ "-D_WIN64",
+ "-D_WIN32",
+ "-v0",
};
-
- parseHeaderFilesToGDT(outputDirectory, "directX64", "x86:LE:64:default", "windows", filenames, includeFiles, args);
+
+ parseHeaderFilesToGDT(outputDirectory, "directX64", "x86:LE:64:default", "windows",
+ filenames, includeFiles, args);
}
-
+
public void parseGDT_WinVS22() throws Exception {
String filenames[] = {
- "# Core necessary files",
- "winapifamily.h",
- "winpackagefamily.h",
- "sdkddkver.h",
- "sal.h",
- "no_sal2.h",
- "corecrt.h",
- "wtypes.h",
- "winnt.h",
- "winternl.h",
- "#ntdef.h",
-
- "# Common headers ",
- "dos.h",
- "errno.h",
- "malloc.h",
- "signal.h",
- "stdalign.h",
- "stddef.h",
- "stdio.h",
- "stdlib.h",
- "assert.h",
- "crtdbg.h",
- "ctype.h",
- "conio.h",
- "direct.h",
- "fcntl.h",
- "float.h",
- "fpieee.h",
- "inttypes.h",
- "io.h",
- "locale.h",
- "complex.h",
- "math.h",
- "mbctype.h",
- "mbstring.h",
- "memory.h",
- "minmax.h",
- "new.h",
- "process.h",
- "search.h",
- "share.h",
- "winbase.h",
- "winuser.h",
- "Windows.h",
-
- "# Security and identity (https://docs.microsoft.com/en-us/windows/win32/api/_security/)",
- "accctrl.h",
- "aclapi.h",
- "aclui.h",
- "adtgen.h",
- "authz.h",
- "azroles.h",
- "bcrypt.h",
- "casetup.h",
- "ccgplugins.h",
- "celib.h",
- "ntlsa.h",
- "sspi.h",
- "ntsecapi.h",
- "ntsecpkg.h",
- "schannel.h",
- "certadm.h",
- "certbcli.h",
- "certcli.h",
- "certenroll.h",
- "certexit.h",
- "certif.h",
- "certmod.h",
- "certpol.h",
- "certpoleng.h",
- "certsrv.h",
- "certview.h",
- "credssp.h",
- "cryptdlg.h",
- "cryptuiapi.h",
- "cryptxml.h",
- "diagnosticdataquery.h",
- "diagnosticdataquerytypes.h",
- "dpapi.h",
- "dssec.h",
- "iads.h",
- "identitycommon.h",
- "identityprovider.h",
- "identitystore.h",
- "keycredmgr.h",
- "lmaccess.h",
- "lsalookup.h",
- "mmcobj.h",
- "mscat.h",
- "mssip.h",
- "namedpipeapi.h",
- "ncrypt.h",
- "ncryptprotect.h",
- "npapi.h",
- "processthreadsapi.h",
- "sas.h",
- "scesvc.h",
- "sddl.h",
- "securityappcontainer.h",
- "securitybaseapi.h",
- "slpublic.h",
- "subauth.h",
- "tokenbinding.h",
- "tpmvscmgr.h",
- "wincred.h",
- "wincrypt.h",
- "winnetwk.h",
- "winreg.h",
- "winsafer.h",
- "winscard.h",
- "winsvc.h",
- "wintrust.h",
- "winwlx.h",
- "xenroll.h",
-
- "# Windows sockets",
- "af_irda.h",
- "in6addr.h",
- "mstcpip.h",
- "winsock2.h",
- "nsemail.h",
- "nspapi.h",
- "socketapi.h",
- "# Nothing includes this; is it necessary?",
- "#sporder.h",
- "transportsettingcommon.h",
- "ws2atm.h",
- "ws2spi.h",
- "mswsock.h",
- "ws2tcpip.h",
- "wsipv6ok.h",
- "wsnwlink.h",
- "wsrm.h",
- "mswsockdef.h",
-
- "# Remote Procedure Call (RPC)",
- "midles.h",
- "midlbase.h",
- "rpc.h",
- "rpcndr.h",
- "rpcasync.h",
- "rpcdcep.h",
- "rpcnsi.h",
- "rpcproxy.h",
- "rpcssl.h",
-
- "# COM",
- "accctrl.h",
- "callobj.h",
- "combaseapi.h",
- "comcat.h",
- "ctxtcall.h",
- "dmerror.h",
- "docobj.h",
- "eventsys.h",
- "guiddef.h",
- "iaccess.h",
- "hstring.h",
- "imessagedispatcher.h",
- "messagedispatherapi.h",
- "objbase.h",
- "objidlbase.h",
- "objidl.h",
- "ocidl.h",
- "ole.h",
- "ole2.h",
- "oledlg.h",
- "oleidl.h",
- "roapi.h",
- "rpcdce.h",
- "servprov.h",
- "shobjidl.h",
- "txlogpub.h",
- "unknwnbase.h",
- "unknwn.h",
- "urlmon.h",
- "vbinterf.h",
- "winddi.h",
- "winerror.h",
- "wtypesbase.h",
-
- "# COM+",
- "comadmin.h",
- "mtxdm.h",
-
- "# More",
- "inspectable.h",
-
- "# Windows Internet",
- "proofofpossessioncookieinfo.h",
- "wininet.h",
- "winineti.h",
-
- "# Windows HTTP Services",
- "winhttp.h",
-
- "# Compression",
- "compressapi.h",
-
- "# TraceLogging",
- "#traceloggingactivity.h",
- "#traceloggingprovider.h",
-
- "# Windows Error Reporting",
- "errorrep.h",
- "werapi.h",
-
- "# Windows and MEssages",
- "olectl.h",
- "windef.h",
- "windowsx.h",
-
- "# Shell",
- "appmgmt.h",
- "appnotify.h",
- "cpl.h",
- "credentialprovider.h",
- "dimm.h",
- "imagetranscode.h",
- "inputpanelconfiguration.h",
- "intsafe.h",
- "intshcut.h",
- "mobsync.h",
- "objectarray.h",
- "pathcch.h",
- "profinfo.h",
- "propkeydef.h",
- "scrnsave.h",
- "shappmgr.h",
- "shdeprecated.h",
- "shidfact.h",
- "shimgdata.h",
- "shlwapi.h",
- "shtypes.h",
- "storageprovider.h",
- "syncmgr.h",
- "thumbcache.h",
- "thumbnailstreamcache.h",
- "tlogstg.h",
- "userenv.h",
-
- "# Windows Controls",
- "commctrl.h",
- "commoncontrols.h",
- "dpa_dsa.h",
- "prsht.h",
- "richedit.h",
- "richole.h",
- "shlobj_core.h",
- "shlobj.h",
- "#textserv.h", // C++
- "tom.h",
- "uxtheme.h",
-
- "# Menus and other resources",
- "resourceindexer.h",
- "strsafe.h",
- "verrsrc.h",
- "winver.h",
-
- "# Windows Accessibility Features",
- "oleacc.h",
- "uiautomationcore.h",
- "uiautomationclient.h",
- "uiautomationcoreapi.h",
-
- "# Internationalization",
- "datetimeapi.h",
- "elscore.h",
- "gb18030.h",
- "imepad.h",
- "imm.h",
- "immdev.h",
- "msime.h",
- "msimeapi.h",
- "muiload.h",
- "spellcheck.h",
- "spellcheckprovider.h",
- "stringapiset.h",
- "usp10.h",
- "winnls.h",
-
- "# HTTP Server API",
- "#http.h", // included by something else
-
- "# IP Helper",
- "ifdef.h",
- "inaddr.h",
- "ip2string.h",
- "ipexport.h",
- "iphlpapi.h",
- "icmpapi.h", // Must be included after iphlpapi.h
- "iprtrmib.h",
- "iptypes.h",
- "netioapi.h",
- "nldef.h",
- "tcpestats.h",
- "ws2ipdef.h",
-
- "# Network Management",
- "atacct.h",
- "lmalert.h",
- "lmapibuf.h",
- "lmat.h",
- "lmaudit.h",
- "lmconfig.h",
- "lmerrlog.h",
- "lmjoin.h",
- "lmmsg.h",
- "lmremutl.h",
- "lmserver.h",
- "lmsvc.h",
- "lmuse.h",
- "lmwksta.h"
+ "# Core necessary files",
+ "winapifamily.h",
+ "winpackagefamily.h",
+ "sdkddkver.h",
+ "sal.h",
+ "no_sal2.h",
+ "corecrt.h",
+ "wtypes.h",
+ "winnt.h",
+ "winternl.h",
+ "#ntdef.h",
+
+ "# Common headers ",
+ "dos.h",
+ "errno.h",
+ "malloc.h",
+ "signal.h",
+ "stdalign.h",
+ "stddef.h",
+ "stdio.h",
+ "stdlib.h",
+ "assert.h",
+ "crtdbg.h",
+ "ctype.h",
+ "conio.h",
+ "direct.h",
+ "fcntl.h",
+ "float.h",
+ "fpieee.h",
+ "inttypes.h",
+ "io.h",
+ "locale.h",
+ "complex.h",
+ "math.h",
+ "mbctype.h",
+ "mbstring.h",
+ "memory.h",
+ "minmax.h",
+ "new.h",
+ "process.h",
+ "search.h",
+ "share.h",
+ "winbase.h",
+ "winuser.h",
+ "Windows.h",
+
+ "# Security and identity (https://docs.microsoft.com/en-us/windows/win32/api/_security/)",
+ "accctrl.h",
+ "aclapi.h",
+ "aclui.h",
+ "adtgen.h",
+ "authz.h",
+ "azroles.h",
+ "bcrypt.h",
+ "casetup.h",
+ "ccgplugins.h",
+ "celib.h",
+ "ntlsa.h",
+ "sspi.h",
+ "ntsecapi.h",
+ "ntsecpkg.h",
+ "schannel.h",
+ "certadm.h",
+ "certbcli.h",
+ "certcli.h",
+ "certenroll.h",
+ "certexit.h",
+ "certif.h",
+ "certmod.h",
+ "certpol.h",
+ "certpoleng.h",
+ "certsrv.h",
+ "certview.h",
+ "credssp.h",
+ "cryptdlg.h",
+ "cryptuiapi.h",
+ "cryptxml.h",
+ "diagnosticdataquery.h",
+ "diagnosticdataquerytypes.h",
+ "dpapi.h",
+ "dssec.h",
+ "iads.h",
+ "identitycommon.h",
+ "identityprovider.h",
+ "identitystore.h",
+ "keycredmgr.h",
+ "lmaccess.h",
+ "lsalookup.h",
+ "mmcobj.h",
+ "mscat.h",
+ "mssip.h",
+ "namedpipeapi.h",
+ "ncrypt.h",
+ "ncryptprotect.h",
+ "npapi.h",
+ "processthreadsapi.h",
+ "sas.h",
+ "scesvc.h",
+ "sddl.h",
+ "securityappcontainer.h",
+ "securitybaseapi.h",
+ "slpublic.h",
+ "subauth.h",
+ "tokenbinding.h",
+ "tpmvscmgr.h",
+ "wincred.h",
+ "wincrypt.h",
+ "winnetwk.h",
+ "winreg.h",
+ "winsafer.h",
+ "winscard.h",
+ "winsvc.h",
+ "wintrust.h",
+ "winwlx.h",
+ "xenroll.h",
+
+ "# Windows sockets",
+ "af_irda.h",
+ "in6addr.h",
+ "mstcpip.h",
+ "winsock2.h",
+ "nsemail.h",
+ "nspapi.h",
+ "socketapi.h",
+ "# Nothing includes this; is it necessary?",
+ "#sporder.h",
+ "transportsettingcommon.h",
+ "ws2atm.h",
+ "ws2spi.h",
+ "mswsock.h",
+ "ws2tcpip.h",
+ "wsipv6ok.h",
+ "wsnwlink.h",
+ "wsrm.h",
+ "mswsockdef.h",
+
+ "# Remote Procedure Call (RPC)",
+ "midles.h",
+ "midlbase.h",
+ "rpc.h",
+ "rpcndr.h",
+ "rpcasync.h",
+ "rpcdcep.h",
+ "rpcnsi.h",
+ "rpcproxy.h",
+ "rpcssl.h",
+
+ "# COM",
+ "accctrl.h",
+ "callobj.h",
+ "combaseapi.h",
+ "comcat.h",
+ "ctxtcall.h",
+ "dmerror.h",
+ "docobj.h",
+ "eventsys.h",
+ "guiddef.h",
+ "iaccess.h",
+ "hstring.h",
+ "imessagedispatcher.h",
+ "messagedispatherapi.h",
+ "objbase.h",
+ "objidlbase.h",
+ "objidl.h",
+ "ocidl.h",
+ "ole.h",
+ "ole2.h",
+ "oledlg.h",
+ "oleidl.h",
+ "roapi.h",
+ "rpcdce.h",
+ "servprov.h",
+ "shobjidl.h",
+ "txlogpub.h",
+ "unknwnbase.h",
+ "unknwn.h",
+ "urlmon.h",
+ "vbinterf.h",
+ "winddi.h",
+ "winerror.h",
+ "wtypesbase.h",
+
+ "# COM+",
+ "comadmin.h",
+ "mtxdm.h",
+
+ "# More",
+ "inspectable.h",
+
+ "# Windows Internet",
+ "proofofpossessioncookieinfo.h",
+ "wininet.h",
+ "winineti.h",
+
+ "# Windows HTTP Services",
+ "winhttp.h",
+
+ "# Compression",
+ "compressapi.h",
+
+ "# TraceLogging",
+ "#traceloggingactivity.h",
+ "#traceloggingprovider.h",
+
+ "# Windows Error Reporting",
+ "errorrep.h",
+ "werapi.h",
+
+ "# Windows and MEssages",
+ "olectl.h",
+ "windef.h",
+ "windowsx.h",
+
+ "# Shell",
+ "appmgmt.h",
+ "appnotify.h",
+ "cpl.h",
+ "credentialprovider.h",
+ "dimm.h",
+ "imagetranscode.h",
+ "inputpanelconfiguration.h",
+ "intsafe.h",
+ "intshcut.h",
+ "mobsync.h",
+ "objectarray.h",
+ "pathcch.h",
+ "profinfo.h",
+ "propkeydef.h",
+ "scrnsave.h",
+ "shappmgr.h",
+ "shdeprecated.h",
+ "shidfact.h",
+ "shimgdata.h",
+ "shlwapi.h",
+ "shtypes.h",
+ "storageprovider.h",
+ "syncmgr.h",
+ "thumbcache.h",
+ "thumbnailstreamcache.h",
+ "tlogstg.h",
+ "userenv.h",
+
+ "# Windows Controls",
+ "commctrl.h",
+ "commoncontrols.h",
+ "dpa_dsa.h",
+ "prsht.h",
+ "richedit.h",
+ "richole.h",
+ "shlobj_core.h",
+ "shlobj.h",
+ "#textserv.h", // C++
+ "tom.h",
+ "uxtheme.h",
+
+ "# Menus and other resources",
+ "resourceindexer.h",
+ "strsafe.h",
+ "verrsrc.h",
+ "winver.h",
+
+ "# Windows Accessibility Features",
+ "oleacc.h",
+ "uiautomationcore.h",
+ "uiautomationclient.h",
+ "uiautomationcoreapi.h",
+
+ "# Internationalization",
+ "datetimeapi.h",
+ "elscore.h",
+ "gb18030.h",
+ "imepad.h",
+ "imm.h",
+ "immdev.h",
+ "msime.h",
+ "msimeapi.h",
+ "muiload.h",
+ "spellcheck.h",
+ "spellcheckprovider.h",
+ "stringapiset.h",
+ "usp10.h",
+ "winnls.h",
+
+ "# HTTP Server API",
+ "#http.h", // included by something else
+
+ "# IP Helper",
+ "ifdef.h",
+ "inaddr.h",
+ "ip2string.h",
+ "ipexport.h",
+ "iphlpapi.h",
+ "icmpapi.h", // Must be included after iphlpapi.h
+ "iprtrmib.h",
+ "iptypes.h",
+ "netioapi.h",
+ "nldef.h",
+ "tcpestats.h",
+ "ws2ipdef.h",
+
+ "# Network Management",
+ "atacct.h",
+ "lmalert.h",
+ "lmapibuf.h",
+ "lmat.h",
+ "lmaudit.h",
+ "lmconfig.h",
+ "lmerrlog.h",
+ "lmjoin.h",
+ "lmmsg.h",
+ "lmremutl.h",
+ "lmserver.h",
+ "lmsvc.h",
+ "lmuse.h",
+ "lmwksta.h"
};
-
+
String includeFiles[] = {
- headerFilePath+"/VC/VS22/Community/VC/Tools/MSVC/14.29.30133/include",
- headerFilePath+"/VC/VS22/10.0.19041.0/shared",
- headerFilePath+"/VC/VS22/10.0.19041.0/ucrt",
- headerFilePath+"/VC/VS22/10.0.19041.0/um",
- headerFilePath+"/VC/VS22/10.0.19041.0/winrt",
+ headerFilePath + "/VC/VS22/Community/VC/Tools/MSVC/14.29.30133/include",
+ headerFilePath + "/VC/VS22/10.0.19041.0/shared",
+ headerFilePath + "/VC/VS22/10.0.19041.0/ucrt",
+ headerFilePath + "/VC/VS22/10.0.19041.0/um",
+ headerFilePath + "/VC/VS22/10.0.19041.0/winrt",
};
-
+
String args[] = {
- "-D_MSC_VER=1924",
- "-D_INTEGRAL_MAX_BITS=64",
- "-DWINVER=0x0a00",
- "-D_WIN32_WINNT=0x0a00",
- "-D_AMD64_",
- "-D_M_AMD64",
- "-D_M_X64",
- "-D_WIN64",
- "-D_WIN32",
- "-D_USE_ATTRIBUTES_FOR_SAL",
- "-D_CRTBLD",
- "-D_OPENMP_NOFORCE_MANIFEST",
- "-DLPSKBINFO=LPARAM",
- "-DCONST=const",
- "-D_CRT_SECURE_NO_WARNINGS",
- "-D_CRT_NONSTDC_NO_DEPRECATE",
- "-D_CRT_NONSTDC_NO_WARNINGS",
- "-D_CRT_OBSOLETE_NO_DEPRECATE",
- "-D_ALLOW_KEYWORD_MACROS",
- "-D_ASSERT_OK",
- "-DSTRSAFE_NO_DEPRECATE",
- "-D__possibly_notnullterminated",
- "-Dtype_info=\"void *\"",
- "-D_ThrowInfo=ThrowInfo",
- "-D__unaligned=",
- "-v0",
- "-D__inner_checkReturn=",
- "-DWINAPI_PARTITION_APP=1",
- "-DWINAPI_PARTITION_SYSTEM=1",
- "-DWINAPI_PARTITION_GAMES=1",
- "-DSECURITY_WIN32",
+ "-D_MSC_VER=1924",
+ "-D_INTEGRAL_MAX_BITS=64",
+ "-DWINVER=0x0a00",
+ "-D_WIN32_WINNT=0x0a00",
+ "-D_AMD64_",
+ "-D_M_AMD64",
+ "-D_M_X64",
+ "-D_WIN64",
+ "-D_WIN32",
+ "-D_USE_ATTRIBUTES_FOR_SAL",
+ "-D_CRTBLD",
+ "-D_OPENMP_NOFORCE_MANIFEST",
+ "-DLPSKBINFO=LPARAM",
+ "-DCONST=const",
+ "-D_CRT_SECURE_NO_WARNINGS",
+ "-D_CRT_NONSTDC_NO_DEPRECATE",
+ "-D_CRT_NONSTDC_NO_WARNINGS",
+ "-D_CRT_OBSOLETE_NO_DEPRECATE",
+ "-D_ALLOW_KEYWORD_MACROS",
+ "-D_ASSERT_OK",
+ "-DSTRSAFE_NO_DEPRECATE",
+ "-D__possibly_notnullterminated",
+ "-Dtype_info=\"void *\"",
+ "-D_ThrowInfo=ThrowInfo",
+ "-D__unaligned=",
+ "-v0",
+ "-D__inner_checkReturn=",
+ "-DWINAPI_PARTITION_APP=1",
+ "-DWINAPI_PARTITION_SYSTEM=1",
+ "-DWINAPI_PARTITION_GAMES=1",
+ "-DSECURITY_WIN32",
};
-
- parseHeaderFilesToGDT(outputDirectory, "windows_vs22_64_new", "x86:LE:64:default", "windows", filenames, includeFiles, args);
+
+ parseHeaderFilesToGDT(outputDirectory, "windows_vs22_64_new", "x86:LE:64:default",
+ "windows", filenames, includeFiles, args);
}
}
diff --git a/Ghidra/Features/Base/ghidra_scripts/CreateUEFIGDTArchivesScript.java b/Ghidra/Features/Base/ghidra_scripts/CreateUEFIGDTArchivesScript.java
index 07db2763f0..e895d9232e 100644
--- a/Ghidra/Features/Base/ghidra_scripts/CreateUEFIGDTArchivesScript.java
+++ b/Ghidra/Features/Base/ghidra_scripts/CreateUEFIGDTArchivesScript.java
@@ -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);
}
}
diff --git a/Ghidra/Features/Base/ghidra_scripts/FixupCompositeDataTypesScript.java b/Ghidra/Features/Base/ghidra_scripts/FixupCompositeDataTypesScript.java
index a69867fcc7..9168ea6d43 100644
--- a/Ghidra/Features/Base/ghidra_scripts/FixupCompositeDataTypesScript.java
+++ b/Ghidra/Features/Base/ghidra_scripts/FixupCompositeDataTypesScript.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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 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);
}
diff --git a/Ghidra/Features/Base/ghidra_scripts/SynchronizeGDTCategoryPaths.java b/Ghidra/Features/Base/ghidra_scripts/SynchronizeGDTCategoryPaths.java
index f1cd181d43..ba47a9e9e5 100644
--- a/Ghidra/Features/Base/ghidra_scripts/SynchronizeGDTCategoryPaths.java
+++ b/Ghidra/Features/Base/ghidra_scripts/SynchronizeGDTCategoryPaths.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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;
diff --git a/Ghidra/Features/Base/src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_description.htm b/Ghidra/Features/Base/src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_description.htm
index 4286217eaf..cfc8cd30e1 100644
--- a/Ghidra/Features/Base/src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_description.htm
+++ b/Ghidra/Features/Base/src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_description.htm
@@ -94,7 +94,7 @@
Data Type Manager window. When a data type archive is open, it
is displayed as a node in the Data Type Manager
tree. Archives can be opened by the user or automatically when a program is opened which
- references that archive. Data type archives can be open for
+ references that archive. Data type archives can be open for
modification or as read-only. Within the Data Type Manager window there are
actions for opening, closing, renaming, and making archives modifiable.
@@ -243,17 +243,6 @@
the program.
-
-
-
- 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.
-
-
Committing Changes To Source Archive
@@ -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 opened for editing. Project archives are normally opened for
+ "#Open_Archive_For_Editing">opened 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.
@@ -467,7 +456,7 @@
Archive action. The archive will be removed from the tree.
- Opening a File Data Type Archive for Editing
+ Opening a File Data Type Archive for Editing
When an archive is first opened, it is not editable. In order to make any changes to
@@ -479,13 +468,13 @@
-
Closing a File Data Type
+ Closing a File Data Type
Archive for Editing
- When an archive that is open for editing no longer
+
When an archive that is open for editing 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 Close for Editing action. If the archive has unsaved
@@ -502,7 +491,6 @@
changes will be saved and the name will be updated to not show a '*'.
-
Undo Unsaved Archive Change
@@ -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
Redo Change action. When the data type archive is
- saved or closed for editing the undo/redo stack is
+ saved or closed for editing the undo/redo stack is
cleared.
@@ -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
Undo Change action. When the data type archive is
- saved or closed for editing the undo/redo stack is
+ saved or closed for editing the undo/redo stack is
cleared.
@@ -550,7 +537,7 @@
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 Delete Archive action. An archive file must be open for editing
- before this action will appear (see Opening a Data Type
+ before this action will appear (see Opening a Data Type
Archive for Editing).
@@ -615,7 +602,7 @@
The source archive must be editable in order to commit. File archives must be open for editing and project
+ "data_type_manager_description.htm#Open_Archive_For_Editing">open for editing and project
archives that are under version control must be checked-out.
Any data type dependencies for a comitted
diff --git a/Ghidra/Features/Base/src/main/java/foundation/FoundationInitializer.java b/Ghidra/Features/Base/src/main/java/foundation/FoundationInitializer.java
index 2634a143fd..87fb473ce8 100644
--- a/Ghidra/Features/Base/src/main/java/foundation/FoundationInitializer.java
+++ b/Ghidra/Features/Base/src/main/java/foundation/FoundationInitializer.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/DataTypeArchiveMergeManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/DataTypeArchiveMergeManager.java
index d751da4055..59598b330b 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/DataTypeArchiveMergeManager.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/DataTypeArchiveMergeManager.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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 {
- 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 multiUserMergeManager,
+ ProjectDataTypeArchive modifiableDomainObject) {
return new DataTypeArchiveMergeManagerPlugin(mergeTool, DataTypeArchiveMergeManager.this,
- (DataTypeArchive) resultDomainObject);
+ resultDomainObject);
}
@Override
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/DataTypeArchiveMergeManagerPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/DataTypeArchiveMergeManagerPlugin.java
index 99d2698dc4..a96f9712dc 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/DataTypeArchiveMergeManagerPlugin.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/DataTypeArchiveMergeManagerPlugin.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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);
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/MergeManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/MergeManager.java
index 97a57b7e52..198935542a 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/MergeManager.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/MergeManager.java
@@ -38,17 +38,20 @@ import help.HelpService;
/**
* Top level object that manages each step of the merge/resolve conflicts
* process.
+ * @param domain object implementation class
+ * @param domain object change set implementation class
*/
-public abstract class MergeManager implements DomainObjectMergeManager {
+public abstract class MergeManager
+ 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 multiUserMergeManager, T modifiableDomainObject);
protected abstract void initializeMerge();
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/ProgramMultiUserMergeManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/ProgramMultiUserMergeManager.java
index b228515145..7183d84d2a 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/ProgramMultiUserMergeManager.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/ProgramMultiUserMergeManager.java
@@ -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 {
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 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);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/DataTypeMergeManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/DataTypeMergeManager.java
index 05d6ca7113..4c217f7f8f 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/DataTypeMergeManager.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/DataTypeMergeManager.java
@@ -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);
}
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ApplyDataArchiveAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ApplyDataArchiveAnalyzer.java
index a4f5b4b601..35b60feb79 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ApplyDataArchiveAnalyzer.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ApplyDataArchiveAnalyzer.java
@@ -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();
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/DefaultDataTypeManagerService.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/DefaultDataTypeManagerService.java
index e2cff4fa1f..9ec6982d2d 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/DefaultDataTypeManagerService.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/DefaultDataTypeManagerService.java
@@ -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
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorDtArchiveDB.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorDtArchiveDB.java
new file mode 100644
index 0000000000..c0035a9f4d
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorDtArchiveDB.java
@@ -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 The specific type of composite
+ */
+public class CompositeEditorDtArchiveDB 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 dtm = getDataTypeManager();
+ withTransaction("Setup for Edit", () -> {
+ dtm.intialize(originalDTM, originalComposite, changeCallback, restoredCallback);
+ });
+ clearUndo();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public CompositeViewerDataTypeManager getDataTypeManager() {
+ return (CompositeViewerDataTypeManager) super.getDataTypeManager();
+ }
+
+ @Override
+ protected CompositeViewerDataTypeManager 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;
+ }
+
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorModel.java
index d2c47818b7..d397b15691 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorModel.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorModel.java
@@ -100,9 +100,10 @@ abstract public class CompositeEditorModel 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 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();
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeViewerDataTypeManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeViewerDataTypeManager.java
index a8575c90ea..d3c187f6d9 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeViewerDataTypeManager.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeViewerDataTypeManager.java
@@ -21,13 +21,17 @@ import java.util.TreeSet;
import javax.help.UnsupportedOperationException;
+import db.DBHandle;
import db.util.ErrorHandler;
+import ghidra.framework.data.OpenMode;
+import ghidra.framework.model.RuntimeIOException;
import ghidra.program.database.DbObject;
+import ghidra.program.database.data.ArchiveDataTypeManagerDB;
import ghidra.program.model.data.*;
import ghidra.program.model.lang.ProgramArchitecture;
+import ghidra.util.Lock;
import ghidra.util.Swing;
-import ghidra.util.exception.AssertException;
-import ghidra.util.exception.CancelledException;
+import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
import utility.function.Callback;
@@ -38,25 +42,24 @@ import utility.function.Callback;
* the editor.
* @param Specific {@link Composite} type being managed
*/
-public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager
+public class CompositeViewerDataTypeManager extends ArchiveDataTypeManagerDB
implements ErrorHandler {
/**
* The data type manager for original composite data type being edited.
* This is where the edited datatype will be written back to.
*/
- private final DataTypeManager originalDTM;
- private final T originalComposite; // may be null if not resolved into this DTM
- private final T viewComposite; // may be null if not resolved into this DTM
+ private DataTypeManager originalDTM;
+ private T originalComposite; // may be null if not resolved into this DTM
+ private T viewComposite; // may be null if not resolved into this DTM
// Database-backed datatype ID map, view to/from original DTM
// This is needed to account for datatype use and ID alterations across undo/redo
- private final IDMapDB dataTypeIDMap;
+ private IDMapDB dataTypeIDMap;
// Editor transaction use only - undo/redo not supported if restoreCallback is null
private Callback restoredCallback;
private Callback changeCallback;
- private int transactionId = 0;
private boolean dataTypeChanged;
// Modification count used to signal optional clearing of undo/redo stack at the end of a
@@ -66,49 +69,51 @@ public class CompositeViewerDataTypeManager extends StandAl
// datatype IDs to be checked as orphaned.
// NOTE: Orphan removal can only be done when this DTM actively manages the viewComposite
private TreeSet orphanIds = new TreeSet<>();
+ private int transactionCount;
- /**
- * Creates a data type manager that the composite editor will use internally for managing
- * dependencies without resolving the actual composite being edited. A single transaction
- * will be started with this instantiation and held open until this instance is closed.
- * Undo/redo and datatype pruning is not be supported.
- * @param rootName the root name for this data type manager (usually the program name).
- * @param originalDTM the original data type manager.
- */
- public CompositeViewerDataTypeManager(String rootName, DataTypeManager originalDTM) {
- this(rootName, originalDTM, null, null, null);
- transactionId = startTransaction("Composite Edit");
+ public static CompositeViewerDataTypeManager createNonUndoableInstance(
+ DataTypeManager originalDTM) {
+ try {
+ CompositeEditorDtArchiveDB archive =
+ new CompositeEditorDtArchiveDB(originalDTM);
+
+ return archive.getDataTypeManager();
+ }
+ catch (IOException e) {
+ throw new RuntimeIOException(e);
+ }
}
- /**
- * Creates a data type manager that the structure editor will use internally for managing a
- * structure being edited and its dependencies.
- * @param rootName the root name for this data type manager (usually the program name).
- * @param originalComposite the original composite data type that is being edited.
- * @param changeCallback Callback will be invoked when any change is made to the view composite.
- * @param restoredCallback Callback will be invoked following any undo/redo.
- */
- public CompositeViewerDataTypeManager(String rootName, T originalComposite,
- Callback changeCallback, Callback restoredCallback) {
- this(rootName, originalComposite.getDataTypeManager(), originalComposite, changeCallback,
- restoredCallback);
+ public static CompositeViewerDataTypeManager createUndoableInstance(
+ T originalComposite, Callback changeCallback,
+ Callback restoredCallback) {
+ try {
+ CompositeEditorDtArchiveDB archive =
+ new CompositeEditorDtArchiveDB(originalComposite, changeCallback,
+ restoredCallback);
+ return archive.getDataTypeManager();
+ }
+ catch (IOException e) {
+ throw new RuntimeIOException(e);
+ }
}
- /**
- * Constructor
- * @param rootName the root name for this data type manager (usually the program name).
- * @param originalDTM the original datatype manager
- * @param originalComposite the original composite data type that is being edited. (may be null)
- * @param changeCallback Callback will be invoked when any change is made to the view composite.
- * @param restoredCallback Callback will be invoked following any undo/redo.
- */
- private CompositeViewerDataTypeManager(String rootName, DataTypeManager originalDTM,
- T originalComposite, Callback changeCallback, Callback restoredCallback) {
- super(rootName, originalDTM.getDataOrganization());
- this.originalDTM = originalDTM;
- this.originalComposite = originalComposite;
- this.changeCallback = changeCallback;
- this.restoredCallback = restoredCallback;
+ CompositeViewerDataTypeManager(DBHandle handle,
+ OpenMode openMode, ErrorHandler errHandler, Lock lock, TaskMonitor monitor)
+ throws CancelledException, VersionException, IOException {
+ super(handle, openMode, errHandler, lock, monitor);
+ }
+
+ @Override
+ public CompositeEditorDtArchiveDB> getDataStore() {
+ return (CompositeEditorDtArchiveDB>) super.getDataStore();
+ }
+
+ void intialize(DataTypeManager dtm, T composite, Callback changeCb, Callback restoredCb) {
+ this.originalDTM = dtm;
+ this.originalComposite = composite;
+ this.changeCallback = changeCb;
+ this.restoredCallback = restoredCb;
int txId = startTransaction("Setup for Edit");
try {
@@ -120,6 +125,7 @@ public class CompositeViewerDataTypeManager extends StandAl
endTransaction(txId, true);
}
clearUndo();
+
}
@SuppressWarnings("unchecked")
@@ -150,10 +156,8 @@ public class CompositeViewerDataTypeManager extends StandAl
return dbHandle.getModCount();
}
- @Override
- protected synchronized void clearUndo() {
- // Exposes method for test use
- super.clearUndo();
+ synchronized void clearUndo() {
+ archive.clearUndo();
}
@Override
@@ -197,10 +201,7 @@ public class CompositeViewerDataTypeManager extends StandAl
@Override
public synchronized void close() {
- if (transactionId != 0) {
- super.endTransaction(transactionId, true);
- }
- super.close();
+ getDataStore().close();
}
/**
@@ -360,10 +361,16 @@ public class CompositeViewerDataTypeManager extends StandAl
}
}
+ @Override
+ public synchronized int startTransaction(String description) {
+ transactionCount++;
+ return super.startTransaction(description);
+ }
+
@Override
public synchronized boolean endTransaction(int transactionID, boolean commit) {
- if (viewComposite != null && getTransactionCount() == 1) {
+ if (viewComposite != null && transactionCount == 1) {
// Perform orphan removal only at the end of the outer-most transaction
synchronized (orphanIds) {
checkOrphansForRemoval(false);
@@ -371,6 +378,7 @@ public class CompositeViewerDataTypeManager extends StandAl
}
boolean committed = super.endTransaction(transactionID, commit);
+ transactionCount--;
if (!isTransactionActive() && flattenModCount != -1) {
if (flattenModCount != dbHandle.getModCount()) {
@@ -382,9 +390,6 @@ public class CompositeViewerDataTypeManager extends StandAl
if (committed && dataTypeChanged && changeCallback != null) {
Swing.runLater(() -> changeCallback.call());
- }
-
- if (getTransactionCount() == 0) {
dataTypeChanged = false;
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/CParserTask.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/CParserTask.java
index 50fda6c116..5fd61cfdde 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/CParserTask.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/CParserTask.java
@@ -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();
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/ParseDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/ParseDialog.java
index 21396ceece..5d08775154 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/ParseDialog.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/ParseDialog.java
@@ -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;
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/ActiveDataTypeStores.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/ActiveDataTypeStores.java
new file mode 100644
index 0000000000..77d5dc2a7f
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/ActiveDataTypeStores.java
@@ -0,0 +1,572 @@
+/* ###
+ * 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.util.*;
+
+import generic.jar.ResourceFile;
+import ghidra.app.plugin.core.datamgr.archive.InvalidArchive;
+import ghidra.framework.data.DomainFileProxy;
+import ghidra.framework.model.DomainFile;
+import ghidra.program.model.data.*;
+import ghidra.program.model.dtarchive.*;
+import ghidra.program.model.listing.Program;
+import ghidra.util.*;
+
+/**
+ * Class to track and manage all the open DataTypeStores ( BuiltInDataTypeManager, the active
+ * program, FileDataTypeArchives, and Project DataTypeArchives). This class adds
+ * DataTypeManagerListers to each corresponding DataTypeManager and consolidates those events into
+ * ArchiveManagerListener events that are used by GUI elements such as the DataTypes tree to keep
+ * it in synch with the state of the archives.
+ */
+class ActiveDataTypeStores {
+
+ private Program program;
+ private DataTypeManager builtInDataTypesManager;
+ private List openArchives = new ArrayList<>();
+ private Map invalidArchives = new HashMap<>();
+
+ private DataTypeIndexer dataTypeIndexer;
+ private DataTypeManagerListenerDelegate listenerDelegate;
+ private List dataTypeManagerListeners = new ArrayList<>();
+ private List archiveManagerlisteners = new ArrayList<>();
+
+ // maintain a set of archives that should automatically be opened the next time the tool is run
+ private Set rememberedArchives = new HashSet<>();
+
+ // Updated anytime any datatype or category changes in any open archive, including the program
+ // archive. Currently used by data type tree nodes to know if their tooltip cache is stale.
+ private volatile long modCount = 0;
+
+ ActiveDataTypeStores() {
+ listenerDelegate = new DataTypeManagerListenerDelegate();
+ builtInDataTypesManager = BuiltInDataTypeManager.getDataTypeManager();
+ builtInDataTypesManager.addDataTypeManagerListener(listenerDelegate);
+ dataTypeIndexer = new DataTypeIndexer();
+ dataTypeIndexer.addDataTypeManager(builtInDataTypesManager);
+ }
+
+ void dispose() {
+ removeAllArchives();
+ dataTypeIndexer.removeDataTypeManager(builtInDataTypesManager);
+ builtInDataTypesManager.removeDataTypeManagerListener(listenerDelegate);
+
+ }
+
+ void setProgram(Program newProgram) {
+ if (this.program != null) {
+ this.program.getDataTypeManager().removeDataTypeManagerListener(listenerDelegate);
+ dataTypeIndexer.removeDataTypeManager(this.program.getDataTypeManager());
+ notifyProgramClosed();
+ this.program = null;
+ }
+ if (newProgram != null) {
+ this.program = newProgram;
+ newProgram.getDataTypeManager().addDataTypeManagerListener(listenerDelegate);
+ dataTypeIndexer.addDataTypeManager(newProgram.getDataTypeManager());
+ notifyProgramOpened();
+ }
+ }
+
+ void addArchive(PersistentDataTypeArchive archive, boolean rememberInTool) {
+ archive.addConsumer(this);
+ openArchives.add(archive);
+ syncArchiveNames(archive);
+ archive.getDataTypeManager().addDataTypeManagerListener(listenerDelegate);
+ dataTypeIndexer.addDataTypeManager(archive.getDataTypeManager());
+ if (rememberInTool) {
+ rememberedArchives.add(archive);
+ }
+ notifyArchiveOpened(archive);
+ }
+
+ /**
+ * Removes all open archives from the service
+ */
+ void removeAllArchives() {
+ // this list will get modified as we close archives, so work from a copy
+ List copy = new ArrayList<>(openArchives);
+ for (PersistentDataTypeArchive archive : copy) {
+ removeArchive(archive);
+ }
+ }
+
+ /**
+ * Closes the given archive.
+ * @param archive the archive to close in the tool
+ */
+ void removeArchive(PersistentDataTypeArchive archive) {
+
+ if (!openArchives.remove(archive)) {
+ return;
+ }
+
+ archive.getDataTypeManager().removeDataTypeManagerListener(listenerDelegate);
+ dataTypeIndexer.removeDataTypeManager(archive.getDataTypeManager());
+
+ rememberedArchives.remove(archive);
+ archive.release(this);
+ notifyArchiveClosed(archive);
+ }
+
+ /**
+ * Adds an ArchiveManagerListener
+ * @param listener the listener
+ */
+ void addArchiveManagerListener(ArchiveManagerListener listener) {
+ archiveManagerlisteners.add(listener);
+ }
+
+ boolean contains(FileDataTypeArchive archive) {
+ return openArchives.contains(archive);
+ }
+
+ boolean isRemembered(PersistentDataTypeArchive archive) {
+ return rememberedArchives.contains(archive);
+ }
+
+ ProjectDataTypeArchive getArchiveForDomainFile(DomainFile domainFile, int version) {
+ for (PersistentDataTypeArchive archive : openArchives) {
+ if (archive instanceof ProjectDataTypeArchive projectArchive) {
+ DomainFile openedDf = projectArchive.getDomainFile();
+ int openedVersion = openedDf.getVersion();
+ if (openedDf instanceof DomainFileProxy proxy) {
+ openedDf = proxy.getOriginalDomainFile();
+ }
+ if (openedVersion == version && domainFile.equals(openedDf)) {
+ return projectArchive;
+ }
+ }
+ }
+ return null;
+ }
+
+ FileDataTypeArchive getArchiveForFile(ResourceFile file) {
+ for (PersistentDataTypeArchive archive : openArchives) {
+ if (archive instanceof FileDataTypeArchive fileArchive) {
+ if (file.equals(fileArchive.getFile())) {
+ return fileArchive;
+ }
+ }
+ }
+ return null;
+ }
+
+ void archiveNameChanged(String fileId, String newName) {
+ if (program != null) {
+ updateSourceArchiveName(program.getDataTypeManager(), fileId, newName);
+ }
+ for (PersistentDataTypeArchive archive : openArchives) {
+ if (!archive.isChangeable()) {
+ continue;
+ }
+ DataTypeManager dataTypeManager = archive.getDataTypeManager();
+ updateSourceArchiveName(dataTypeManager, fileId, newName);
+ }
+ }
+
+ /**
+ * Removes an ArchiveManagerListene3r
+ * @param listener the listener to remove
+ */
+ void removeArchiveManagerListener(ArchiveManagerListener listener) {
+ archiveManagerlisteners.remove(listener);
+ }
+
+ /**
+ * {@return a list of all open DataTypeManagers in the tool}
+ */
+ DataTypeManager[] getDataTypeManagers() {
+ List managers = new ArrayList<>();
+ managers.add(builtInDataTypesManager);
+ if (program != null) {
+ managers.add(program.getDataTypeManager());
+ }
+ for (PersistentDataTypeArchive archive : openArchives) {
+ managers.add(archive.getDataTypeManager());
+ }
+ return managers.toArray(new DataTypeManager[managers.size()]);
+ }
+
+ /**
+ * {@return a list of all open file or project archives}
+ */
+ List getArchives() {
+ return new ArrayList<>(openArchives);
+ }
+
+ /**
+ * Returns all favorite DataTypes in all archives.
+ * @return all favorite DataTypes in all archives.
+ */
+ List getFavoriteDataTypes() {
+ List list = new ArrayList<>();
+ list.addAll(builtInDataTypesManager.getFavorites());
+ if (program != null) {
+ list.addAll(program.getDataTypeManager().getFavorites());
+ }
+ for (PersistentDataTypeArchive archive : openArchives) {
+ DataTypeManager dataTypeManager = archive.getDataTypeManager();
+ list.addAll(dataTypeManager.getFavorites());
+ }
+
+ return list;
+ }
+
+ Set getRememberedArchives() {
+ return rememberedArchives;
+ }
+
+ /**
+ * {@return a list of all open file archives in the tool}
+ */
+ List getOpenFileArchives() {
+ List archiveList = new ArrayList<>();
+ for (PersistentDataTypeArchive archive : openArchives) {
+ if (archive instanceof FileDataTypeArchive fileArchive) {
+ archiveList.add(fileArchive);
+ }
+ }
+ return archiveList;
+ }
+
+ /**
+ * {@return a list of all open project archives in the tool}
+ */
+ List getOpenProjectArchives() {
+ List archiveList = new ArrayList<>();
+ for (PersistentDataTypeArchive archive : openArchives) {
+ if (archive instanceof ProjectDataTypeArchive projectArchive) {
+ archiveList.add(projectArchive);
+ }
+ }
+ return archiveList;
+ }
+
+ List getSortedDataTypeList() {
+ return dataTypeIndexer.getSortedDataTypeList();
+ }
+
+ List getSortedCategoryPathList() {
+ return dataTypeIndexer.getSortedCategoryPathList();
+ }
+
+ /**
+ * Adds a listener for when DataTypes are added/removed/changed.
+ * @param listener the listener to be notified
+ */
+ void addDataTypeManagerChangeListener(DataTypeManagerChangeListener listener) {
+ dataTypeManagerListeners.add(listener);
+ }
+
+ void removeDataTypeManagerChangeListener(DataTypeManagerChangeListener listener) {
+ dataTypeManagerListeners.remove(listener);
+ }
+
+ /**
+ * {@return the DatatypeManager associated with the given SourceArchive}
+ * @param source the SourceArchive to find its associated DataTypeManager
+ */
+ DataTypeManager getDataTypeManager(SourceArchive source) {
+ return getDataTypeManager(source.getSourceArchiveID());
+ }
+
+ DataTypeManager getDataTypeManager(UniversalID id) {
+ for (PersistentDataTypeArchive archive : openArchives) {
+ DataTypeManager dataTypeManager = archive.getDataTypeManager();
+ UniversalID universalID = dataTypeManager.getUniversalID();
+ if ((universalID != null) && universalID.equals(id)) {
+ return dataTypeManager;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the current modification count which is incremented anytime any archive or any
+ * category or datatype it contains is changed in any way. This includes the datatypes in
+ * the current program.
+ * @return the current modification count.
+ */
+ long getModificationCount() {
+ return modCount;
+ }
+
+ boolean isAlreadyOpen(SourceArchive source) {
+ if (getDataTypeManager(source) != null) {
+ return true;
+ }
+ return invalidArchives.containsKey(source.getSourceArchiveID());
+ }
+
+ void createInvalidArchive(SourceArchive sourceArchive) {
+ String name = sourceArchive.getName();
+ UniversalID id = sourceArchive.getSourceArchiveID();
+ ArchiveType type = sourceArchive.getArchiveType();
+ String domainFileId = sourceArchive.getDomainFileID();
+
+ InvalidArchive invalidArchive = new InvalidArchive(name, id, type, domainFileId);
+ invalidArchives.put(id, invalidArchive);
+ notifyInvalidArchiveAdded(invalidArchive);
+
+ }
+
+ /**
+ * Removes the given InvalidArchive from the tool
+ * @param archive the invalid archive to remove from the tool
+ */
+ void removeInvalidArchive(InvalidArchive archive) {
+ invalidArchives.remove(archive.id());
+ notifyInvalidArchiveRemoved(archive);
+ }
+
+ Program getProgram() {
+ return program;
+ }
+
+ List getInvalidArchives() {
+ return new ArrayList<>(invalidArchives.values());
+ }
+
+ void notifyStateChanged(DataTypeStore dataTypeStore) {
+ Swing.runNow(() -> {
+ for (ArchiveManagerListener listener : archiveManagerlisteners) {
+ listener.stateChanged(dataTypeStore);
+ }
+ });
+ }
+
+ private void notifyProgramClosed() {
+ SystemUtilities.runSwingNow(() -> {
+ for (ArchiveManagerListener listener : archiveManagerlisteners) {
+ listener.programClosed(program);
+ }
+ });
+ }
+
+ private void notifyArchiveOpened(PersistentDataTypeArchive archive) {
+ SystemUtilities.runSwingNow(() -> {
+ for (ArchiveManagerListener listener : archiveManagerlisteners) {
+ listener.archiveOpened(archive);
+ }
+ });
+ }
+
+ private void notifyInvalidArchiveAdded(InvalidArchive archive) {
+ SystemUtilities.runSwingNow(() -> {
+ for (ArchiveManagerListener listener : archiveManagerlisteners) {
+ listener.invalidArchiveAdded(archive);
+ }
+ });
+ }
+
+ private void notifyInvalidArchiveRemoved(InvalidArchive archive) {
+ SystemUtilities.runSwingNow(() -> {
+ for (ArchiveManagerListener listener : archiveManagerlisteners) {
+ listener.invalidArchiveRemoved(archive);
+ }
+ });
+ }
+
+ private void notifyArchiveClosed(PersistentDataTypeArchive archive) {
+ SystemUtilities.runSwingNow(() -> {
+ for (ArchiveManagerListener listener : archiveManagerlisteners) {
+ listener.archiveClosed(archive);
+ }
+ });
+ }
+
+ private void notifyProgramOpened() {
+ SystemUtilities.runSwingNow(() -> {
+ for (ArchiveManagerListener listener : archiveManagerlisteners) {
+ listener.programOpened(program);
+ }
+ });
+ }
+
+ /**
+ * Update the given archive and any other open archives to have the up-to-date archive names,
+ * as names may have changed while archives were not open.
+ * @param archive the archive
+ */
+ private void syncArchiveNames(PersistentDataTypeArchive archive) {
+ try {
+ DataTypeManager dtm = archive.getDataTypeManager();
+ if (program != null) {
+ synchronizeSourceArchiveNames(dtm, program.getDataTypeManager());
+ }
+ for (PersistentDataTypeArchive openArchive : openArchives) {
+ synchronizeSourceArchiveNames(dtm, openArchive.getDataTypeManager());
+ }
+ }
+ catch (Exception e) {
+ // can't update now (we are probably immutable), no problem
+ }
+ }
+
+ private void synchronizeSourceArchiveNames(DataTypeManager dtm1, DataTypeManager dtm2) {
+ updateSourceArchiveName(dtm1, dtm2);
+ updateSourceArchiveName(dtm2, dtm1);
+ }
+
+ private void updateSourceArchiveName(DataTypeManager destination, DataTypeManager source) {
+ if (!destination.getDataStore().isChangeable()) {
+ return;
+ }
+ destination.withTransaction("Udaate Data Tpye Source Archive Name", () -> {
+ UniversalID id = source.getUniversalID();
+ String name = source.getName();
+ destination.updateSourceArchiveName(id, name);
+ });
+
+ }
+
+ private void updateSourceArchiveName(DataTypeManager dataTypeManager, String fileID,
+ String name) {
+ dataTypeManager.withTransaction("Update Data Type Source Archive Name",
+ () -> dataTypeManager.updateSourceArchiveName(fileID, name));
+ }
+
+ class DataTypeManagerListenerDelegate implements DataTypeManagerChangeListener {
+
+ @Override
+ public void categoryAdded(DataTypeManager dtm, CategoryPath path) {
+ modCount++;
+ for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
+ listener.categoryAdded(dtm, path);
+ }
+ }
+
+ @Override
+ public void categoryMoved(DataTypeManager dtm, CategoryPath oldPath, CategoryPath newPath) {
+ modCount++;
+ for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
+ listener.categoryMoved(dtm, oldPath, newPath);
+ }
+ }
+
+ @Override
+ public void categoryRemoved(DataTypeManager dtm, CategoryPath path) {
+ modCount++;
+ for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
+ listener.categoryRemoved(dtm, path);
+ }
+ }
+
+ @Override
+ public void categoryRenamed(DataTypeManager dtm, CategoryPath oldPath,
+ CategoryPath newPath) {
+ modCount++;
+ for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
+ listener.categoryRenamed(dtm, oldPath, newPath);
+ }
+ }
+
+ @Override
+ public void dataTypeAdded(DataTypeManager dtm, DataTypePath path) {
+ modCount++;
+ for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
+ listener.dataTypeAdded(dtm, path);
+ }
+ }
+
+ @Override
+ public void dataTypeChanged(DataTypeManager dtm, DataTypePath path) {
+ modCount++;
+ for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
+ listener.dataTypeChanged(dtm, path);
+ }
+ }
+
+ @Override
+ public void dataTypeMoved(DataTypeManager dtm, DataTypePath oldPath, DataTypePath newPath) {
+ modCount++;
+ for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
+ listener.dataTypeMoved(dtm, oldPath, newPath);
+ }
+ }
+
+ @Override
+ public void dataTypeRemoved(DataTypeManager dtm, DataTypePath path) {
+ modCount++;
+ for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
+ listener.dataTypeRemoved(dtm, path);
+ }
+ }
+
+ @Override
+ public void dataTypeRenamed(DataTypeManager dtm, DataTypePath oldPath,
+ DataTypePath newPath) {
+ modCount++;
+ for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
+ listener.dataTypeRenamed(dtm, oldPath, newPath);
+ }
+ }
+
+ @Override
+ public void dataTypeReplaced(DataTypeManager dtm, DataTypePath oldPath,
+ DataTypePath newPath, DataType newDataType) {
+ modCount++;
+ for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
+ listener.dataTypeReplaced(dtm, oldPath, newPath, newDataType);
+ }
+ }
+
+ @Override
+ public void favoritesChanged(DataTypeManager dtm, DataTypePath path, boolean isFavorite) {
+ modCount++;
+ for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
+ listener.favoritesChanged(dtm, path, isFavorite);
+ }
+ }
+
+ @Override
+ public void sourceArchiveAdded(DataTypeManager dataTypeManager,
+ SourceArchive dataTypeSource) {
+ modCount++;
+ for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
+ listener.sourceArchiveAdded(dataTypeManager, dataTypeSource);
+ }
+ }
+
+ @Override
+ public void sourceArchiveChanged(DataTypeManager dataTypeManager,
+ SourceArchive dataTypeSource) {
+ modCount++;
+ for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
+ listener.sourceArchiveChanged(dataTypeManager, dataTypeSource);
+ }
+ }
+
+ @Override
+ public void programArchitectureChanged(DataTypeManager dataTypeManager) {
+ modCount++;
+ for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
+ listener.programArchitectureChanged(dataTypeManager);
+ }
+ }
+
+ @Override
+ public void restored(DataTypeManager dataTypeManager) {
+ modCount++;
+ for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
+ listener.restored(dataTypeManager);
+ }
+ }
+ }
+
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ArchiveFileChooser.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/ArchiveFileChooser.java
similarity index 87%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ArchiveFileChooser.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/ArchiveFileChooser.java
index f9d5b01f27..ef40efb1fc 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ArchiveFileChooser.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/ArchiveFileChooser.java
@@ -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);
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/ArchiveManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/ArchiveManager.java
new file mode 100644
index 0000000000..b552e697fb
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/ArchiveManager.java
@@ -0,0 +1,826 @@
+/* ###
+ * 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.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.Set;
+
+import docking.widgets.pathmanager.PathManager;
+import docking.widgets.tree.GTree;
+import docking.widgets.tree.GTreeState;
+import generic.jar.ResourceFile;
+import generic.util.Path;
+import ghidra.app.plugin.core.datamgr.archive.DuplicateIdException;
+import ghidra.app.plugin.core.datamgr.archive.InvalidArchive;
+import ghidra.app.plugin.core.datamgr.util.DataTypeArchiveUtility;
+import ghidra.app.services.Recover;
+import ghidra.app.services.Upgrade;
+import ghidra.framework.main.AppInfo;
+import ghidra.framework.model.*;
+import ghidra.framework.plugintool.PluginTool;
+import ghidra.program.database.dtarchive.DataTypeArchiveContentHandler;
+import ghidra.program.database.dtarchive.DataTypeArchiveFactory;
+import ghidra.program.model.data.*;
+import ghidra.program.model.dtarchive.*;
+import ghidra.program.model.listing.Program;
+import ghidra.util.Msg;
+import ghidra.util.UniversalID;
+import ghidra.util.exception.*;
+import ghidra.util.task.TaskLauncher;
+import ghidra.util.task.TaskMonitor;
+
+/**
+ * Helper class to create, open, and close DataTypeArchives. Internally, it uses an
+ * {@link ActiveDataTypeStores} to track all open archives in the tool, maintain a
+ * complete index of all datatypes open, and remember which archives should be automatically
+ * opened when the tool is re-launched.
+ */
+public class ArchiveManager {
+ private static final String[] UNALLOWED_ARCHIVE_PATH_FRAGMENTS = new String[] {
+ "/Ghidra/Extensions/", "/Ghidra/docs/", "/Ghidra/Features/", "/Ghidra/Test/" };
+
+ public static final String OLD_DATA_TYPE_ARCHIVE_PATH_KEY = "DATA_TYPE_ARCHIVE_PATH";
+ public static final String DATA_TYPE_ARCHIVE_PATH_KEY = "DATATYPE_ARCHIVE_PATHS";
+ public static final String DISABLED_DATA_TYPE_ARCHIVE_PATH_KEY =
+ "DISABLED_DATA_TYPE_ARCHIVE_PATH";
+
+ private ActiveDataTypeStores openStores;
+ private DataTypeManagerPlugin plugin;
+ private MyFolderListener folderListener;
+
+ public ArchiveManager(DataTypeManagerPlugin plugin) {
+ this.plugin = plugin;
+ openStores = new ActiveDataTypeStores();
+ initializeFavorites();
+
+ folderListener = new MyFolderListener();
+ PluginTool tool = plugin.getTool();
+ Project project = tool.getProject();
+ project.getProjectData().addDomainFolderChangeListener(folderListener);
+ }
+
+ /**
+ * Close and reopen the given archive, preserving the tree selection
+ * @param archive the archive to reopen
+ * @return the reopened archive instance. The old instance is now invalid
+ */
+ public PersistentDataTypeArchive reopenArchive(PersistentDataTypeArchive archive) {
+ if (archive instanceof FileDataTypeArchive fileArchive) {
+ boolean changeable = fileArchive.isChangeable();
+ return reopenFileArchive(fileArchive, changeable);
+ }
+ else if (archive instanceof ProjectDataTypeArchive projectArchive) {
+ return doReopenProjectArchive(projectArchive);
+ }
+ return null;
+ }
+
+ /**
+ * Close and reopen the given FileDataTypeArchive in either update or read-only mode. If going
+ * from read-only to open for update fails, it will attempt to keep it open read-only (It closed
+ * the read-only version before attempt to open it for update.)
+ * @param archive the archive to reopen
+ * @param forUpdate whether or not the archive is modifiable
+ * @return the new archive instance that was reopened
+ */
+ public FileDataTypeArchive reopenFileArchive(FileDataTypeArchive archive, boolean forUpdate) {
+ GTreeState treeState = getTreeState();
+ ResourceFile file = archive.getFile();
+ boolean rememberInTool = false;
+ if (openStores.contains(archive)) {
+ rememberInTool = openStores.isRemembered(archive);
+ openStores.removeArchive(archive);
+ }
+ FileDataTypeArchive reopenedArchive = null;
+ reopenedArchive = openFileArchiveInTask(file, forUpdate, Upgrade.ASK, rememberInTool);
+ if (reopenedArchive == null && forUpdate) {
+ // Open for update failed - try re-open as read-only
+ reopenedArchive = openFileArchiveInTask(file, false, Upgrade.NO, rememberInTool);
+ }
+ restoreTreeState(treeState);
+ return reopenedArchive;
+ }
+
+ /**
+ * Called when the tool is closed
+ */
+ public void dispose() {
+ PluginTool tool = plugin.getTool();
+ Project project = tool.getProject();
+ ProjectData projectData = project.getProjectData();
+ projectData.removeDomainFolderChangeListener(folderListener);
+ openStores.dispose();
+ }
+
+ /**
+ * {@return a list of all archives that have been marked that they should be re-opened when
+ * the tool is re-launched}
+ */
+ public Set getRememberedArchives() {
+ return openStores.getRememberedArchives();
+ }
+
+ /**
+ * Creates a new ProjectDataTypeArchive. The user will be prompted for the folder and name
+ * of the new archive.
+ * @return the newly created ProjectDaaTypeArchive
+ */
+ public ProjectDataTypeArchive createProjectArchive() {
+ CreateProjectArchiveDialog dialog = new CreateProjectArchiveDialog(this);
+
+ plugin.getTool().showDialog(dialog);
+ ProjectDataTypeArchive archive = dialog.getArchive();
+ if (archive != null) {
+ openStores.addArchive(archive, true);
+ archive.release(this);
+ }
+ return archive;
+ }
+
+ /**
+ * Opens the give DomainFile in the tool as a ProjectDataTypeArchive. This method should be
+ * used by clients that are already in the background and have a TaskMonitor that can be
+ * used to cancel the operation.
+ * @param file the DomainFile to open
+ * @param version the version (if the file is versioned, otherwise use DomainFile.DEFAULT_VERSION)
+ * @param upgradeStrategy determine what happens if the archive needs to be upgraded before
+ * opening. The options are to do the upgrade, don't do the upgrade, or ask which pops up a
+ * dialog asking if it is ok to upgrade.
+ * @param recoverStrategy determine what happens if the archive has crash recovery data. The
+ * options are to recover the crash data changes, not recover the changes, or to ask which
+ * popups a dialog asking if the crash recovery data should be used.
+ * @param rememberInTool specifies if this archive should be remembered to be opened the next
+ * time the tool is launched.
+ * @param monitor The task monitor that can be used to cancel the operation
+ * @return new newly opened ProjectDataTypeArchive
+ * @throws VersionException if the archive is not the current version, and either it can't be
+ * upgraded or it was told not to upgrade.
+ * @throws CancelledException if the operation was cancelled
+ * @throws IOException if an general I/O exception occurs while reading the data from the
+ * database file.
+ * @throws DuplicateIdException if the archive has the same id as an already open archive (that
+ * is not from the same DomainFile - this is an unexpected situation)
+ */
+ public ProjectDataTypeArchive openProjectArchive(DomainFile file, int version,
+ Upgrade upgradeStrategy, Recover recoverStrategy, boolean rememberInTool,
+ TaskMonitor monitor)
+ throws VersionException, CancelledException, IOException, DuplicateIdException {
+
+ ProjectDataTypeArchive archive = openStores.getArchiveForDomainFile(file, version);
+ if (archive != null) {
+ return archive;
+ }
+ // The task has the open logic, so create a task and call its openArchive method directly.
+ OpenProjectArchiveTask task = new OpenProjectArchiveTask(file, version,
+ upgradeStrategy, recoverStrategy, this);
+ archive = task.openArchive(monitor);
+ checkForDuplicateArchiveID(archive);
+ openStores.addArchive(archive, rememberInTool);
+ archive.release(this);
+ return archive;
+ }
+
+ /**
+ * Opens the give DomainFile in the tool as a ProjectDataTypeArchive in a background thread.
+ * This method should be used by clients that are working in the swing thread.
+ * @param file the DomainFile to open
+ * @param version the version (if the file is versioned, otherwise use DomainFile.DEFAULT_VERSION)
+ * @param upgradeStrategy determine what happens if the archive needs to be upgraded before
+ * opening. The options are to do the upgrade, don't do the upgrade, or ask which pops up a
+ * dialog asking if it is ok to upgrade.
+ * @param recoverStrategy determine what happens if the archive has crash recovery data. The
+ * options are to recover the crash data changes, not recover the changes, or to ask which
+ * popups a dialog asking if the crash recovery data should be used.
+ * @param rememberInTool specifies if this archive should be remembered to be opened the next
+ * time the tool is launched.
+ * @return the newly opened ProjectArchive or null if the open failed. (Exceptions are caught
+ * and reported in the task)
+ */
+ public ProjectDataTypeArchive openProjectArchiveInTask(DomainFile file, int version,
+ Upgrade upgradeStrategy, Recover recoverStrategy, boolean rememberInTool) {
+ ProjectDataTypeArchive archive = openStores.getArchiveForDomainFile(file, version);
+ if (archive != null) {
+ return archive;
+ }
+ OpenProjectArchiveTask task =
+ new OpenProjectArchiveTask(file, version, upgradeStrategy, recoverStrategy, this);
+ TaskLauncher.launch(task);
+ archive = task.getArchive();
+ if (archive == null) {
+ return null;
+ }
+ try {
+ checkForDuplicateArchiveID(archive);
+ }
+ catch (DuplicateIdException e) {
+ Msg.showError(this, null, "Error Opening Project Archive", e.getMessage());
+ return null;
+ }
+ openStores.addArchive(archive, rememberInTool);
+ archive.release(this);
+ return archive;
+ }
+
+ /**
+ * Creates a new FileDataType archive given a non-existing file
+ * @param file the file to use for the new archive (the file must not currently exist)
+ * @return the newly create FileDataTypeArchive or null if the create failed
+ */
+ public FileDataTypeArchive createFileArchive(File file) {
+ try {
+ FileDataTypeArchive archive = DataTypeArchiveFactory.createFileArchive(file, this);
+ addArchivePath(new ResourceFile(file));
+ openStores.addArchive(archive, true);
+ archive.release(this);
+ return archive;
+ }
+ catch (Exception e) {
+ Msg.showError(this, plugin.getProvider().getComponent(), "Create Archive Failed",
+ "Error creating archive file (" + file.getName() + "): " + e.getMessage());
+ }
+ return null;
+ }
+
+ /**
+ * Opens the give {@link ResourceFile} in the tool as a FileDataTypeArchive. This method should
+ * be used by clients that are already in the background and have a TaskMonitor that can be
+ * used to cancel the operation.
+ * @param file the {@link ResourceFile} to open
+ * @param openForUpdate specifies if the file should be open for update or read-only. Note that
+ * if openForUpdate is true and the ResourceFile does not represent a modifiable file, an
+ * {@link IOException} will be thrown.
+ * @param upgradeStrategy determine what happens if the archive needs to be upgraded before
+ * opening. The options are to do the upgrade, don't do the upgrade, or ask which pops up a
+ * dialog asking if it is ok to upgrade.
+ * @param rememberInTool specifies if this archive should be remembered to be opened the next
+ * time the tool is launched.
+ * @param monitor The task monitor that can be used to cancel the operation
+ * @return new newly opened ProjectDataTypeArchive
+ * @throws VersionException if the archive is not the current version, and either it can't be
+ * upgraded or it was told not to upgrade.
+ * @throws CancelledException if the operation was cancelled
+ * @throws IOException if an general I/O exception occurs while reading the data from the
+ * database file.
+ * @throws DuplicateIdException if the archive has the same id as an already open archive (that
+ * is not from the same DomainFile - this is an unexpected situation)
+ */
+ public FileDataTypeArchive openFileArchive(ResourceFile file, boolean openForUpdate,
+ Upgrade upgradeStrategy, boolean rememberInTool, TaskMonitor monitor)
+ throws VersionException, IOException, DuplicateIdException, CancelledException {
+ FileDataTypeArchive archive = openStores.getArchiveForFile(file);
+ if (archive != null) {
+ if (openForUpdate && !archive.isChangeable()) {
+ // if the file is open read-only and we want it open for update, close the existing
+ openStores.removeArchive(archive);
+ }
+ else {
+ return archive;
+ }
+ }
+ OpenFileArchiveTask task =
+ new OpenFileArchiveTask(file, openForUpdate, upgradeStrategy, this);
+
+ archive = task.openArchive(monitor);
+ if (archive != null) {
+ checkForDuplicateArchiveID(archive);
+ openStores.addArchive(archive, rememberInTool);
+ archive.release(this);
+ }
+ return archive;
+ }
+
+ /**
+ * Opens the give {@link ResourceFile} in the tool as a FileDataTypeArchive in background
+ * thread. This method should be used by clients on the swing thread
+ * @param file the {@link ResourceFile} to open
+ * @param openForUpdate specifies if the file should be open for update or read-only. Note that
+ * if openForUpdate is true and the ResourceFile does not represent a modifiable file, an
+ * {@link IOException} will be thrown.
+ * @param upgradeStrategy determine what happens if the archive needs to be upgraded before
+ * opening. The options are to do the upgrade, don't do the upgrade, or ask which pops up a
+ * dialog asking if it is ok to upgrade.
+ * @param rememberInTool specifies if this archive should be remembered to be opened the next
+ * time the tool is launched.
+ * @return new newly opened FileDataTypeArchive or null if an error occurred. The error will
+ * be reported by the task
+ */
+ public FileDataTypeArchive openFileArchiveInTask(ResourceFile file, boolean openForUpdate,
+ Upgrade upgradeStrategy, boolean rememberInTool) {
+ FileDataTypeArchive archive = openStores.getArchiveForFile(file);
+ if (archive != null) {
+ if (openForUpdate && !archive.isChangeable()) {
+ // if the file is open read-only and we want it open for update, close the existing
+ openStores.removeArchive(archive);
+ }
+ else {
+ return archive;
+ }
+ }
+ OpenFileArchiveTask task =
+ new OpenFileArchiveTask(file, openForUpdate, upgradeStrategy, this);
+ TaskLauncher.launch(task);
+ archive = task.getArchive();
+ if (archive == null) {
+ return null;
+ }
+ try {
+ checkForDuplicateArchiveID(archive);
+ }
+ catch (DuplicateIdException e) {
+ Msg.showError(this, null, "Error Opening Project Archive", e.getMessage());
+ return null;
+ }
+ openStores.addArchive(archive, rememberInTool);
+ archive.release(this);
+ return archive;
+
+ }
+
+ /**
+ * Updates the current program. May be null if the current program is closed or deactivated.
+ * @param program the currently active program or null if the program is closed or about to
+ * be swapped out for another
+ */
+ public void setProgram(Program program) {
+ openStores.setProgram(program);
+ if (program != null) {
+ DataTypeManager programDataTypeManager = program.getDataTypeManager();
+ List sources = programDataTypeManager.getSourceArchives();
+ for (SourceArchive source : sources) {
+ if (openStores.isAlreadyOpen(source)) {
+ continue;
+ }
+ ArchiveType archiveType = source.getArchiveType();
+ if (archiveType == ArchiveType.PROJECT) {
+ findAndOpenProjectArchiveForSource(source);
+ }
+ else if (archiveType == ArchiveType.FILE) {
+ findAndOpenFileArchiveForSource(source);
+ }
+ }
+ }
+ }
+
+ /**
+ * Saves the given archive.
+ * @param archive the DataTypeArchive to save
+ */
+ public void save(PersistentDataTypeArchive archive) {
+ if (!archive.isChanged()) {
+ return;
+ }
+ PluginTool tool = plugin.getTool();
+ tool.prepareToSave(archive);
+ DataTypeArchiveSaveTask task = new DataTypeArchiveSaveTask(archive, tool);
+ TaskLauncher.launch(task);
+ openStores.notifyStateChanged(archive);
+ }
+
+ /**
+ * Removes the SourceArchive corresponding to the invalid archive from the active program
+ * and removes the association from all datatypes with that SourceArchive.
+ * @param archive the InvalidArchive to remove the SourceArchive that it represents
+ */
+ public void removeInvalidArchiveFromProgram(InvalidArchive archive) {
+ closeInvalidArchive(archive);
+ Program program = openStores.getProgram();
+ if (program == null) {
+ return;
+ }
+
+ DataTypeManager programDataTypeManager = program.getDataTypeManager();
+ program.withTransaction("Remove Invalid Source Archive From Program", () -> {
+ UniversalID sourceArchiveID = archive.id();
+ SourceArchive sourceArchive = programDataTypeManager.getSourceArchive(sourceArchiveID);
+ if (sourceArchive != null) {
+ programDataTypeManager.removeSourceArchive(sourceArchive);
+ }
+ });
+ }
+
+ /**
+ * Initiates a save as operation. The user will be prompted for additional information needed
+ * @param archive the archive to do a save as operation on
+ */
+ public void saveAs(PersistentDataTypeArchive archive) {
+ if (!plugin.canCloseDomainObject(archive)) {
+ return;
+ }
+ if (archive instanceof FileDataTypeArchive fileArchive) {
+ saveFileArchiveAs(fileArchive);
+ }
+ else if (archive instanceof ProjectDataTypeArchive projectArchive) {
+ PluginTool tool = plugin.getTool();
+ ProjectArchiveSaveAsDialog dialog =
+ new ProjectArchiveSaveAsDialog(tool, projectArchive);
+ tool.showDialog(dialog);
+ }
+ openStores.notifyStateChanged(archive);
+ }
+
+ /**
+ * Closes all open DataTypeArchives.
+ */
+ public void closeAllArchives() {
+ List archives = openStores.getArchives();
+ for (PersistentDataTypeArchive archive : archives) {
+ openStores.removeArchive(archive);
+ }
+ }
+
+//==================================================================================================
+// Pass through methods
+//==================================================================================================
+ /**
+ * {@return the modification count for the last time any archive had changes}
+ */
+ public long getModificationCount() {
+ return openStores.getModificationCount();
+ }
+
+ /**
+ * {@return the current active program. May be null}
+ */
+ public Program getProgram() {
+ return openStores.getProgram();
+ }
+
+ /**
+ * @return all the current DataTypeManagers in the tool. This includes the built-in
+ * DataTypeManager, the currently active program's DataTypeManager, and all DataTypeArchive's
+ * DataTypeManagers}
+ */
+ public DataTypeManager[] getDataTypeManagers() {
+ return openStores.getDataTypeManagers();
+ }
+
+ /**
+ * Closes the archive from the tool. (May not actually close the archive if some other client
+ * has a consumer registered on the archive.)
+ * @param archive the archive to close with respect to the tool
+ */
+ public void closeArchive(PersistentDataTypeArchive archive) {
+ openStores.removeArchive(archive);
+ }
+
+ /**
+ * {@return a list of all open file or project datatype archives}
+ */
+ public List getOpenArchives() {
+ return openStores.getArchives();
+ }
+
+ /**
+ * {@return a list of all favorite datatypes from all current DataTypeManagers open in the tool}
+ */
+ public List getFavoriteDataTypes() {
+ return openStores.getFavoriteDataTypes();
+ }
+
+ /**
+ * {@return a list of all datatypes from all current DataTypeManagers open in the tool}
+ */
+ public List getSortedDataTypeList() {
+ return openStores.getSortedDataTypeList();
+ }
+
+ /**
+ * {@return a list of all current categories in all current DataTypeManagers open in the tool}
+ */
+ public List getSortedCategoryPathList() {
+ return openStores.getSortedCategoryPathList();
+ }
+
+ /**
+ * Adds a DataTypeManagerChangeListener to all open DataTypeManagers open in the tool}
+ * @param listener the listener to be notified of datatype changes
+ */
+ public void addDataTypeManagerChangeListener(DataTypeManagerChangeListener listener) {
+ openStores.addDataTypeManagerChangeListener(listener);
+ }
+
+ /**
+ * Removes a DataTypeManagerChangeListener from all open DataTypeManagers open in the tool}
+ * @param listener the listener to be removed
+ */
+ public void removeDataTypeManagerChangeListener(DataTypeManagerChangeListener listener) {
+ openStores.removeDataTypeManagerChangeListener(listener);
+ }
+
+ /**
+ * {@return a list of all open FileDataTypeArhives}
+ */
+ public List getOpenFileArchives() {
+ return openStores.getOpenFileArchives();
+ }
+
+ /**
+ * {@return a list of all open ProjetDataTypeArhives}
+ */
+ public List getProjectArchives() {
+ return openStores.getOpenProjectArchives();
+ }
+
+ /**
+ * {@return the DatatypeManager associated with the given SourceArchive}
+ * @param source the SourceArchive to find its associated DataTypeManager
+ */
+ public DataTypeManager getDataTypeManager(SourceArchive source) {
+ return openStores.getDataTypeManager(source);
+ }
+
+ /**
+ * Removes the given InvalidArchive from the tool
+ * @param archive the invalid archive to remove from the tool
+ */
+ public void closeInvalidArchive(InvalidArchive archive) {
+ openStores.removeInvalidArchive(archive);
+ }
+
+ /**
+ * Adds an ArchiveManagerListener to all open DataTypeManagers open in the tool}
+ * @param listener the listener to be notified of archive changes
+ */
+ public void addArchiveManagerListener(ArchiveManagerListener listener) {
+ openStores.addArchiveManagerListener(listener);
+ }
+
+ /**
+ * removes an ArchiveManagerListener from all open DataTypeManagers open in the tool}
+ * @param listener the listener to be removed
+ */
+ public void removeArchiveManagerListener(ArchiveManagerListener listener) {
+ openStores.removeArchiveManagerListener(listener);
+ }
+
+ public List getInvalidArchives() {
+ return openStores.getInvalidArchives();
+ }
+
+//==================================================================================================
+// Private methods
+//==================================================================================================
+ private void saveFileArchiveAs(FileDataTypeArchive archive) {
+ ArchiveFileChooser fileChooser = new ArchiveFileChooser(null);
+ File file = fileChooser.promptUserForFile(archive.getName());
+ fileChooser.dispose();
+ if (file == null) {
+ return;
+ }
+ if (file.exists()) {
+ Msg.showInfo(this, null, "Cannot Perform Save As",
+ "Cannot save archive to " + file.getName() + "\nbecause " +
+ file.getName() + " already exists.");
+ return;
+ }
+ TaskLauncher.launchModal("Save As", monitor -> {
+ try {
+ archive.saveAs(file, monitor);
+ }
+ catch (CancelledException e) {
+ // Use chose this, nothing to report
+ }
+ catch (DuplicateFileException de) {
+ Msg.showError(this, null, "Unable to Save File",
+ "Archive already exists: " + file.getName());
+ }
+ catch (IOException ioe) {
+ Msg.showError(this, null, "Unable to Save File",
+ "Unexpected exception attempting to save archive: " + file.getName(), ioe);
+ }
+ });
+
+ }
+
+ private void findAndOpenProjectArchiveForSource(SourceArchive source) {
+ String domainFileID = source.getDomainFileID();
+ ProjectData projectData = plugin.getTool().getProject().getProjectData();
+ DomainFile domainFile = projectData.getFileByID(domainFileID);
+ if (domainFile == null) {
+ openStores.createInvalidArchive(source);
+ }
+ else {
+ openProjectArchiveInTask(domainFile, DomainFile.DEFAULT_VERSION, Upgrade.ASK,
+ Recover.ASK, true);
+ }
+ }
+
+ private void findAndOpenFileArchiveForSource(SourceArchive sourceArchive) {
+ String name = sourceArchive.getName();
+ UniversalID id = sourceArchive.getSourceArchiveID();
+ if (findAndOpenFileArchive(name, id) == null) {
+ openStores.createInvalidArchive(sourceArchive);
+ }
+ }
+
+ private FileDataTypeArchive findAndOpenFileArchive(String archiveName, UniversalID archiveID) {
+
+ if (archiveName.endsWith(FileDataTypeArchive.SUFFIX)) {
+ archiveName = archiveName.substring(0,
+ archiveName.length() - FileDataTypeArchive.SUFFIX.length());
+ }
+
+ String archiveFileName = archiveName + FileDataTypeArchive.SUFFIX;
+
+ Path[] pathsFromPreferences = getArchivePaths();
+ for (Path path : pathsFromPreferences) {
+ if (!path.isEnabled() || !isAllowedArchivePath(path.getPathAsString())) {
+ continue;
+ }
+ ResourceFile file = new ResourceFile(path.getPath(), archiveFileName);
+ if (file.exists()) {
+ FileDataTypeArchive archive =
+ openFileArchiveInTask(file, false, Upgrade.ASK, false);
+ if (matchesId(archive, archiveID)) {
+ return archive;
+ }
+ openStores.removeArchive(archive);
+ return null;
+ }
+ }
+
+ // Look for archive provided with installation (read-only)
+ ResourceFile file = DataTypeArchiveUtility.findArchiveFile(archiveFileName);
+ if (file == null) {
+ Msg.showError(this, plugin.getProvider().getComponent(), "Open Archive Failed",
+ "Archive file not found: " + archiveFileName + FileDataTypeArchive.SUFFIX);
+ return null;
+ }
+ return openFileArchiveInTask(file, false, Upgrade.ASK, false);
+ }
+
+ private boolean matchesId(FileDataTypeArchive archive, UniversalID archiveID) {
+ return archive != null && archive.getUniversalID().equals(archiveID);
+ }
+
+ /**
+ * Determine if archive path is allowed.
+ * An attempt is made to disallow any path which appears to be contained
+ * within a Ghidra installation.
+ * @param path directory or file archive path
+ * @return true if path is allowed
+ */
+ private boolean isAllowedArchivePath(String path) {
+
+ if (path.startsWith(Path.GHIDRA_HOME)) {
+ return false; // Ghidra type info directories will always be searched
+ }
+
+ for (String unallowed : UNALLOWED_ARCHIVE_PATH_FRAGMENTS) {
+ if (path.indexOf(unallowed) > 0) {
+ // Remembering paths to older Ghidra installations is bad
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private void checkForDuplicateArchiveID(PersistentDataTypeArchive archive) throws DuplicateIdException {
+ UniversalID id = archive.getDataTypeManager().getUniversalID();
+ DataTypeManager existing = openStores.getDataTypeManager(id);
+ if (existing != null) {
+ archive.release(this);
+ throw new DuplicateIdException(archive.getName(), existing.getName());
+ }
+ }
+
+ private ProjectDataTypeArchive doReopenProjectArchive(ProjectDataTypeArchive archive) {
+ // When re-opened the latest version will be opened
+ GTreeState treeState = getTreeState();
+ DomainFile domainFile = archive.getDomainFile();
+ ProjectLocator projectLocator = domainFile.getProjectLocator();
+ String path = domainFile.getPathname();
+ boolean isRemembered = openStores.isRemembered(archive);
+ openStores.removeArchive(archive);
+ ProjectData projectData = AppInfo.getActiveProject().getProjectData(projectLocator);
+ DomainFile file = projectData.getFile(path);
+ archive = openProjectArchiveInTask(file, DomainFile.DEFAULT_VERSION, Upgrade.ASK,
+ Recover.ASK, isRemembered);
+ restoreTreeState(treeState);
+ return archive;
+ }
+
+ private GTreeState getTreeState() {
+ GTree tree = plugin.getProvider().getGTree();
+ return tree.getTreeState();
+ }
+
+ private void restoreTreeState(GTreeState state) {
+ GTree tree = plugin.getProvider().getGTree();
+ tree.restoreTreeState(state);
+ }
+
+ private void initializeFavorites() {
+ BuiltInDataTypeManager dtm = BuiltInDataTypeManager.getDataTypeManager();
+ dtm.setFavorite(dtm.resolve(PointerDataType.dataType, null), true);
+ dtm.setFavorite(dtm.resolve(CharDataType.dataType, null), true);
+ dtm.setFavorite(dtm.resolve(StringDataType.dataType, null), true);
+ dtm.setFavorite(dtm.resolve(TerminatedStringDataType.dataType, null), true);
+ dtm.setFavorite(dtm.resolve(TerminatedUnicodeDataType.dataType, null), true);
+ dtm.setFavorite(dtm.resolve(FloatDataType.dataType, null), true);
+ dtm.setFavorite(dtm.resolve(DoubleDataType.dataType, null), true);
+ dtm.setFavorite(dtm.resolve(LongDoubleDataType.dataType, null), true);
+ dtm.setFavorite(dtm.resolve(IntegerDataType.dataType, null), true);
+ dtm.setFavorite(dtm.resolve(LongDataType.dataType, null), true);
+ dtm.setFavorite(dtm.resolve(UnsignedIntegerDataType.dataType, null), true);
+ dtm.setFavorite(dtm.resolve(UnsignedLongDataType.dataType, null), true);
+ dtm.setFavorite(dtm.resolve(ByteDataType.dataType, null), true);
+ dtm.setFavorite(dtm.resolve(WordDataType.dataType, null), true);
+ dtm.setFavorite(dtm.resolve(DWordDataType.dataType, null), true);
+ dtm.setFavorite(dtm.resolve(QWordDataType.dataType, null), true);
+ }
+
+ /**
+ * @return all archive search paths (both enabled and disabled are included)
+ */
+ private Path[] getArchivePaths() {
+ return PathManager.getPathsFromPreferences(DATA_TYPE_ARCHIVE_PATH_KEY, null,
+ DISABLED_DATA_TYPE_ARCHIVE_PATH_KEY);
+ }
+
+ private void addArchivePath(ResourceFile archiveFilePath) {
+
+ Path newPath = new Path(archiveFilePath.getParentFile());
+ if (!isAllowedArchivePath(newPath.getPathAsString())) {
+ return;
+ }
+
+ Path[] paths = getArchivePaths();
+ for (Path path : paths) {
+ if (path.equals(newPath)) {
+ if (!path.isEnabled()) {
+ path.setEnabled(true);
+ PathManager.savePathsToPreferences(DATA_TYPE_ARCHIVE_PATH_KEY,
+ DISABLED_DATA_TYPE_ARCHIVE_PATH_KEY, paths);
+ }
+ return;
+ }
+ }
+
+ Path[] newPaths = new Path[paths.length + 1];
+ System.arraycopy(paths, 0, newPaths, 0, paths.length);
+ newPaths[paths.length] = newPath;
+
+ PathManager.savePathsToPreferences(DATA_TYPE_ARCHIVE_PATH_KEY,
+ DISABLED_DATA_TYPE_ARCHIVE_PATH_KEY, newPaths);
+ }
+
+//==================================================================================================
+// Inner Classes
+//==================================================================================================
+ private class MyFolderListener extends DomainFolderListenerAdapter {
+
+ @Override
+ public void domainFileStatusChanged(DomainFile file, boolean fileIDset) {
+ if (!DataTypeArchiveContentHandler.DATA_TYPE_ARCHIVE_CONTENT_TYPE
+ .equals(file.getContentType())) {
+ return;
+ }
+
+ ProjectDataTypeArchive existing =
+ openStores.getArchiveForDomainFile(file, DomainFile.DEFAULT_VERSION);
+ if (existing == null) {
+ return;
+ }
+ // we only have to worry about the projectArchive being checked out (going from
+ // not changeable to changeable). The other direction (check-in) is not allowed
+ // while the archive is open, so if it happens, we won't have the archive in our list.
+ if (file.isCheckedOut() && !existing.isChangeable()) {
+ reopenArchive(existing);
+ }
+ }
+
+ @Override
+ public void domainFileRemoved(DomainFolder parentFolder, String name, String fileID) {
+ // ignore
+ }
+
+ @Override
+ public void domainFileRenamed(DomainFile file, String oldName) {
+ if (!DataTypeArchiveContentHandler.DATA_TYPE_ARCHIVE_CONTENT_TYPE
+ .equals(file.getContentType())) {
+ return;
+ }
+ String newName = file.getName();
+ String fileId = file.getFileID();
+ openStores.archiveNameChanged(fileId, newName);
+ }
+ }
+
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/ArchiveManagerListener.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/ArchiveManagerListener.java
new file mode 100644
index 0000000000..7d82c220f9
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/ArchiveManagerListener.java
@@ -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);
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/framework/main/datatree/VersionControlDataTypeArchiveUndoCheckoutAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/ArchiveUndoCheckoutTask.java
similarity index 66%
rename from Ghidra/Features/Base/src/main/java/ghidra/framework/main/datatree/VersionControlDataTypeArchiveUndoCheckoutAction.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/ArchiveUndoCheckoutTask.java
index 950b66b92c..1e359659e4 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/framework/main/datatree/VersionControlDataTypeArchiveUndoCheckoutAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/ArchiveUndoCheckoutTask.java
@@ -4,16 +4,16 @@
* 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;
import java.io.IOException;
import java.util.ArrayList;
@@ -22,15 +22,19 @@ import java.util.List;
import javax.swing.Icon;
import docking.action.MenuData;
+import docking.widgets.tree.GTreeState;
import generic.theme.GIcon;
-import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
-import ghidra.app.plugin.core.datamgr.archive.*;
import ghidra.app.plugin.core.datamgr.editor.DataTypeEditorManager;
+import ghidra.app.plugin.core.datamgr.tree.DataTypeArchiveGTree;
+import ghidra.app.services.Recover;
+import ghidra.app.services.Upgrade;
import ghidra.framework.client.ClientUtil;
import ghidra.framework.main.SaveDataDialog;
import ghidra.framework.main.datatable.DomainFileContext;
+import ghidra.framework.main.datatree.UndoActionDialog;
import ghidra.framework.main.projectdata.actions.VersionControlAction;
import ghidra.framework.model.DomainFile;
+import ghidra.program.model.dtarchive.ProjectDataTypeArchive;
import ghidra.util.exception.AssertException;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.Task;
@@ -39,24 +43,21 @@ import ghidra.util.task.TaskMonitor;
/**
* Action to undo checkouts for domain files in the repository.
*/
-public class VersionControlDataTypeArchiveUndoCheckoutAction extends VersionControlAction {
+public class ArchiveUndoCheckoutTask extends VersionControlAction {
private static final Icon ICON =
new GIcon("icon.base.util.datatree.version.control.archive.dt.checkout.undo");
private DataTypeManagerPlugin dtmPlugin;
- private ArchiveProvider archiveProvider;
/**
* Creates an action to undo checkouts for domain files in the repository.
* @param plugin the plug-in that owns this action.
* @param provider provides a list of domain files to be affected by this action.
*/
- public VersionControlDataTypeArchiveUndoCheckoutAction(DataTypeManagerPlugin plugin,
- ArchiveProvider provider) {
+ public ArchiveUndoCheckoutTask(DataTypeManagerPlugin plugin) {
super("UndoCheckOut", plugin.getName(), plugin.getTool());
this.dtmPlugin = plugin;
- this.archiveProvider = provider;
setPopupMenuData(new MenuData(new String[] { "Undo Checkout" }, ICON, GROUP));
setDescription("Undo checkout");
@@ -65,19 +66,22 @@ public class VersionControlDataTypeArchiveUndoCheckoutAction extends VersionCont
@Override
public void actionPerformed(DomainFileContext context) {
- undoCheckOut();
+ undoCheckOut((DataTypesActionContext) context);
}
@Override
public boolean isEnabledForContext(DomainFileContext context) {
+ if (!(context instanceof DataTypesActionContext dataTypesContext)) {
+ return false;
+ }
if (isFileSystemBusy()) {
return false; // don't block; we should get called again later
}
- List domainFiles = context.getSelectedFiles();
- for (DomainFile domainFile : domainFiles) {
- if (domainFile.isCheckedOut()) {
- return true; // At least one checked out file selected.
+ List archives = dataTypesContext.getSelectedProjectArchives();
+ for (ProjectDataTypeArchive archive : archives) {
+ if (archive.getDomainFile().isCheckedOut()) {
+ return true;
}
}
return false;
@@ -86,19 +90,19 @@ public class VersionControlDataTypeArchiveUndoCheckoutAction extends VersionCont
/**
* Gets the domain files from the provider and then undoes the checkout on any that are
* checked out.
+ * @param context
*/
- protected void undoCheckOut() {
+ protected void undoCheckOut(DataTypesActionContext context) {
if (!checkRepositoryConnected()) {
return;
}
- closeEditorsForUndoCheckOut();
+ List archives = context.getSelectedProjectArchives();
+ closeEditorsForUndoCheckOut(archives);
- List archiveList = archiveProvider.getArchives();
- List unmodifiedCheckOutsList = new ArrayList<>();
- List modifiedCheckOutsList = new ArrayList<>();
- for (Archive archive2 : archiveList) {
- ProjectArchive archive = (ProjectArchive) archive2;
+ List unmodifiedCheckOutsList = new ArrayList<>();
+ List modifiedCheckOutsList = new ArrayList<>();
+ for (ProjectDataTypeArchive archive : archives) {
DomainFile domainFile = archive.getDomainFile();
if (domainFile.isCheckedOut()) {
if (domainFile.modifiedSinceCheckout() || domainFile.isChanged()) {
@@ -119,10 +123,9 @@ public class VersionControlDataTypeArchiveUndoCheckoutAction extends VersionCont
}
}
- private void closeEditorsForUndoCheckOut() {
+ private void closeEditorsForUndoCheckOut(List archives) {
DataTypeEditorManager editorManager = dtmPlugin.getEditorManager();
- List archiveList = archiveProvider.getArchives();
- for (Archive archive : archiveList) {
+ for (ProjectDataTypeArchive archive : archives) {
if (!editorManager.checkEditors(archive.getDataTypeManager(), true)) {
continue;
}
@@ -140,12 +143,12 @@ public class VersionControlDataTypeArchiveUndoCheckoutAction extends VersionCont
* @param modifiedArchivesList the list of archives that have been modified
* @throws CancelledException if cancelled
*/
- protected void undoCheckOuts(List unmodifiedArchivesList,
- List modifiedArchivesList) throws CancelledException {
+ protected void undoCheckOuts(List unmodifiedArchivesList,
+ List modifiedArchivesList) throws CancelledException {
boolean saveCopy = false;
- DomainFile[] selectedFiles = new DomainFile[0];
boolean undoWasCancelled = false;
- List selectedArchives = modifiedArchivesList;
+ List selectedArchives = modifiedArchivesList;
+
// Now confirm the modified ones and undo checkout for the ones the user indicates.
if (modifiedArchivesList.size() > 0) {
UndoActionDialog dialog = new UndoActionDialog("Confirm Undo Checkout",
@@ -153,14 +156,14 @@ public class VersionControlDataTypeArchiveUndoCheckoutAction extends VersionCont
int actionID = dialog.showDialog(tool);
if (actionID != UndoActionDialog.CANCEL) {
saveCopy = dialog.saveCopy();
- selectedFiles = dialog.getSelectedDomainFiles();
+ DomainFile[] selectedFiles = dialog.getSelectedDomainFiles();
selectedArchives = getMatchingArchives(modifiedArchivesList, selectedFiles);
}
else {
throw new CancelledException();
}
}
- if ((unmodifiedArchivesList.size() > 0) || (selectedFiles.length > 0)) {
+ if ((unmodifiedArchivesList.size() > 0) || (selectedArchives.size() > 0)) {
tool.execute(new DataTypeArchiveUndoCheckOutTask(unmodifiedArchivesList,
selectedArchives, saveCopy));
}
@@ -169,12 +172,12 @@ public class VersionControlDataTypeArchiveUndoCheckoutAction extends VersionCont
}
}
- private List getMatchingArchives(List archivesList,
- DomainFile[] selectedFiles) {
- List archiveList =
- new ArrayList<>(selectedFiles.length);
+ private List getMatchingArchives(
+ List archivesList, DomainFile[] selectedFiles) {
+
+ List archiveList = new ArrayList<>(selectedFiles.length);
for (DomainFile domainFile : selectedFiles) {
- DomainFileArchive archive = getArchiveForDomainFile(archivesList, domainFile);
+ ProjectDataTypeArchive archive = getArchiveForDomainFile(archivesList, domainFile);
if (archive != null) {
archiveList.add(archive);
}
@@ -187,9 +190,9 @@ public class VersionControlDataTypeArchiveUndoCheckoutAction extends VersionCont
return archiveList;
}
- private DomainFileArchive getArchiveForDomainFile(List archivesList,
- DomainFile domainFile) {
- for (DomainFileArchive domainFileArchive : archivesList) {
+ private ProjectDataTypeArchive getArchiveForDomainFile(
+ List archivesList, DomainFile domainFile) {
+ for (ProjectDataTypeArchive domainFileArchive : archivesList) {
if (domainFileArchive.getDomainFile() == domainFile) {
return domainFileArchive;
}
@@ -197,10 +200,10 @@ public class VersionControlDataTypeArchiveUndoCheckoutAction extends VersionCont
return null;
}
- private List getDomainFileList(List modifiedArchivesList) {
+ private List getDomainFileList(List modifiedArchivesList) {
List dfList = new ArrayList<>(modifiedArchivesList.size());
- for (DomainFileArchive dfArchive : modifiedArchivesList) {
- dfList.add(dfArchive.getDomainFile());
+ for (ProjectDataTypeArchive archive : modifiedArchivesList) {
+ dfList.add(archive.getDomainFile());
}
return dfList;
}
@@ -224,8 +227,8 @@ public class VersionControlDataTypeArchiveUndoCheckoutAction extends VersionCont
* Task for undoing check out of files that are in version control.
*/
private class DataTypeArchiveUndoCheckOutTask extends Task {
- private List unmodifiedCheckOutsList;
- private List modifiedCheckedOutFiles;
+ private List unmodifiedCheckOutsList;
+ private List modifiedCheckedOutFiles;
private boolean saveCopy;
/**
@@ -235,8 +238,8 @@ public class VersionControlDataTypeArchiveUndoCheckoutAction extends VersionCont
* @param saveCopy true indicates that copies of the modified files should be made
* before undo of the checkout.
*/
- DataTypeArchiveUndoCheckOutTask(List unmodifiedCheckOutsList,
- List modifiedCheckedOutFiles, boolean saveCopy) {
+ DataTypeArchiveUndoCheckOutTask(List unmodifiedCheckOutsList,
+ List modifiedCheckedOutFiles, boolean saveCopy) {
super("Undo Check Out", true, true, true);
this.unmodifiedCheckOutsList = unmodifiedCheckOutsList;
@@ -246,21 +249,20 @@ public class VersionControlDataTypeArchiveUndoCheckoutAction extends VersionCont
@Override
public void run(TaskMonitor monitor) {
+ DataTypeArchiveGTree gTree = dtmPlugin.getProvider().getGTree();
+ GTreeState treeState = gTree.getTreeState();
try {
- for (DomainFileArchive archive : unmodifiedCheckOutsList) {
+ ArchiveManager archiveManager = dtmPlugin.getArchiveManager();
+ for (ProjectDataTypeArchive archive : unmodifiedCheckOutsList) {
DomainFile df = archive.getDomainFile();
if (df.isCheckedOut() && (dtmPlugin != null)) {
- // TODO Need to close archive here if it is open.
- archive.close();
-
+ archiveManager.closeArchive(archive);
df.undoCheckout(false);
-
- // TODO Need to open the archive here if it got closed above.
- dtmPlugin.openArchive(df);
-
+ archiveManager.openProjectArchiveInTask(df, DomainFile.DEFAULT_VERSION,
+ Upgrade.ASK, Recover.ASK, false);
}
}
- for (DomainFileArchive currentArchive : modifiedCheckedOutFiles) {
+ for (ProjectDataTypeArchive currentArchive : modifiedCheckedOutFiles) {
monitor.checkCancelled();
DomainFile currentDF = currentArchive.getDomainFile();
@@ -271,14 +273,10 @@ public class VersionControlDataTypeArchiveUndoCheckoutAction extends VersionCont
monitor.setMessage("Undoing Check Out " + currentDF.getName());
- // TODO Need to close archive here if it is open.
- currentArchive.close();
-
+ archiveManager.closeArchive(currentArchive);
currentDF.undoCheckout(saveCopy);
-
- // TODO Need to open the archive here if it got closed above.
- dtmPlugin.openArchive(currentDF);
-
+ archiveManager.openProjectArchiveInTask(currentDF, DomainFile.DEFAULT_VERSION,
+ Upgrade.ASK, Recover.ASK, true);
}
}
catch (CancelledException e) {
@@ -287,6 +285,7 @@ public class VersionControlDataTypeArchiveUndoCheckoutAction extends VersionCont
catch (IOException e) {
ClientUtil.handleException(repository, e, "Undo Check Out", tool.getToolFrame());
}
+ gTree.restoreTreeState(treeState);
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/CreateProjectArchiveDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/CreateProjectArchiveDialog.java
new file mode 100644
index 0000000000..a584324e3d
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/CreateProjectArchiveDialog.java
@@ -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;
+ }
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeArchiveSaveTask.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeArchiveSaveTask.java
new file mode 100644
index 0000000000..ba5e14c215
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeArchiveSaveTask.java
@@ -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 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;
+ }
+
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DataTypeIndexer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeIndexer.java
similarity index 99%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DataTypeIndexer.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeIndexer.java
index 057579e4a1..c1b9875a62 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DataTypeIndexer.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeIndexer.java
@@ -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.*;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeManagerPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeManagerPlugin.java
index 555cec383b..840ed472c6 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeManagerPlugin.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeManagerPlugin.java
@@ -32,6 +32,7 @@ import docking.Tool;
import docking.action.*;
import docking.action.builder.ActionBuilder;
import docking.actions.PopupActionProvider;
+import docking.widgets.OptionDialog;
import docking.widgets.tree.GTreeNode;
import generic.jar.ResourceFile;
import generic.util.Path;
@@ -39,35 +40,32 @@ import ghidra.app.CorePluginPackage;
import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.plugin.ProgramPlugin;
import ghidra.app.plugin.core.datamgr.actions.RecentlyOpenedArchiveAction;
-import ghidra.app.plugin.core.datamgr.actions.UpdateSourceArchiveNamesAction;
import ghidra.app.plugin.core.datamgr.actions.associate.*;
-import ghidra.app.plugin.core.datamgr.archive.*;
+import ghidra.app.plugin.core.datamgr.archive.DuplicateIdException;
+import ghidra.app.plugin.core.datamgr.archive.InvalidArchive;
import ghidra.app.plugin.core.datamgr.editor.DataTypeEditorManager;
-import ghidra.app.plugin.core.datamgr.tree.ArchiveNode;
+import ghidra.app.plugin.core.datamgr.tree.DataTypeStoreNode;
import ghidra.app.plugin.core.datamgr.tree.DtFilterState;
-import ghidra.app.plugin.core.datamgr.util.DataDropOnBrowserHandler;
-import ghidra.app.plugin.core.datamgr.util.DataTypeChooserDialog;
+import ghidra.app.plugin.core.datamgr.util.*;
import ghidra.app.services.*;
-import ghidra.app.util.HelpTopics;
import ghidra.app.util.datatype.DataTypeSelectionDialog;
import ghidra.framework.Application;
-import ghidra.framework.main.OpenVersionedFileDialog;
import ghidra.framework.model.*;
import ghidra.framework.options.SaveState;
import ghidra.framework.plugintool.PluginInfo;
import ghidra.framework.plugintool.PluginTool;
import ghidra.framework.plugintool.util.PluginStatus;
+import ghidra.framework.store.FileSystem;
import ghidra.program.database.data.ProgramDataTypeManager;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.data.*;
-import ghidra.program.model.listing.DataTypeArchive;
+import ghidra.program.model.dtarchive.*;
import ghidra.program.model.listing.Program;
import ghidra.util.*;
import ghidra.util.data.DataTypeParser.AllowedDataTypes;
import ghidra.util.datastruct.LRUMap;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.VersionException;
-import ghidra.util.task.TaskLauncher;
import ghidra.util.task.TaskMonitor;
/**
@@ -95,8 +93,13 @@ public class DataTypeManagerPlugin extends ProgramPlugin
private static final String STANDARD_ARCHIVE_MENU = "Standard Archive";
private static final String RECENTLY_OPENED_MENU = "Recently Opened Archive";
+ private final static String ARCHIVE_NAMES = "ArchiveNames";
+ private static final String PROJECT_NAME_DELIMETER = ":";
+ private final static String RECENT_NAMES = "RecentArchiveNames";
+ private static final String FAVORITES = "Favorite Dts";
+ private static final String RELATIVE_PATH_PREFIX = ".";
- private DataTypeManagerHandler dataTypeManagerHandler;
+ private ArchiveManager archiveManager;
private DataTypesProvider provider;
private Map recentlyOpenedArchiveMap;
@@ -104,6 +107,7 @@ public class DataTypeManagerPlugin extends ProgramPlugin
private Clipboard clipboard = new Clipboard(getName());
private DataTypeEditorManager editorManager;
private DataTypePropertyManager dataTypePropertyManager;
+ private RecentlyUsedDataType recentlyUsedDataType = new RecentlyUsedDataType();
public DataTypeManagerPlugin(PluginTool tool) {
super(tool);
@@ -122,43 +126,59 @@ public class DataTypeManagerPlugin extends ProgramPlugin
}
};
- dataTypeManagerHandler = new DataTypeManagerHandler(this);
+ archiveManager = new ArchiveManager(this);
dataTypePropertyManager = new DataTypePropertyManager();
provider = new DataTypesProvider(this, "DataTypes Provider");
createActions();
- dataTypeManagerHandler.addArchiveManagerListener(new ArchiveManagerListener() {
+ archiveManager.addArchiveManagerListener(new ArchiveManagerListener() {
@Override
- public void archiveClosed(Archive archive) {
- if (archive instanceof ProjectArchive) {
- ProjectArchive projectArchive = (ProjectArchive) archive;
- projectArchive.getDomainObject().removeListener(DataTypeManagerPlugin.this);
+ public void archiveClosed(PersistentDataTypeArchive archive) {
+ editorManager.dismissEditors(archive.getDataTypeManager());
+ tool.setConfigChanged(true);
+ if (archive instanceof ProjectDataTypeArchive projectArchive) {
+ projectArchive.removeListener(DataTypeManagerPlugin.this);
}
-
- provider.archiveClosed(archive.getDataTypeManager());
+ provider.archiveClosed(archive);
}
@Override
- public void archiveOpened(Archive archive) {
- if (archive instanceof FileArchive) {
- addRecentlyOpenedArchiveFile(((FileArchive) archive).getFile());
+ public void archiveOpened(PersistentDataTypeArchive archive) {
+ tool.setConfigChanged(true);
+ if (archive instanceof FileDataTypeArchive fileArchive) {
+ addRecentlyOpenedArchiveFile(fileArchive.getFile());
}
- else if (archive instanceof ProjectArchive) {
- ProjectArchive projectArchive = (ProjectArchive) archive;
- projectArchive.getDomainObject().addListener(DataTypeManagerPlugin.this);
- addRecentlyOpenedProjectArchive((ProjectArchive) archive);
+ else if (archive instanceof ProjectDataTypeArchive projectArchive) {
+ projectArchive.addListener(DataTypeManagerPlugin.this);
+ addRecentlyOpenedProjectArchive(projectArchive);
}
}
@Override
- public void archiveDataTypeManagerChanged(Archive archive) {
- provider.archiveChanged(archive);
+ public void programOpened(Program program) {
+ // don't care
}
@Override
- public void archiveStateChanged(Archive archive) {
- provider.archiveChanged(archive);
+ public void programClosed(Program program) {
+ // don't care
}
+
+ @Override
+ public void invalidArchiveAdded(InvalidArchive invalidArchive) {
+ // don't care
+ }
+
+ @Override
+ public void invalidArchiveRemoved(InvalidArchive invalidArchive) {
+ // don't care
+ }
+
+ @Override
+ public void stateChanged(DataTypeStore store) {
+ provider.archiveChanged(store.getName());
+ }
+
});
editorManager = new DataTypeEditorManager(this);
@@ -187,7 +207,7 @@ public class DataTypeManagerPlugin extends ProgramPlugin
}
Path path = new Path(file);
String absoluteFilePath = path.getPathAsString();
- if (!absoluteFilePath.endsWith(FileDataTypeManager.SUFFIX)) {
+ if (!absoluteFilePath.endsWith(FileDataTypeArchive.SUFFIX)) {
// ignore invalid archive files
return;
}
@@ -209,7 +229,7 @@ public class DataTypeManagerPlugin extends ProgramPlugin
* @param pathname the pathname
*/
public void addRecentlyOpenedProjectArchive(String projectName, String pathname) {
- String projectPathname = DataTypeManagerHandler.getProjectPathname(projectName, pathname);
+ String projectPathname = getProjectPathname(projectName, pathname);
if (recentlyOpenedArchiveMap.get(projectPathname) != null) {
return;
}
@@ -230,8 +250,8 @@ public class DataTypeManagerPlugin extends ProgramPlugin
* remembered).
* @param pa project archive
*/
- public void addRecentlyOpenedProjectArchive(ProjectArchive pa) {
- String projectPathname = dataTypeManagerHandler.getProjectPathname(pa, true);
+ public void addRecentlyOpenedProjectArchive(ProjectDataTypeArchive pa) {
+ String projectPathname = getProjectPathname(pa, true);
if (projectPathname != null) { // projectPathname will be null if we can't remember it
DomainFile df = pa.getDomainFile();
addRecentlyOpenedProjectArchive(df.getProjectLocator().getName(), df.getPathname());
@@ -249,48 +269,174 @@ public class DataTypeManagerPlugin extends ProgramPlugin
Project project = tool.getProjectManager().getActiveProject();
if (project != null && project.getName().equals(projectName)) {
DomainFile df = project.getProjectData().getFile(pathname);
- if (df != null && DataTypeArchive.class.isAssignableFrom(df.getDomainObjectClass())) {
+ if (df != null &&
+ ProjectDataTypeArchive.class.isAssignableFrom(df.getDomainObjectClass())) {
return df;
}
}
return null;
}
- /**
- * A collection of files that have recently been opened by the user.
- * @return A collection of files that have recently been opened by the user.
- */
- public Collection getRecentlyOpenedArchives() {
- return Collections.unmodifiableSet(recentlyOpenedArchiveMap.keySet());
- }
-
@Override
public void dispose() {
tool.removePopupActionProvider(this);
- dataTypeManagerHandler.closeAllArchives();
- dataTypeManagerHandler.dispose();
+ archiveManager.dispose();
}
@Override
public void readConfigState(SaveState saveState) {
- dataTypeManagerHandler.restore(saveState);
+ restoreArchiveNames(saveState);
+ restoreRecentlyOpenedArchiveNames(saveState);
+ restoreFavorites(saveState);
provider.restore(saveState);
}
@Override
public void writeConfigState(SaveState saveState) {
- dataTypeManagerHandler.save(saveState);
+ saveArchiveNames(saveState);
+ saveRecentlyOpenedArchiveNames(saveState);
+ saveFavorites(saveState);
provider.save(saveState);
}
+ private void restoreRecentlyOpenedArchiveNames(SaveState saveState) {
+ String[] recentFilenames = saveState.getStrings(RECENT_NAMES, null);
+ List archivePaths = resolveArchivePaths(recentFilenames);
+ for (String path : archivePaths) {
+ if (path.startsWith(PROJECT_NAME_DELIMETER)) {
+ String[] projectPathname = parseProjectPathname(path);
+ if (projectPathname != null) {
+ addRecentlyOpenedProjectArchive(projectPathname[0], projectPathname[1]);
+ }
+ }
+ else {
+ ResourceFile file = new ResourceFile(path);
+ if (file.exists()) {
+ file = file.getCanonicalFile();
+ addRecentlyOpenedArchiveFile(file);
+ }
+ }
+ }
+ }
+
+ private void restoreFavorites(SaveState saveState) {
+ String[] names = saveState.getStrings(FAVORITES, new String[0]);
+ if (names.length == 0) {
+ return;
+ }
+ BuiltInDataTypeManager builtinDtm = BuiltInDataTypeManager.getDataTypeManager();
+ Set favorites = new HashSet<>();
+ for (String dtName : names) {
+ DataType dataType = builtinDtm.getDataType(dtName);
+ if (dataType != null) {
+ favorites.add(dataType);
+ }
+ }
+
+ List currentFavoritesList = builtinDtm.getFavorites();
+ for (DataType type : currentFavoritesList) {
+ if (favorites.contains(type)) {
+ favorites.remove(type);
+ }
+ else {
+ builtinDtm.setFavorite(type, false);
+ }
+ }
+ for (DataType dataType : favorites) {
+ builtinDtm.setFavorite(dataType, true);
+ }
+ }
+
+ private void restoreArchiveNames(SaveState saveState) {
+ String[] savedFilenames = saveState.getStrings(ARCHIVE_NAMES, new String[0]);
+ List archivePaths = resolveArchivePaths(savedFilenames);
+ openArchives(archivePaths);
+
+ }
+
+ private void openArchives(List archiveFilenames) {
+ for (String filename : archiveFilenames) {
+ String[] projectPathname = parseProjectPathname(filename);
+ if (projectPathname != null) {
+ DomainFile df = getProjectArchiveFile(projectPathname[0], projectPathname[1]);
+ if (df != null) {
+ archiveManager.openProjectArchiveInTask(df, DomainFile.DEFAULT_VERSION,
+ Upgrade.ASK, Recover.ASK, true);
+ }
+ }
+ else {
+ File file = new File(filename);
+ if (!file.exists()) {
+ continue; // if the file does not exist, skip it.
+ }
+ archiveManager.openFileArchiveInTask(new ResourceFile(file), false, Upgrade.ASK,
+ true);
+ }
+ }
+ }
+
+ private void saveRecentlyOpenedArchiveNames(SaveState saveState) {
+ List recentMenuList = new ArrayList<>();
+ for (String file : recentlyOpenedArchiveMap.keySet()) {
+ recentMenuList.add(file);
+ }
+ saveState.putStrings(RECENT_NAMES, getSaveableArchiveNames(recentMenuList));
+ }
+
+ private void saveArchiveNames(SaveState saveState) {
+ List rememberedArchivePaths = new ArrayList<>();
+ Set rememberedArchives = archiveManager.getRememberedArchives();
+ for (PersistentDataTypeArchive archive : rememberedArchives) {
+ String filePath = null;
+ if (archive instanceof FileDataTypeArchive fileArchive) {
+ ResourceFile file = fileArchive.getFile();
+ rememberedArchivePaths.add(file.getAbsolutePath());
+ }
+ else if (archive instanceof ProjectDataTypeArchive projectArchive) {
+ filePath = getProjectPathname(projectArchive, true);
+ if (filePath != null) {
+ rememberedArchivePaths.add(filePath);
+ }
+ }
+ }
+ saveState.putStrings(ARCHIVE_NAMES, getSaveableArchiveNames(rememberedArchivePaths));
+ }
+
+ private String[] getSaveableArchiveNames(List absoluteFilenameList) {
+ String[] saveableFilenames = new String[absoluteFilenameList.size()];
+ for (int i = 0; i < absoluteFilenameList.size(); i++) {
+ saveableFilenames[i] = getSaveableArchive(absoluteFilenameList.get(i));
+ }
+ return saveableFilenames;
+ }
+
+ private String getSaveableArchive(String absoluteFilename) {
+ if (absoluteFilename.startsWith(PROJECT_NAME_DELIMETER)) {
+ return absoluteFilename;
+ }
+ Path path = new Path(absoluteFilename);
+ return path.getPathAsString();
+ }
+
+ void saveFavorites(SaveState saveState) {
+ BuiltInDataTypeManager builtInDtm = BuiltInDataTypeManager.getDataTypeManager();
+ List favoritesList = builtInDtm.getFavorites();
+ String[] names = new String[favoritesList.size()];
+ for (int i = 0; i < names.length; i++) {
+ DataType dataType = favoritesList.get(i);
+ names[i] = dataType.getPathName();
+ }
+
+ saveState.putStrings(FAVORITES, names);
+ }
+
@Override
public void domainObjectChanged(DomainObjectChangedEvent event) {
if (event.contains(DomainObjectEvent.RESTORED)) {
Object source = event.getSource();
- if (source instanceof DataTypeManagerDomainObject) {
- DataTypeManagerDomainObject domainObject = (DataTypeManagerDomainObject) source;
- provider.domainObjectRestored(domainObject);
- dataTypePropertyManager.domainObjectRestored(domainObject);
+ if (source instanceof PersistentDataTypeArchive archive) {
+ provider.domainObjectRestored(archive);
+ dataTypePropertyManager.domainObjectRestored(archive);
// NOTE: each editor that cares about a restored DataTypeManager must establish
// a DataTypeManagerChangeListener and will be notified via the restored method.
}
@@ -303,7 +449,7 @@ public class DataTypeManagerPlugin extends ProgramPlugin
@Override
protected void programDeactivated(Program program) {
program.removeListener(this);
- dataTypeManagerHandler.programClosed();
+ archiveManager.setProgram(null);
dataTypePropertyManager.programClosed(program);
}
@@ -311,7 +457,7 @@ public class DataTypeManagerPlugin extends ProgramPlugin
protected void programActivated(Program program) {
program.addListener(this);
provider.programActivated(program);
- dataTypeManagerHandler.programOpened(program);
+ archiveManager.setProgram(program);
dataTypePropertyManager.programOpened(program);
}
@@ -325,9 +471,11 @@ public class DataTypeManagerPlugin extends ProgramPlugin
@Override
protected boolean canCloseDomainObject(DomainObject dObj) {
- if (dObj instanceof DataTypeManagerDomainObject) {
- DataTypeManagerDomainObject dtmObject = (DataTypeManagerDomainObject) dObj;
- return editorManager.checkEditors(dtmObject.getDataTypeManager(), true);
+ if (dObj instanceof PersistentDataTypeArchive archive) {
+ return editorManager.checkEditors(archive.getDataTypeManager(), true);
+ }
+ else if (dObj instanceof Program program) {
+ return editorManager.checkEditors(program.getDataTypeManager(), true);
}
return true;
}
@@ -338,21 +486,45 @@ public class DataTypeManagerPlugin extends ProgramPlugin
return false;
}
editorManager.dismissEditors(null);
- dataTypeManagerHandler.updateKnownOpenArchives();
- if (!ArchiveUtils.canClose(dataTypeManagerHandler.getAllModifiedFileArchives(),
- provider.getComponent())) {
- return false;
+ List archives = archiveManager.getOpenFileArchives();
+ for (FileDataTypeArchive archive : archives) {
+ if (!resolveModifiedArchive(archive)) {
+ return false;
+ }
}
return true;
}
+ /**
+ * Prompts the user to save any changes to the given archive in preparation for closing.
+ * @param archive the archive that is to be prompted to save
+ * @return true if the archive can be closed (The user either saved it or declined to save it).
+ * Only returns false if the user cancelled the operation.
+ */
+ public boolean resolveModifiedArchive(PersistentDataTypeArchive archive) {
+
+ if (!archive.isChanged()) {
+ return true;
+ }
+
+ int result =
+ OptionDialog.showYesNoCancelDialog(null, "Save Archive?", "Datatype Archive \"" +
+ archive.getName() + "\" has been changed.\n Do you want to save the changes?");
+
+ if (result == OptionDialog.YES_OPTION) {
+ archiveManager.save(archive);
+ }
+
+ return result != OptionDialog.CANCEL_OPTION;
+ }
+
@Override
protected void close() {
provider.dispose();
}
- public DataTypeManagerHandler getDataTypeManagerHandler() {
- return dataTypeManagerHandler;
+ public ArchiveManager getArchiveManager() {
+ return archiveManager;
}
public DataTypeEditorManager getEditorManager() {
@@ -425,7 +597,7 @@ public class DataTypeManagerPlugin extends ProgramPlugin
private void createStandardArchivesMenu() {
installArchiveMap = new TreeMap<>();
- String gdt = FileDataTypeManager.SUFFIX;
+ String gdt = FileDataTypeArchive.SUFFIX;
List gdts = Application.findFilesByExtensionInApplication(gdt);
for (ResourceFile archiveFile : gdts) {
Path path = new Path(archiveFile);
@@ -505,7 +677,7 @@ public class DataTypeManagerPlugin extends ProgramPlugin
@Override
public DataTypeManager getBuiltInDataTypesManager() {
- return dataTypeManagerHandler.getBuiltInDataTypesManager();
+ return BuiltInDataTypeManager.getDataTypeManager();
}
public DataTypeManager getProgramDataTypeManager() {
@@ -609,77 +781,79 @@ public class DataTypeManagerPlugin extends ProgramPlugin
@Override
public DataTypeManager[] getDataTypeManagers() {
- return dataTypeManagerHandler.getDataTypeManagers();
+ return archiveManager.getDataTypeManagers();
+ }
+
+ @Override
+ public List getDataTypeArchives() {
+ return archiveManager.getOpenArchives();
}
@Override
public void closeArchive(DataTypeManager dtm) {
- dataTypeManagerHandler.closeArchive(dtm);
- provider.archiveClosed(dtm);
+ DataTypeStore dataStore = dtm.getDataStore();
+ if (dataStore instanceof PersistentDataTypeArchive archive) {
+ archiveManager.closeArchive(archive);
+ provider.archiveClosed(archive);
+ }
}
@Override
- public DataTypeManager openDataTypeArchive(String archiveName)
- throws IOException, DuplicateIdException {
- return dataTypeManagerHandler.openArchive(archiveName);
+ public void closeArchive(PersistentDataTypeArchive archive) {
+ archiveManager.closeArchive(archive);
+ provider.archiveClosed(archive);
}
@Override
- public DataTypeManager openArchive(ResourceFile file, boolean acquireWriteLock)
- throws IOException, DuplicateIdException {
- Archive archive = openArchive(file.getFile(true), acquireWriteLock);
- return archive.getDataTypeManager();
+ public FileDataTypeArchive openFileArchive(String archiveName, TaskMonitor monitor)
+ throws IOException, DuplicateIdException, CancelledException {
+ ResourceFile file = DataTypeArchiveUtility.findArchiveFile(archiveName);
+ if (file != null) {
+ try {
+ return openFileArchive(file, false, Upgrade.NO, monitor);
+ }
+ catch (VersionException e) {
+ throw new IOException(e); // legacy service method doesn't throw VersionException
+ }
+ }
+ return null;
}
@Override
- public DataTypeManager openArchive(DomainFile domainFile, TaskMonitor monitor)
+ public FileDataTypeArchive openFileArchive(ResourceFile resourceFile, boolean openForUpdate,
+ Upgrade upgradeStrategy, TaskMonitor monitor)
+ throws IOException, VersionException, DuplicateIdException, CancelledException {
+
+ return archiveManager.openFileArchive(resourceFile, openForUpdate, upgradeStrategy, false,
+ monitor);
+ }
+
+ @Override
+ public ProjectDataTypeArchive openProjectArchive(DomainFile domainFile, Upgrade upgradeStrategy,
+ Recover recoverStrategy, TaskMonitor monitor)
throws VersionException, CancelledException, IOException, DuplicateIdException {
- DataTypeArchive archive = openArchive(domainFile);
- return archive.getDataTypeManager();
- }
-
- public List getAllArchives() {
- return dataTypeManagerHandler.getAllArchives();
- }
-
- public void openProjectDataTypeArchive() {
-
- OpenVersionedFileDialog dialog = new OpenVersionedFileDialog<>(tool,
- "Open Project Data Type Archive", DataTypeArchive.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();
- openArchive(domainFile, version);
- }
- });
-
- tool.showDialog(dialog);
+ return archiveManager.openProjectArchive(domainFile, DomainFile.DEFAULT_VERSION,
+ upgradeStrategy, recoverStrategy, false, monitor);
}
@Override
public List getFavorites() {
- return dataTypeManagerHandler.getFavoriteDataTypes();
+ return archiveManager.getFavoriteDataTypes();
}
@Override
public DataType getRecentlyUsed() {
- return dataTypeManagerHandler.getRecentlyDataType();
+ return recentlyUsedDataType.getDataType();
}
@Override
public List getSortedDataTypeList() {
- return dataTypeManagerHandler.getDataTypeIndexer().getSortedDataTypeList();
+ return archiveManager.getSortedDataTypeList();
}
@Override
public List getSortedCategoryPathList() {
- return dataTypeManagerHandler.getDataTypeIndexer().getSortedCategoryPathList();
+ return archiveManager.getSortedCategoryPathList();
}
@Override
@@ -710,27 +884,33 @@ public class DataTypeManagerPlugin extends ProgramPlugin
@Override
public void setRecentlyUsed(DataType dt) {
- dataTypeManagerHandler.setRecentlyUsedDataType(dt);
+ recentlyUsedDataType = new RecentlyUsedDataType(dt);
+
}
@Override
public void addDataTypeManagerChangeListener(DataTypeManagerChangeListener listener) {
- dataTypeManagerHandler.addDataTypeManagerChangeListener(listener);
+ archiveManager.addDataTypeManagerChangeListener(listener);
}
@Override
public void removeDataTypeManagerChangeListener(DataTypeManagerChangeListener listener) {
- dataTypeManagerHandler.removeDataTypeManagerChangeListener(listener);
+ archiveManager.removeDataTypeManagerChangeListener(listener);
}
@Override
public Set getPossibleEquateNames(long value) {
- return dataTypeManagerHandler.getPossibleEquateNames(value);
+ Set equateNames = new HashSet<>();
+ DataTypeManager[] dataTypeManagers = archiveManager.getDataTypeManagers();
+ for (DataTypeManager dtm : dataTypeManagers) {
+ dtm.findEnumValueNames(value, equateNames);
+ }
+ return equateNames;
}
@Override
public Class>[] getSupportedDataTypes() {
- return new Class[] { DataTypeArchive.class };
+ return new Class[] { ProjectDataTypeArchive.class };
}
@Override
@@ -740,10 +920,12 @@ public class DataTypeManagerPlugin extends ProgramPlugin
}
boolean addedArchives = false;
- for (DomainFile element : data) {
- if (element != null &&
- DataTypeArchive.class.isAssignableFrom(element.getDomainObjectClass())) {
- openArchive(element);
+ for (DomainFile df : data) {
+ if (df != null &&
+ ProjectDataTypeArchive.class.isAssignableFrom(df.getDomainObjectClass())) {
+ archiveManager.openProjectArchiveInTask(df, DomainFile.DEFAULT_VERSION, Upgrade.ASK,
+ Recover.ASK, true);
+
addedArchives = true;
}
}
@@ -760,44 +942,22 @@ public class DataTypeManagerPlugin extends ProgramPlugin
SwingUtilities.invokeLater(() -> tool.toFront(provider));
}
- public DataTypeArchive openArchive(DomainFile df) {
- return openArchive(df, -1);
- }
-
- public DataTypeArchive openArchive(final DomainFile df, final int version) {
- OpenDomainFileTask task =
- new OpenDomainFileTask(df, version, tool, DataTypeManagerPlugin.this);
- new TaskLauncher(task, tool.getToolFrame(), 0);
- return task.getArchive();
- }
-
public boolean commit(DataType dataType) {
- return DataTypeSynchronizer.commit(dataTypeManagerHandler, dataType);
+ return DataTypeSynchronizer.commit(archiveManager, dataType);
}
public boolean update(DataType dataType) {
- return DataTypeSynchronizer.update(dataTypeManagerHandler, dataType);
+ return DataTypeSynchronizer.update(archiveManager, dataType);
}
public boolean revert(DataType dataType) {
- return DataTypeSynchronizer.update(dataTypeManagerHandler, dataType);
+ return DataTypeSynchronizer.update(archiveManager, dataType);
}
public void disassociate(DataType dataTypes) {
DataTypeSynchronizer.disassociate(dataTypes);
}
- @Override
- public Archive openArchive(DataTypeArchive dataTypeArchive) {
- return dataTypeManagerHandler.openArchive(dataTypeArchive);
- }
-
- @Override
- public Archive openArchive(File file, boolean acquireWriteLock)
- throws IOException, DuplicateIdException {
- return dataTypeManagerHandler.openArchive(file, acquireWriteLock, false);
- }
-
public AddressSetView getCurrentSelection() {
return currentSelection;
}
@@ -809,15 +969,13 @@ public class DataTypeManagerPlugin extends ProgramPlugin
}
DataTypesActionContext dtContext = (DataTypesActionContext) context;
GTreeNode selectedNode = dtContext.getClickedNode();
- if (!(selectedNode instanceof ArchiveNode)) {
+ if (!(selectedNode instanceof DataTypeStoreNode archiveNode)) {
return null;
}
List actions = new ArrayList<>();
- ArchiveNode archiveNode = (ArchiveNode) selectedNode;
- Archive archive = archiveNode.getArchive();
- DataTypeManager dataTypeManager = archive.getDataTypeManager();
+ DataTypeManager dataTypeManager = archiveNode.getDataTypeManager();
if (dataTypeManager == null) {
return null;
}
@@ -825,18 +983,18 @@ public class DataTypeManagerPlugin extends ProgramPlugin
String group = "FGroup"; // after 'Edit'
List sourceArchives = dataTypeManager.getSourceArchives();
for (SourceArchive sourceArchive : sourceArchives) {
- DataTypeManager sourceDTM = dataTypeManagerHandler.getDataTypeManager(sourceArchive);
+ DataTypeManager sourceDTM = archiveManager.getDataTypeManager(sourceArchive);
boolean canUpdate = canUpdate(sourceArchive, sourceDTM);
boolean canCommit = canCommit(sourceArchive, sourceDTM);
- actions.add(new SyncRefreshAction(this, dataTypeManagerHandler, dataTypeManager,
+ actions.add(new SyncRefreshAction(this, archiveManager, dataTypeManager,
archiveNode, sourceArchive, true));
- actions.add(new CommitAction(this, dataTypeManagerHandler, dataTypeManager, archiveNode,
+ actions.add(new CommitAction(this, archiveManager, dataTypeManager, archiveNode,
sourceArchive, canCommit));
- actions.add(new UpdateAction(this, dataTypeManagerHandler, dataTypeManager, archiveNode,
+ actions.add(new UpdateAction(this, archiveManager, dataTypeManager, archiveNode,
sourceArchive, canUpdate));
- actions.add(new RevertAction(this, dataTypeManagerHandler, dataTypeManager, archiveNode,
+ actions.add(new RevertAction(this, archiveManager, dataTypeManager, archiveNode,
sourceArchive, canCommit));
- actions.add(new DisassociateAction(this, dataTypeManagerHandler, dataTypeManager,
+ actions.add(new DisassociateAction(this, archiveManager, dataTypeManager,
archiveNode, sourceArchive));
}
@@ -846,11 +1004,6 @@ public class DataTypeManagerPlugin extends ProgramPlugin
String pullRightName = popupData.getMenuPath()[0];
tool.setMenuGroup(new String[] { pullRightName }, group);
}
-
- UpdateSourceArchiveNamesAction action =
- new UpdateSourceArchiveNamesAction(this, dataTypeManager);
- action.getPopupMenuData().setMenuGroup(group);
- actions.add(action);
return actions;
}
@@ -875,10 +1028,10 @@ public class DataTypeManagerPlugin extends ProgramPlugin
// Program Manager will take care of programs.
// We need to take care of Project Data Type Archives.
List domainFileList = new ArrayList<>();
- List allArchives = dataTypeManagerHandler.getAllArchives();
- for (Archive archive : allArchives) {
- if (archive instanceof ProjectArchive && archive.isModifiable()) {
- domainFileList.add(((ProjectArchive) archive).getDomainFile());
+ List allArchives = archiveManager.getProjectArchives();
+ for (ProjectDataTypeArchive archive : allArchives) {
+ if ((archive instanceof ProjectDataTypeArchive pa) && archive.isChangeable()) {
+ domainFileList.add(pa.getDomainFile());
}
}
return domainFileList.toArray(new DomainFile[domainFileList.size()]);
@@ -886,10 +1039,173 @@ public class DataTypeManagerPlugin extends ProgramPlugin
@Override
protected boolean saveData() {
- if (!ArchiveUtils.canClose(dataTypeManagerHandler.getAllFileOrProjectArchives(),
- provider.getComponent())) {
- return false;
+ // Note: project archives are saved via this method and file archives are saved via
+ // the canClose() method. The reason is to prevent duplicate asks to save an archive.
+ //
+ // There is an inconsistency between these methods getting called depending on whether just
+ // a tool is being closed or the front-end is closing. This method is only called in the
+ // case when just a tool is closing. When the front-end is closing, this call is skipped
+ // and instead a generic dialog for any changed project domain object (which includes
+ // programs and project datatype archives) is called.
+ //
+ // So, if we were to try and save file archives here, they wouldn't get saved since this
+ // method isn't called when the front-end is closed.
+
+ List archives = archiveManager.getProjectArchives();
+ for (ProjectDataTypeArchive archive : archives) {
+ if (!resolveModifiedArchive(archive)) {
+ return false;
+ }
}
return true;
}
+
+ /**
+ * Create project archive path string for recently used project archive
+ * @param projectName the project name
+ * @param pathname the pathname used to create the final path
+ * @return recently used project pathname string
+ */
+ public static String getProjectPathname(String projectName, String pathname) {
+ if (pathname.length() < 2 || !pathname.startsWith(FileSystem.SEPARATOR)) {
+ throw new IllegalArgumentException("Absolute project pathname required");
+ }
+ return PROJECT_NAME_DELIMETER + projectName + PROJECT_NAME_DELIMETER + pathname;
+ }
+
+ /**
+ * Determine if we can remember the specified project archive using a simple project path
+ * (e.g., we can't remember specific versions).
+ * @param pa project archive
+ * @param activeProjectOnly if true pa must be contained within the
+ * active project to be remembered.
+ * @return return project path which can be remembered or null
+ */
+ public String getProjectPathname(ProjectDataTypeArchive pa, boolean activeProjectOnly) {
+ // Project archives are always opened by a user.
+ // Only remember it if it is the current version within the current project
+ DomainFile df = pa.getDomainFile();
+ ProjectLocator projectLocator = df.getProjectLocator();
+ String projectName = projectLocator.getName();
+ boolean remember = df.isInWritableProject();
+ if (!remember) {
+ // handle read-only case
+ Project project = tool.getProjectManager().getActiveProject();
+ remember = (project != null && project.getName().equals(projectName) &&
+ df.getVersion() == DomainFile.DEFAULT_VERSION);
+ }
+ return remember ? getProjectPathname(projectName, df.getPathname()) : null;
+ }
+
+ private static List resolveArchivePaths(String[] savedArchivePaths) {
+ if (savedArchivePaths == null) {
+ return Collections.emptyList();
+ }
+ List resolvedPaths = new ArrayList<>();
+ for (String archivePath : savedArchivePaths) {
+ archivePath = adjustArchivePath(archivePath);
+ if (archivePath != null) {
+ resolvedPaths.add(archivePath);
+ }
+ }
+ return resolvedPaths;
+ }
+
+ private static String adjustArchivePath(String pathName) {
+ if (pathName.startsWith(PROJECT_NAME_DELIMETER)) {
+ return pathName;
+ }
+ if (pathName.startsWith(RELATIVE_PATH_PREFIX)) {
+ ResourceFile file = DataTypeArchiveUtility.findArchiveFile(pathName);
+ if (file == null) {
+ Msg.error(ArchiveManager.class, "Archive not found: " + pathName);
+ return null;
+ }
+ return file.getAbsolutePath();
+ }
+ Path path = new Path(pathName);
+ return path.getPath().getAbsolutePath();
+ }
+
+ /**
+ * Parse a recently used project pathname string
+ * @param projectFilePath project pathname string
+ * @return 2-element String array containing project name and pathname of project archive, or null if path is invalid
+ */
+ public static String[] parseProjectPathname(String projectFilePath) {
+ if (projectFilePath.startsWith(PROJECT_NAME_DELIMETER)) {
+ int index = projectFilePath.indexOf(PROJECT_NAME_DELIMETER, 1);
+ if (index > 0) {
+ String projectName = projectFilePath.substring(1, index);
+ String pathname = projectFilePath.substring(index + 1);
+ if (pathname.length() > 1 && pathname.startsWith(FileSystem.SEPARATOR)) {
+ return new String[] { projectName, pathname };
+ }
+ }
+ }
+ return null;
+ }
+
+ class RecentlyUsedDataType {
+
+ private String dataTypeManagerName;
+ private CategoryPath path;
+ private String dataTypeName;
+
+ RecentlyUsedDataType() {
+ // default constructor
+ }
+
+ RecentlyUsedDataType(DataType dt) {
+ dataTypeName = dt.getName();
+ path = dt.getCategoryPath();
+ DataTypeManager dtMgr = dt.getDataTypeManager();
+ dataTypeManagerName = dtMgr == null ? null : dtMgr.getName();
+
+ if (dataTypeManagerName == null && currentProgram != null) {
+ DataTypeManager programDataTypeManager = currentProgram.getDataTypeManager();
+ dataTypeManagerName = programDataTypeManager.getName();
+ }
+ }
+
+ public DataType getDataType() {
+ if (dataTypeName == null) {
+ return null;
+ }
+ DataTypeManager dtMgr = findDataTypeManager();
+ Category category = dtMgr.getCategory(path);
+ if (category != null) {
+ DataType dt = category.getDataType(dataTypeName);
+ if (dt != null) {
+ return dt;
+ }
+ }
+ return getBuiltInDataType();
+ }
+
+ private DataType getBuiltInDataType() {
+ DataTypeManager dtMgr = getBuiltInDataTypesManager();
+ Category category = dtMgr.getCategory(path);
+ if (category != null) {
+ DataType dt = category.getDataType(dataTypeName);
+ if (dt != null) {
+ return dt;
+ }
+ }
+ return null;
+ }
+
+ private DataTypeManager findDataTypeManager() {
+ if (currentProgram != null && currentProgram.getName().equals(dataTypeManagerName)) {
+ return currentProgram.getDataTypeManager();
+ }
+ for (PersistentDataTypeArchive archive : archiveManager.getOpenArchives()) {
+ if (archive.getName().equals(dataTypeManagerName)) {
+ return archive.getDataTypeManager();
+ }
+ }
+ return BuiltInDataTypeManager.getDataTypeManager();
+ }
+ }
+
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypePropertyManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypePropertyManager.java
index 6ca8fdb80d..b9b85304b2 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypePropertyManager.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypePropertyManager.java
@@ -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.
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeSynchronizer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeSynchronizer.java
index 610f32d0e6..a9b34cd899 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeSynchronizer.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeSynchronizer.java
@@ -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 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;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypesActionContext.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypesActionContext.java
index 27868baaab..edf9a2837c 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypesActionContext.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypesActionContext.java
@@ -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();
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 getSelectedProjectArchives() {
+ List list = new ArrayList<>();
+
+ List selectedNodes = getSelectedNodes();
+ for (GTreeNode node : selectedNodes) {
+ if (node instanceof ProjectArchiveNode projectNode) {
+ ProjectDataTypeArchive archive = projectNode.getArchive();
+ list.add(archive);
+ }
+ }
+ return list;
+ }
+
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypesProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypesProvider.java
index 84fc1f2832..fe001d375f 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypesProvider.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypesProvider.java
@@ -38,19 +38,18 @@ import generic.theme.GIcon;
import generic.theme.GThemeDefaults.Colors;
import ghidra.app.plugin.core.datamgr.actions.*;
import ghidra.app.plugin.core.datamgr.actions.associate.*;
-import ghidra.app.plugin.core.datamgr.archive.*;
import ghidra.app.plugin.core.datamgr.tree.*;
import ghidra.app.plugin.core.datamgr.util.DataTypeUtils;
import ghidra.app.util.ToolTipUtils;
import ghidra.app.util.datatype.DataTypeUrl;
-import ghidra.framework.main.datatree.ArchiveProvider;
-import ghidra.framework.main.datatree.VersionControlDataTypeArchiveUndoCheckoutAction;
import ghidra.framework.main.projectdata.actions.*;
+import ghidra.framework.model.DomainFile;
import ghidra.framework.options.SaveState;
import ghidra.framework.plugintool.ComponentProviderAdapter;
import ghidra.program.model.data.*;
import ghidra.program.model.data.DataTypeConflictHandler.ConflictResolutionPolicy;
-import ghidra.program.model.listing.DataTypeArchive;
+import ghidra.program.model.dtarchive.PersistentDataTypeArchive;
+import ghidra.program.model.dtarchive.FileDataTypeArchive;
import ghidra.program.model.listing.Program;
import ghidra.util.*;
import ghidra.util.task.SwingUpdateManager;
@@ -172,12 +171,13 @@ public class DataTypesProvider extends ComponentProviderAdapter {
// File group
addLocalAction(new SaveArchiveAction(plugin)); // Archive
+ addLocalAction(new SaveArchiveAsAction(plugin));
addLocalAction(new CloseArchiveAction(plugin)); // Archive
addLocalAction(new RemoveInvalidArchiveFromProgramAction(plugin)); // Archive
// FileEdit group
- addLocalAction(new LockArchiveAction(plugin)); // Archive
- addLocalAction(new UnlockArchiveAction(plugin)); // Archive
+ addLocalAction(new OpenArchiveForEditingAction(plugin)); // Archive
+ addLocalAction(new CloseArchiveForEditingAction(plugin)); // Archive
addLocalAction(new UndoArchiveTransactionAction(plugin)); // Archive
addLocalAction(new RedoArchiveTransactionAction(plugin)); // Archive
@@ -247,20 +247,6 @@ public class DataTypesProvider extends ComponentProviderAdapter {
private void addVersionControlActions() {
- ArchiveProvider archiveProvider = () -> {
- TreePath[] selectionPaths = archiveGTree.getSelectionPaths();
- List selectedArchives = new ArrayList<>();
- for (TreePath path : selectionPaths) {
- Object lastPathComponent = path.getLastPathComponent();
- if (lastPathComponent instanceof ProjectArchiveNode) {
- ProjectArchiveNode node = (ProjectArchiveNode) lastPathComponent;
- ProjectArchive archive = (ProjectArchive) node.getArchive();
- selectedArchives.add(archive);
- }
- }
- return selectedArchives;
- };
-
VersionControlAddAction addAction = new VersionControlAddAction(plugin);
addAction.setEnabled(false);
@@ -274,8 +260,8 @@ public class DataTypesProvider extends ComponentProviderAdapter {
new VersionControlCheckInAction(plugin, archiveGTree);
checkInAction.setEnabled(false);
- VersionControlDataTypeArchiveUndoCheckoutAction undoCheckOutAction =
- new VersionControlDataTypeArchiveUndoCheckoutAction(plugin, archiveProvider);
+ ArchiveUndoCheckoutTask undoCheckOutAction =
+ new ArchiveUndoCheckoutTask(plugin);
undoCheckOutAction.setEnabled(false);
VersionControlShowHistoryAction showHistoryAction =
@@ -572,35 +558,16 @@ public class DataTypesProvider extends ComponentProviderAdapter {
}
private static DataType updateDataType(CategoryPath path, String dataTypeName,
- ArchiveNode archiveNode) {
- DataTypeManager dataTypeManager = archiveNode.getArchive().getDataTypeManager();
+ PersistentDataTypeArchive archive) {
+ if (archive == null) {
+ return null;
+ }
+ DataTypeManager dataTypeManager = archive.getDataTypeManager();
Category category = dataTypeManager.getCategory(path);
return category.getDataType(dataTypeName);
}
- private boolean getWriteLock(DataTypeManagerPlugin dataTypePlugin, ArchiveNode archiveNode) {
- if (!isOkToLock()) {
- return false;
- }
- GTree tree = dataTypePlugin.getProvider().getGTree();
- GTreeState state = tree.getTreeState();
- if (!ArchiveUtils.lockArchive((FileArchive) archiveNode.getArchive())) {
- return false;
- }
- tree.restoreTreeState(state);
-
- return true;
- }
-
- private boolean needsWriteLock(ArchiveNode archiveNode) {
- if (archiveNode instanceof FileArchiveNode) {
- FileArchiveNode fileArchiveNode = (FileArchiveNode) archiveNode;
- return !fileArchiveNode.hasWriteLock();
- }
- return false;
- }
-
- private boolean isOkToLock() {
+ private boolean askToOpenArchiveForUpdate() {
return (OptionDialog.showYesNoDialog(archiveGTree, "Open Archive for Edit?",
"Archive file is not modifiable.\nDo you want to open for edit?") == OptionDialog.OPTION_ONE);
}
@@ -623,30 +590,55 @@ public class DataTypesProvider extends ComponentProviderAdapter {
dataType = DataTypeUtils.getBaseDataType(dataType);
CategoryPath path = dataType.getCategoryPath();
String dataTypeName = dataType.getName();
- ArchiveNode archiveNode = dataTypeNode.getArchiveNode();
+ DataTypeStoreNode archiveNode = dataTypeNode.getArchiveNode();
- if (archiveNode instanceof ProjectArchiveNode && !archiveNode.isModifiable()) {
- ProjectArchiveNode projectArchive = (ProjectArchiveNode) archiveNode;
- if (projectArchive.getDomainFile().isReadOnly()) {
- Msg.showInfo(getClass(), archiveGTree, "Read-Only Archive",
- "You may not edit data type within a read-only project archive.");
- }
- else {
- Msg.showInfo(getClass(), archiveGTree, "Archive Not Checked Out",
- "You must checkout this archive before you may edit data types.");
- }
+ if (isUnmodifiableProjectArchive(archiveNode)) {
return;
}
- // must get write lock before we can edit
- if (needsWriteLock(archiveNode)) {
- if (!getWriteLock(plugin, archiveNode)) {
- return;
+ if (archiveNode instanceof FileArchiveNode fileNode) {
+ FileDataTypeArchive archive = fileNode.getArchive();
+ if (!archive.isChangeable()) {
+ if (!askToOpenArchiveForUpdate()) {
+ return;
+ }
+ archive = openForUpdate(archive);
+ dataType = updateDataType(path, dataTypeName, archive);
}
- dataType = updateDataType(path, dataTypeName, archiveNode);
+ }
+ if (dataType != null) {
+ plugin.getEditorManager().edit(dataType);
+ }
+ }
+
+ private FileDataTypeArchive openForUpdate(FileDataTypeArchive archive) {
+ GTree tree = plugin.getProvider().getGTree();
+ GTreeState state = tree.getTreeState();
+ archive = plugin.getArchiveManager().reopenFileArchive(archive, true);
+ tree.restoreTreeState(state);
+ return archive;
+ }
+
+ private boolean isUnmodifiableProjectArchive(DataTypeStoreNode archiveNode) {
+ if (!(archiveNode instanceof ProjectArchiveNode projectNode)) {
+ return false;
}
- plugin.getEditorManager().edit(dataType);
+ if (archiveNode.isModifiable()) {
+ return false;
+ }
+ DomainFile domainFile = projectNode.getDomainFile();
+ DomainFile originalDomainFile = projectNode.getOriginalDomainFile();
+ if (domainFile.getVersion() == originalDomainFile.getLatestVersion() &&
+ originalDomainFile.canCheckout()) {
+ Msg.showInfo(getClass(), archiveGTree, "Archive Not Checked Out",
+ "You must checkout this archive before you may edit data types.");
+ }
+ else {
+ Msg.showInfo(getClass(), archiveGTree, "Archive Opened Read-Only",
+ "You may not edit data type within a read-only project archive.");
+ }
+ return true;
}
void restore(SaveState saveState) {
@@ -692,55 +684,26 @@ public class DataTypesProvider extends ComponentProviderAdapter {
return archiveGTree;
}
- void domainObjectRestored(DataTypeManagerDomainObject domainObject) {
+ void domainObjectRestored(PersistentDataTypeArchive archive) {
if (archiveGTree == null) {
return; // nothing to update
}
- if (domainObject instanceof Program) {
- Program program = (Program) domainObject;
- Program programInTree = plugin.getProgram(); // may be null
- if (program == programInTree) {
- DataTypeArchiveGTree gTree = getGTree();
- ArchiveNode node = getProgramArchiveNode();
- if (node != null) {
- GTreeState state = gTree.getTreeState(node);
- node.structureChanged();
- gTree.restoreTreeState(state);
- }
- }
- }
- else if (domainObject instanceof DataTypeArchive) {
- DataTypeArchive dataTypeArchive = (DataTypeArchive) domainObject;
- DataTypeArchiveGTree gTree = getGTree();
- ArchiveNode node = getDataTypeArchiveNode(dataTypeArchive);
- if (node != null) {
- GTreeState state = gTree.getTreeState(node);
- node.structureChanged();
- gTree.restoreTreeState(state);
- }
+ DataTypeArchiveGTree gTree = getGTree();
+ ArchiveNode node = getDataTypeArchiveNode(archive);
+ if (node != null) {
+ GTreeState state = gTree.getTreeState(node);
+ node.structureChanged();
+ gTree.restoreTreeState(state);
}
}
- private ProgramArchiveNode getProgramArchiveNode() {
+ private ArchiveNode getDataTypeArchiveNode(PersistentDataTypeArchive dataTypeArchive) {
GTreeNode rootNode = getGTree().getModelRoot();
List children = rootNode.getChildren();
for (GTreeNode node : children) {
- if (node instanceof ProgramArchiveNode programNode) {
- return programNode;
- }
- }
- return null;
- }
-
- private ArchiveNode getDataTypeArchiveNode(DataTypeArchive dataTypeArchive) {
- GTreeNode rootNode = getGTree().getModelRoot();
- List children = rootNode.getChildren();
- for (GTreeNode node : children) {
- ArchiveNode archiveNode = (ArchiveNode) node;
- Archive archive = archiveNode.getArchive();
- if (archive instanceof ProjectArchive) {
- ProjectArchive projectArchive = (ProjectArchive) archive;
- if (projectArchive.getDataTypeManager() == dataTypeArchive.getDataTypeManager()) {
+ if (node instanceof ArchiveNode archiveNode) {
+ PersistentDataTypeArchive archive = archiveNode.getArchive();
+ if (archive == dataTypeArchive) {
return archiveNode;
}
}
@@ -774,7 +737,7 @@ public class DataTypesProvider extends ComponentProviderAdapter {
Category category = dataTypeManager.getCategory(dataType.getCategoryPath());
ArchiveRootNode rootNode = (ArchiveRootNode) gTree.getViewRoot();
- ArchiveNode archiveNode = rootNode.getNodeForManager(dataTypeManager);
+ DataTypeStoreNode archiveNode = rootNode.getNodeForManager(dataTypeManager);
if (archiveNode == null) {
plugin.setStatus("Cannot find archive '" + dataTypeManager.getName() + "'. It may " +
"be filtered out of view or may have been closed (Data Type Manager)");
@@ -824,7 +787,7 @@ public class DataTypesProvider extends ComponentProviderAdapter {
}
ArchiveRootNode rootNode = (ArchiveRootNode) gTree.getViewRoot();
- ArchiveNode archiveNode = rootNode.getNodeForManager(dataTypeManager);
+ DataTypeStoreNode archiveNode = rootNode.getNodeForManager(dataTypeManager);
if (archiveNode == null) {
plugin.setStatus("Cannot find archive '" + dataTypeManager.getName() + "'. It may " +
"be filtered out of view or may have been closed (Data Type Manager)");
@@ -924,8 +887,7 @@ public class DataTypesProvider extends ComponentProviderAdapter {
}
private void restoreProgramTreeState(ProgramArchiveNode programNode) {
- ProgramArchive programArchive = (ProgramArchive) programNode.getArchive();
- Program program = programArchive.getProgram();
+ Program program = programNode.getProgram();
long id = program.getUniqueProgramID();
TreePath selectedPath = programTreeState.get(id);
if (selectedPath == null) {
@@ -946,8 +908,7 @@ public class DataTypesProvider extends ComponentProviderAdapter {
// of the program node, so only save the path if there is a single selection. This will
// be helpful in the case that the user was working with a single data type in the program.
//
- ProgramArchive programArchive = (ProgramArchive) programNode.getArchive();
- Program program = programArchive.getProgram();
+ Program program = programNode.getProgram();
long id = program.getUniqueProgramID();
GTreeState state = archiveGTree.getTreeState();
List paths = state.getSelectedPaths();
@@ -987,16 +948,11 @@ public class DataTypesProvider extends ComponentProviderAdapter {
clearDataTypePreview();
}
- void archiveClosed(DataTypeManager dtm) {
- dataTypeManagerChanged(dtm);
+ void archiveClosed(PersistentDataTypeArchive archive) {
+ archiveChanged(archive.getName());
}
- void archiveChanged(Archive archive) {
- DataTypeManager dtm = archive.getDataTypeManager();
- dataTypeManagerChanged(dtm);
- }
-
- private void dataTypeManagerChanged(DataTypeManager dtm) {
+ void archiveChanged(String name) {
if (lastPreviewNode == null || !(lastPreviewNode instanceof DataTypeNode)) {
return;
@@ -1005,9 +961,10 @@ public class DataTypesProvider extends ComponentProviderAdapter {
DataTypeNode dtNode = (DataTypeNode) lastPreviewNode;
DataType dt = dtNode.getDataType();
DataTypeManager dtManager = dt.getDataTypeManager();
-
- // note: compare using name; an equality check will fail if the manager is reloaded
- if (dtm.getName().equals(dtManager.getName())) {
+ // notes: the archive name and the datatypeManager name are the same. If the archive
+ // changed because it was closed, then its datatype manager will be null. So just
+ // compare the datatype's manager's name with the archive's name.
+ if (name.equals(dtManager.getName())) {
lastPreviewNode = null;
}
}
@@ -1016,9 +973,8 @@ public class DataTypesProvider extends ComponentProviderAdapter {
ArchiveRootNode rootNode = (ArchiveRootNode) archiveGTree.getModelRoot();
List allChildren = rootNode.getChildren();
for (GTreeNode node : allChildren) {
- ArchiveNode archiveNode = (ArchiveNode) node;
- if (archiveNode.getArchive() instanceof ProgramArchive) {
- archiveNode.nodeChanged();
+ if (node instanceof ProgramArchiveNode programNode) {
+ programNode.nodeChanged();
return;
}
}
@@ -1087,14 +1043,14 @@ public class DataTypesProvider extends ComponentProviderAdapter {
private class ProgramNodeUpdateListener implements ArchiveRootNodeListener {
@Override
- public void archiveNodeAdded(ArchiveNode node) {
+ public void archiveNodeAdded(DataTypeStoreNode node) {
if (node instanceof ProgramArchiveNode programNode) {
restoreProgramTreeState(programNode);
}
}
@Override
- public void archiveNodeRemoved(ArchiveNode node) {
+ public void archiveNodeRemoved(DataTypeStoreNode node) {
if (node instanceof ProgramArchiveNode programNode) {
saveProgramTreeState(programNode);
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/OpenDomainFileTask.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/OpenDomainFileTask.java
deleted file mode 100644
index b3c0bc96d7..0000000000
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/OpenDomainFileTask.java
+++ /dev/null
@@ -1,239 +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;
-
-import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
-import java.util.List;
-
-import javax.swing.SwingUtilities;
-
-import docking.widgets.OptionDialog;
-import docking.widgets.tree.GTree;
-import docking.widgets.tree.GTreeNode;
-import ghidra.app.plugin.core.datamgr.archive.*;
-import ghidra.app.plugin.core.datamgr.tree.ArchiveNode;
-import ghidra.framework.client.ClientUtil;
-import ghidra.framework.client.RepositoryAdapter;
-import ghidra.framework.main.AppInfo;
-import ghidra.framework.model.DomainFile;
-import ghidra.framework.plugintool.PluginTool;
-import ghidra.program.model.listing.DataTypeArchive;
-import ghidra.util.*;
-import ghidra.util.exception.CancelledException;
-import ghidra.util.exception.VersionException;
-import ghidra.util.task.Task;
-import ghidra.util.task.TaskMonitor;
-
-class OpenDomainFileTask extends Task {
- private DomainFile domainFile;
- private int version;
- private DataTypeManagerPlugin dtmPlugin;
- private DataTypeManagerHandler dtmHandler;
- private PluginTool tool;
- private DataTypeArchive dtArchive = null;
-
- OpenDomainFileTask(DomainFile domainFile, int version, PluginTool tool,
- DataTypeManagerPlugin dtmPlugin) {
-
- super("Open Project Data Type Archive", true, true, true);
- this.domainFile = domainFile;
- this.dtmPlugin = dtmPlugin;
- this.dtmHandler = dtmPlugin.getDataTypeManagerHandler();
- this.tool = tool;
- this.version = version;
- }
-
- DataTypeArchive getArchive() {
- return dtArchive;
- }
-
- /* (non-Javadoc)
- * @see ghidra.util.task.Task#run(ghidra.util.task.TaskMonitor)
- */
- @Override
- public void run(TaskMonitor monitor) {
-
- if (isFileOpen()) {
- return;
- }
- boolean associateWithOriginalDomainFile = true;
- if (version != DomainFile.DEFAULT_VERSION) {
- openReadOnlyFile(monitor);
- associateWithOriginalDomainFile = false;
- }
- else if (domainFile.isReadOnly()) {
- openReadOnlyFile(monitor);
- }
- else if (domainFile.isVersioned() && !domainFile.isCheckedOut()) {
- openReadOnlyFile(monitor);
- }
- else {
- openUnversionedFile(monitor);
- }
- if (dtArchive != null) {
- openFileInTree(associateWithOriginalDomainFile);
- dtArchive.release(this);
- }
- }
-
- private boolean isFileOpen() {
- List dtArchiveList = dtmHandler.getAllArchives();
- for (Archive archive : dtArchiveList) {
- if (archive instanceof ProjectArchive) {
- ProjectArchive projectArchive = (ProjectArchive) archive;
- DomainFile archiveDomainFile = projectArchive.getDomainFile();
- if (filesMatch(domainFile, archiveDomainFile)) {
- // archive = projectArchive;
- // dtmHandler.open // TODO
- return true;
- }
- }
- }
-
- return false;
- }
-
- private boolean filesMatch(DomainFile file1, DomainFile file2) {
- if (!file1.getPathname().equals(file2.getPathname())) {
- return false;
- }
-
- if (file1.isCheckedOut() != file2.isCheckedOut()) {
- return false;
- }
-
- if (!SystemUtilities.isEqual(file1.getProjectLocator(), file2.getProjectLocator())) {
- return false;
- }
-
- int otherVersion = file2.isReadOnly() ? file2.getVersion() : -1;
- return version == otherVersion;
- }
-
- /**
- * Open archive in an immutable fashion. Unlike ProgramDB, we do not want to
- * allow upgrade or modification of a read-only archve (e.g., not-checked-out).
- * @param monitor task monitor
- */
- private void openReadOnlyFile(TaskMonitor monitor) {
- String fileDescr =
- ((version != DomainFile.DEFAULT_VERSION) ? "version " + version + " of " : "") +
- domainFile.getName();
- String contentType = null;
- try {
- monitor.setMessage("Opening " + fileDescr);
- contentType = domainFile.getContentType();
- dtArchive =
- (DataTypeArchive) domainFile.getImmutableDomainObject(this, version, monitor);
- }
- catch (CancelledException e) {
- // we don't care, the task has been canceled
- }
- catch (IOException e) {
- if (domainFile.isVersioned() && domainFile.isInWritableProject()) {
- ClientUtil.handleException(AppInfo.getActiveProject().getRepository(), e,
- "Get Versioned Object", null);
- }
- else {
- Msg.showError(this, null, "Project Archive Open Error",
- "Error occurred while opening " + fileDescr, e);
- }
- }
- catch (VersionException e) {
- VersionExceptionHandler.showVersionError(tool.getToolFrame(), domainFile.getName(),
- contentType, "Open", false, e);
- }
- }
-
- private void openUnversionedFile(TaskMonitor monitor) {
- monitor.setMessage("Opening " + domainFile.getName());
- String contentType = null;
- try {
- final boolean recoverFile = isRecoveryOK(domainFile);
- contentType = domainFile.getContentType();
- try {
- dtArchive =
- (DataTypeArchive) domainFile.getDomainObject(this, false, recoverFile, monitor);
- }
- catch (VersionException e) {
- if (VersionExceptionHandler.isUpgradeOK(null, domainFile, "Open", e)) {
- dtArchive = (DataTypeArchive) domainFile.getDomainObject(this, true,
- recoverFile, monitor);
- }
- }
- }
- catch (VersionException e) {
- VersionExceptionHandler.showVersionError(null, domainFile.getName(), contentType,
- "Open", false, e);
- }
- catch (CancelledException e) {
- // we don't care, the task has been canceled
- }
- catch (Exception e) {
- if (domainFile.isInWritableProject() && (e instanceof IOException)) {
- RepositoryAdapter repo = domainFile.getParent().getProjectData().getRepository();
- ClientUtil.handleException(repo, e, "Open File", null);
- }
- else {
- Msg.showError(this, null, "Error Opening " + domainFile.getName(),
- "Opening data type archive failed.\n" + e.getMessage());
- }
- }
- }
-
- private boolean isRecoveryOK(final DomainFile dfile)
- throws InterruptedException, InvocationTargetException {
- final boolean[] recoverFile = new boolean[] { false };
- if (dfile.isInWritableProject() && dfile.canRecover()) {
- Runnable r = () -> {
- int option = OptionDialog.showYesNoDialog(null, "Crash Recovery Data Found",
- "" + HTMLUtilities.escapeHTML(dfile.getName()) + " has crash data.
" +
- "Would you like to recover unsaved changes?");
- recoverFile[0] = (option == OptionDialog.OPTION_ONE);
- };
- SwingUtilities.invokeAndWait(r);
- }
- return recoverFile[0];
- }
-
- private void openFileInTree(boolean associatedWithOriginalDomainFile) {
- DataTypesProvider provider = dtmPlugin.getProvider();
- GTree tree = provider.getGTree();
- DataTypeManagerHandler manager = dtmPlugin.getDataTypeManagerHandler();
- DomainFile df = associatedWithOriginalDomainFile ? domainFile : dtArchive.getDomainFile();
- Archive archive = manager.openArchive(dtArchive, df);
- GTreeNode node = getNodeForArchive(tree, archive);
- if (node != null) {
- tree.setSelectedNode(node);
- }
- }
-
- private GTreeNode getNodeForArchive(GTree tree, Archive archive) {
- GTreeNode rootNode = tree.getModelRoot();
- for (GTreeNode node : rootNode.getChildren()) {
- if (node instanceof ArchiveNode) {
- ArchiveNode archiveNode = (ArchiveNode) node;
- if (archiveNode.getArchive() == archive) {
- return archiveNode;
- }
- }
- }
-
- return null;
- }
-
-}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/OpenFileArchiveTask.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/OpenFileArchiveTask.java
new file mode 100644
index 0000000000..d98bbd177d
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/OpenFileArchiveTask.java
@@ -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;
+ }
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/OpenProjectArchiveTask.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/OpenProjectArchiveTask.java
new file mode 100644
index 0000000000..aa68933661
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/OpenProjectArchiveTask.java
@@ -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",
+ "" + HTMLUtilities.escapeHTML(file.getName()) + " has crash data.
" +
+ "Would you like to recover unsaved changes?");
+ return (option == OptionDialog.OPTION_ONE);
+ }
+
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/ProjectArchiveSaveAsDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/ProjectArchiveSaveAsDialog.java
new file mode 100644
index 0000000000..78c1cdd6aa
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/ProjectArchiveSaveAsDialog.java
@@ -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 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;
+ }
+
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/AbstractUndoRedoArchiveTransactionAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/AbstractUndoRedoArchiveTransactionAction.java
index 1d36502b2d..5879ca52f8 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/AbstractUndoRedoArchiveTransactionAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/AbstractUndoRedoArchiveTransactionAction.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CaptureFunctionDataTypesAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CaptureFunctionDataTypesAction.java
index 130cd0de55..5709dced4b 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CaptureFunctionDataTypesAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CaptureFunctionDataTypesAction.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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.";
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/ClearArchiveArchitectureAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/ClearArchiveArchitectureAction.java
index f88e1aea76..24965991a9 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/ClearArchiveArchitectureAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/ClearArchiveArchitectureAction.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -15,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 = "Clear program-architecture for Archive?
" + dtm.getPath() +
+ Messages.NORMAL + "\">" + archive.getPath() +
"
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);
}
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CloseArchiveAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CloseArchiveAction.java
index 5207353914..2d07c542f0 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CloseArchiveAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CloseArchiveAction.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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 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 archives = new ArrayList();
- 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 archives = new ArrayList<>();
+ List 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 archives) {
+ DataTypeEditorManager editorManager = plugin.getEditorManager();
+ for (PersistentDataTypeArchive archive : archives) {
+ DataTypeManager dtm = archive.getDataTypeManager();
+ if (!editorManager.checkEditors(dtm, true)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/UnlockArchiveAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CloseArchiveForEditingAction.java
similarity index 66%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/UnlockArchiveAction.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CloseArchiveForEditingAction.java
index 3acea700ce..8eb27f5b78 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/UnlockArchiveAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CloseArchiveForEditingAction.java
@@ -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);
}
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CopyAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CopyAction.java
index ea8ed82e6c..734ba09414 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CopyAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CopyAction.java
@@ -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) {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CreateArchiveAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CreateArchiveAction.java
index f72b57d0ef..c2709175e5 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CreateArchiveAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CreateArchiveAction.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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() });
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CreateCategoryAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CreateCategoryAction.java
index 02853f7224..f7b5f42678 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CreateCategoryAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CreateCategoryAction.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CreatePointerAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CreatePointerAction.java
index cf35d16fe3..27e8c547e9 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CreatePointerAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CreatePointerAction.java
@@ -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;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CreateProjectArchiveAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CreateProjectArchiveAction.java
index 78e10e8bf2..c0d224c77c 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CreateProjectArchiveAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CreateProjectArchiveAction.java
@@ -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 -> {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CreateTypeDefAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CreateTypeDefAction.java
index 2e6a1793a7..bb7dcc5e21 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CreateTypeDefAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CreateTypeDefAction.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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);
}
-
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/DeleteAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/DeleteAction.java
index 51e1c2bd02..487d9748ad 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/DeleteAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/DeleteAction.java
@@ -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;
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/DeleteArchiveAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/DeleteArchiveAction.java
index 708eb47577..4df1dc6a95 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/DeleteArchiveAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/DeleteArchiveAction.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/DerivativeDataTypeInfo.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/DerivativeDataTypeInfo.java
index bc9591ae23..17f2197c8b 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/DerivativeDataTypeInfo.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/DerivativeDataTypeInfo.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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 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;
+ }
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/EditArchivePathAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/EditArchivePathAction.java
index 64ccd6c157..5b7b3ef4f9 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/EditArchivePathAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/EditArchivePathAction.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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();
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/OpenArchiveAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/OpenArchiveAction.java
index e30084731a..2ca77adfb5 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/OpenArchiveAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/OpenArchiveAction.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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 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;
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/LockArchiveAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/OpenArchiveForEditingAction.java
similarity index 77%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/LockArchiveAction.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/OpenArchiveForEditingAction.java
index 4b78cf7344..c08009d8c0 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/LockArchiveAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/OpenArchiveForEditingAction.java
@@ -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);
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/OpenProjectArchiveAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/OpenProjectArchiveAction.java
index d061b75a2a..6ea136f2b5 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/OpenProjectArchiveAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/OpenProjectArchiveAction.java
@@ -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 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);
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/PasteAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/PasteAction.java
index c7f6710710..8db62bbb77 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/PasteAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/PasteAction.java
@@ -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
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/RecentlyOpenedArchiveAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/RecentlyOpenedArchiveAction.java
index e6268c91c3..a8319a2e81 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/RecentlyOpenedArchiveAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/RecentlyOpenedArchiveAction.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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);
- }
- }
- }
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/RedoArchiveTransactionAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/RedoArchiveTransactionAction.java
index cf9345eadf..1284e5b711 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/RedoArchiveTransactionAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/RedoArchiveTransactionAction.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -15,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);
+ }
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/RemoveInvalidArchiveFromProgramAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/RemoveInvalidArchiveFromProgramAction.java
index 634c2dc991..a6e1fcc4c4 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/RemoveInvalidArchiveFromProgramAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/RemoveInvalidArchiveFromProgramAction.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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);
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/RenameAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/RenameAction.java
index fcd05afe75..084c645d98 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/RenameAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/RenameAction.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/ReplaceDataTypeAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/ReplaceDataTypeAction.java
index 79f65c4454..bf46f80c47 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/ReplaceDataTypeAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/ReplaceDataTypeAction.java
@@ -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();
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/SaveArchiveAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/SaveArchiveAction.java
index 51fa66a5f6..de804bf69b 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/SaveArchiveAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/SaveArchiveAction.java
@@ -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.");
- }
- }
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/SaveAsAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/SaveArchiveAsAction.java
similarity index 59%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/SaveAsAction.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/SaveArchiveAsAction.java
index 309139f4a9..57fe814065 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/SaveAsAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/SaveArchiveAsAction.java
@@ -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);
}
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/SetArchiveArchitectureAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/SetArchiveArchitectureAction.java
index 0520cf2ad0..0107334ab1 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/SetArchiveArchitectureAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/SetArchiveArchitectureAction.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -15,8 +15,6 @@
*/
package ghidra.app.plugin.core.datamgr.actions;
-import java.io.IOException;
-
import javax.swing.tree.TreePath;
import docking.ActionContext;
@@ -26,23 +24,23 @@ 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.tree.*;
+import ghidra.app.plugin.core.datamgr.*;
+import ghidra.app.plugin.core.datamgr.tree.ArchiveNode;
+import ghidra.app.plugin.core.datamgr.tree.ProjectArchiveNode;
import ghidra.app.plugin.core.processors.SetLanguageDialog;
-import ghidra.framework.model.DomainFile;
-import ghidra.framework.store.LockException;
-import ghidra.program.model.data.StandAloneDataTypeManager;
-import ghidra.program.model.data.StandAloneDataTypeManager.LanguageUpdateOption;
+import ghidra.program.model.dtarchive.PersistentDataTypeArchive;
+import ghidra.program.model.dtarchive.ProjectDataTypeArchive;
+import ghidra.program.model.dtarchive.DataTypeArchive.LanguageUpdateOption;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.IncompatibleLanguageException;
import ghidra.program.util.DefaultLanguageService;
import ghidra.util.Msg;
-import ghidra.util.Swing;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.*;
+/**
+ * Action for setting the Architecture for a DataTypeAchive.
+ */
public class SetArchiveArchitectureAction extends DockingAction {
private final DataTypeManagerPlugin plugin;
@@ -78,13 +76,10 @@ public class SetArchiveArchitectureAction extends DockingAction {
return false;
}
GTreeNode node = (GTreeNode) selectionPath.getLastPathComponent();
- if (!(node instanceof FileArchiveNode) && !(node instanceof ProjectArchiveNode)) {
- return false;
+ if (node instanceof ArchiveNode archiveNode) {
+ return archiveNode.getArchive().isUpdatable();
}
- ArchiveNode archiveNode = (ArchiveNode) node;
- StandAloneDataTypeManager dtm =
- (StandAloneDataTypeManager) archiveNode.getArchive().getDataTypeManager();
- return dtm.isUpdatable();
+ return false;
}
@Override
@@ -94,13 +89,12 @@ public class SetArchiveArchitectureAction extends DockingAction {
return;
}
GTreeNode node = (GTreeNode) selectionPath.getLastPathComponent();
- if (!(node instanceof FileArchiveNode) && !(node instanceof ProjectArchiveNode)) {
+ if (!(node instanceof ArchiveNode archiveNode)) {
return;
}
- if (node instanceof ProjectArchiveNode) {
- ProjectArchiveNode paNode = (ProjectArchiveNode) node;
- ProjectArchive pa = (ProjectArchive) paNode.getArchive();
+ if (node instanceof ProjectArchiveNode projectNode) {
+ ProjectDataTypeArchive pa = projectNode.getArchive();
if (!pa.hasExclusiveAccess()) {
Msg.showError(this, null, "Set Program Architecture Failed",
"Setting program-architecture on Project Archive requires exclusive checkout.");
@@ -108,11 +102,8 @@ public class SetArchiveArchitectureAction extends DockingAction {
}
}
- ArchiveNode archiveNode = (ArchiveNode) node;
- StandAloneDataTypeManager dtm =
- (StandAloneDataTypeManager) archiveNode.getArchive().getDataTypeManager();
-
- if (dtm.isChanged()) {
+ PersistentDataTypeArchive archive = archiveNode.getArchive();
+ if (archive.isChanged()) {
if (OptionDialog.OPTION_ONE != OptionDialog.showOptionDialogWithCancelAsDefaultButton(
null, "Save Archive Changes",
"Archive has unsaved changes which must be saved before continuing." +
@@ -120,19 +111,12 @@ public class SetArchiveArchitectureAction 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;
- }
+ plugin.getArchiveManager().save(archiveNode.getArchive());
}
SetLanguageDialog dialog = new SetLanguageDialog(plugin.getTool(),
- dtm.getProgramArchitecture(),
- "Select Program Architecture for Archive: " + dtm.getName());
+ archive.getProgramArchitecture(),
+ "Select Program Architecture for Archive: " + archive.getName());
LanguageID languageId = dialog.getLanguageDescriptionID();
CompilerSpecID compilerSpecId = dialog.getCompilerSpecDescriptionID();
if ((languageId == null) || (compilerSpecId == null)) {
@@ -147,15 +131,15 @@ public class SetArchiveArchitectureAction extends DockingAction {
buf.append(compilerSpecId.getIdAsString());
String newProgramArchitectureSummary = buf.toString();
- String programArchitectureSummary = dtm.getProgramArchitectureSummary();
+ String programArchitectureSummary = archive.getProgramArchitectureSummary();
String msg =
"Set program-architecture for Archive?
" + dtm.getPath() + "";
+ "\">" + archive.getPath() + "";
if (programArchitectureSummary != null) {
msg +=
"\nChange Language/Compiler\n from: " +
- programArchitectureSummary + "\n to: ";
+ programArchitectureSummary + "\n to: ";
}
else {
msg += "\n\nLanguage/Compiler: ";
@@ -170,46 +154,44 @@ public class SetArchiveArchitectureAction extends DockingAction {
return;
}
- new TaskLauncher(new SetProgramArchitectureTask(archiveNode.getArchive(), dtm, language,
+ new TaskLauncher(new SetProgramArchitectureTask(archive, language,
compilerSpecId));
}
catch (LanguageNotFoundException e) {
Msg.showError(this, null, "Archive Update Failed",
- "Failed to set program-architecture for Archive: " + dtm.getName() + "\n" +
+ "Failed to set program-architecture for Archive: " + archive.getName() + "\n" +
e.getMessage());
}
}
private class SetProgramArchitectureTask extends Task {
- private final Archive archive;
- private final StandAloneDataTypeManager dtm;
+ private final PersistentDataTypeArchive archive;
private final Language language;
private final CompilerSpecID compilerSpecId;
- public SetProgramArchitectureTask(Archive archive, StandAloneDataTypeManager dtm,
- Language language, CompilerSpecID compilerSpecId) {
+ public SetProgramArchitectureTask(PersistentDataTypeArchive archive, Language language,
+ CompilerSpecID compilerSpecId) {
super("Updating Program-Architecture for Archive", true, false, true, false);
this.archive = archive;
- this.dtm = dtm;
this.language = language;
this.compilerSpecId = compilerSpecId;
}
@Override
public void run(TaskMonitor monitor) throws CancelledException {
-
+
boolean success = false;
try {
try {
- dtm.setProgramArchitecture(language, compilerSpecId,
+ archive.setProgramArchitecture(language, compilerSpecId,
LanguageUpdateOption.TRANSLATE, monitor);
success = true;
}
catch (IncompatibleLanguageException e) {
int resp = OptionDialog.showOptionDialog(null, "Archive Architecture Change",
"Unable to translate storage for specified architecture change.
" + dtm.getPath() +
+ Messages.NORMAL + "\">" + archive.getPath() +
"
Would you like to Clear custom storage information or Cancel change?",
"Clear");
if (resp == OptionDialog.CANCEL_OPTION) {
@@ -220,7 +202,7 @@ public class SetArchiveArchitectureAction extends DockingAction {
if (resp == OptionDialog.OPTION_TWO) {
updateOption = LanguageUpdateOption.UNCHANGED;
}
- dtm.setProgramArchitecture(language, compilerSpecId, updateOption, monitor);
+ archive.setProgramArchitecture(language, compilerSpecId, updateOption, monitor);
success = true;
}
}
@@ -229,27 +211,18 @@ public class SetArchiveArchitectureAction extends DockingAction {
}
catch (Exception e) {
Msg.showError(this, null, "Archive Update Failed",
- "Failed to set program-architecture for Archive: " + dtm.getName() + "\n" +
+ "Failed to set program-architecture for Archive: " + archive.getName() + "\n" +
e.getMessage());
}
finally {
if (!success) {
- Swing.runNow(() -> {
- /* flush event queue before closing archive */ });
- 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);
- }
+ // not sure why this is needed; put back if so and explain why
+ // Swing.runNow(() -> {
+ // /* flush event queue before closing archive */
+ // });
+
+ ArchiveManager archiveManager = plugin.getArchiveManager();
+ archiveManager.reopenArchive(archive);
}
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/UndoArchiveTransactionAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/UndoArchiveTransactionAction.java
index bc16e07226..7b16d0ed07 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/UndoArchiveTransactionAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/UndoArchiveTransactionAction.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -15,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);
+ }
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/UpdateSourceArchiveNamesAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/UpdateSourceArchiveNamesAction.java
deleted file mode 100644
index fa0b35dcfc..0000000000
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/UpdateSourceArchiveNamesAction.java
+++ /dev/null
@@ -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);
- }
- }
-
-}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/AssociateDataTypeAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/AssociateDataTypeAction.java
index 05651aa52d..3c587cffc5 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/AssociateDataTypeAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/AssociateDataTypeAction.java
@@ -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 getDataTypeNodes(DataTypesActionContext ctx) {
@@ -91,11 +93,11 @@ public class AssociateDataTypeAction extends DockingAction {
return !nodes.isEmpty();
}
- private Archive getSingleDTArchive(List nodes) {
+ private DataTypeStore getSingleDataTypeStore(List 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 getDestinationArchives(Archive excludedArchive) {
+ private List getDestinationArchives(DataTypeStore excluded) {
- List archives = plugin.getAllArchives();
- List destArchives = archives.stream()
- .filter(a -> !(a instanceof ProgramArchive))
- .filter(a -> !(a instanceof BuiltInArchive))
- .filter(a -> !a.equals(excludedArchive))
+ List archives = plugin.getArchiveManager().getOpenArchives();
+ List 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 archives = getDestinationArchives(dtArchive);
+ List 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 archivesBox = new GhidraComboBox<>();
+ private GhidraComboBox archivesBox = new GhidraComboBox<>();
private JTextField categoryField = new JTextField(20);
- ChooseArchiveDialog(List archives) {
+ ChooseArchiveDialog(List 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;
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/CommitAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/CommitAction.java
index 821b306751..6b7f8c8f1b 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/CommitAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/CommitAction.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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()));
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/CommitSingleDataTypeAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/CommitSingleDataTypeAction.java
index 4fe152dbc8..b497af044b 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/CommitSingleDataTypeAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/CommitSingleDataTypeAction.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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();
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/DisassociateAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/DisassociateAction.java
index d26a97de9b..d27b8cadae 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/DisassociateAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/DisassociateAction.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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());
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/DisassociateDataTypeAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/DisassociateDataTypeAction.java
index 5f1c471932..8a6a111d38 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/DisassociateDataTypeAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/DisassociateDataTypeAction.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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> entry : sourceToTypes.entrySet()) {
SourceArchive source = entry.getKey();
List types = entry.getValue();
- DataTypeSynchronizer synchronizer = new DataTypeSynchronizer(handler, dtm, source);
+ DataTypeSynchronizer synchronizer =
+ new DataTypeSynchronizer(archiveManager, dtm, source);
disassociate(synchronizer, dtm, types, monitor);
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/RevertAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/RevertAction.java
index 7d10931cde..87da4c2aee 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/RevertAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/RevertAction.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -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()));
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/RevertDataTypeAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/RevertDataTypeAction.java
index 8367123c41..4f30c65a3e 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/RevertDataTypeAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/RevertDataTypeAction.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -23,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();
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/SyncAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/SyncAction.java
index 7f228feb6c..4a27bb9932 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/SyncAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/SyncAction.java
@@ -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 {
-
- /**
- * 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);
-}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ArchiveManagerListener.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ArchiveManagerListener.java
deleted file mode 100644
index e5a913ec8c..0000000000
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ArchiveManagerListener.java
+++ /dev/null
@@ -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);
-}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ArchiveUtils.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ArchiveUtils.java
deleted file mode 100644
index 590fad3050..0000000000
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ArchiveUtils.java
+++ /dev/null
@@ -1,215 +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.File;
-import java.io.IOException;
-import java.util.List;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-
-import docking.widgets.OptionDialog;
-import ghidra.framework.store.LockException;
-import ghidra.program.model.data.FileDataTypeManager;
-import ghidra.util.Msg;
-import ghidra.util.ReadOnlyException;
-import ghidra.util.exception.DuplicateFileException;
-
-public class ArchiveUtils {
- static final Logger log = LogManager.getLogger(ArchiveUtils.class);
-
- private ArchiveUtils() {
- // utils class
- }
-
- /**
- * Saves the given archive to a file of the user's choosing.
- *
- * @param component The component over which GUI message will be shown when required.
- * @param archive The archive to save.
- * @throws DuplicateFileException thrown in the case of a naming conflict.
- * @throws IOException If the sky is falling.
- */
- public static void saveAs(Component component, FileArchive archive)
- throws DuplicateFileException, IOException {
- File saveAsFile = getFile(component, archive);
- if (saveAsFile == null) {
- return;
- }
-
- if (saveAsFile.equals(archive.getFile())) {
- archive.save();
- }
- else {
- archive.saveAs(saveAsFile);
- }
- }
-
- /**
- * This method will perform a save on the given archive. However, the one caveat is that if
- * the archive has never been saved, then a filename needs to be chosen. Under this 'special'
- * condition this method logically turns into a {@link #saveAs(Component, FileArchive)}.
- *
- * @param component The component over which GUI message will be shown when required.
- * @param archive The archive to save.
- * @throws DuplicateFileException thrown only in the {@link #saveAs(Component, FileArchive)}
- * condition in the case of a naming conflict.
- * @throws IOException If the sky is falling.
- */
- public static void save(Component component, Archive archive)
- throws DuplicateFileException, IOException {
- if (!archive.isSavable()) {
- archive.saveAs(component);
- }
- else {
- archive.save();
- }
- }
-
- public static boolean canClose(List archiveList, Component component) {
- for (Archive archive : archiveList) {
- if (!canClose(archive, component)) {
- return false;
- }
- }
- return true;
- }
-
- public static boolean lockArchive(FileArchive archive) {
- try {
- archive.acquireWriteLock();
- return true;
- }
- catch (ReadOnlyException e) {
- Msg.showError(log, null, "Unable to Lock Archive for Writing", e.getMessage());
- }
- catch (LockException exc) {
- Msg.showError(log, null, "Unable to Lock Archive for Writing",
- "Unable to obtain lock for archive: " + archive.getName() + "\n" +
- exc.getMessage());
- }
- catch (IOException ioe) {
- Throwable cause = ioe.getCause();
- if (cause == null) {
- cause = ioe;
- }
- Msg.showError(log, null, "Unable to Lock Archive for Writing",
- "Problem attempting to open archive for update: " + archive.getName() + "\n" +
- cause.getMessage());
- }
- return false;
- }
-
-// ==================================================================================================
-// Private methods
-//==================================================================================================
-
- static File getFile(Component component, FileArchive archive) {
- ArchiveFileChooser fileChooser = new ArchiveFileChooser(component);
- String archiveName = archive.getName();
- File file = fileChooser.promptUserForFile(archiveName);
- fileChooser.dispose();
- if (file == null) {
- return null;
- }
- if (file.equals(archive.getFile().getFile(false))) {
- return file;
- }
-
- if (archive.getArchiveManager().isInUse(file)) {
- Msg.showInfo(ArchiveUtils.class, component, "Cannot Perform Save As",
- "Cannot save archive to " + file.getName() + "\nbecause " + file.getName() +
- " is in use.");
- return null;
- }
-
- if (file.exists()) {
- if (OptionDialog.showYesNoDialogWithNoAsDefaultButton(component,
- "Overwrite Existing File?", "Do you want to overwrite existing file\n" +
- file.getAbsolutePath()) != OptionDialog.OPTION_ONE) {
- return null;
- }
-
- if (!deleteArchiveFile(file)) {
- Msg.showError(log, component, "Error Deleting File",
- "Could not delete file " + file.getAbsolutePath());
-
- return null;
- }
- }
-
- return file;
- }
-
- private static boolean deleteArchiveFile(File file) {
- try {
- FileDataTypeManager.delete(file);
- return true;
- }
- catch (Exception e) {
- // try below
- }
- return file.delete();
- }
-
- public static boolean canClose(Archive archive, Component component) {
- if (!archive.isChanged()) {
- return true;
- }
- int result =
- OptionDialog.showYesNoCancelDialog(component, "Save Archive?", "Datatype Archive \"" +
- archive.getName() + "\" has been changed.\n Do you want to save the changes?");
-
- if (result == OptionDialog.CANCEL_OPTION) {
- return false;
- }
- if (result == OptionDialog.NO_OPTION) {
- if (archive instanceof FileArchive) {
- // Release the write lock without saving. Returns file archive to its unedited state.
- try {
- ((FileArchive) archive).releaseWriteLock();
- }
- catch (IOException e) {
- Msg.showError(log, component, "Unable to release File Archive write lock.",
- e.getMessage(), e);
- return false;
- }
- }
- return true;
- }
-
- return saveArchive(archive, component);
- }
-
- private static boolean saveArchive(Archive archive, Component component) {
- try {
- ArchiveUtils.save(component, archive);
- return true;
- }
- catch (DuplicateFileException e) {
- Msg.showError(log, component, "Unable to Save Archive",
- "Archive already exists: " + archive, e);
- }
- catch (IOException e) {
- Msg.showError(log, component, "Unable to Save Archive",
- "Unexpected exception attempting to save archive: " + archive, e);
- }
- return false;
- }
-
-}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/BasicDataTypeArchiveService.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/BasicDataTypeArchiveService.java
new file mode 100644
index 0000000000..3596e27ecd
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/BasicDataTypeArchiveService.java
@@ -0,0 +1,215 @@
+/* ###
+ * IP: GHIDRA
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package ghidra.app.plugin.core.datamgr.archive;
+
+import java.io.IOException;
+import java.util.*;
+
+import generic.jar.ResourceFile;
+import ghidra.app.plugin.core.datamgr.util.DataTypeArchiveUtility;
+import ghidra.app.services.*;
+import ghidra.framework.model.DomainFile;
+import ghidra.program.database.data.ProgramDataTypeManager;
+import ghidra.program.database.dtarchive.DataTypeArchiveFactory;
+import ghidra.program.model.data.BuiltInDataTypeManager;
+import ghidra.program.model.data.DataTypeManager;
+import ghidra.program.model.dtarchive.*;
+import ghidra.util.Msg;
+import ghidra.util.UniversalID;
+import ghidra.util.exception.CancelledException;
+import ghidra.util.exception.VersionException;
+import ghidra.util.task.TaskMonitor;
+
+/**
+ * Simple, non-ui implementation of the {@link DataTypeArchiveService} interface. This is only
+ * used in headless mode (and some tests). The methods of this class are synchronized to protect
+ * the openArchives structure and to prevent multiple threads from attempting to open the same
+ * archives at the same time. Since this is used in headless mode, they may be multiple threads
+ * accessing this service at the same time.
+ */
+public class BasicDataTypeArchiveService implements DataTypeArchiveService {
+
+ private Map openArchives = new HashMap<>();
+ protected BuiltInDataTypeManager builtInDataTypesManager;
+
+ public BasicDataTypeArchiveService() {
+ this.builtInDataTypesManager = BuiltInDataTypeManager.getDataTypeManager();
+ }
+
+ public synchronized void dispose() {
+ for (PersistentDataTypeArchive archive : new ArrayList<>(openArchives.values())) {
+ closeArchive(archive); // mutates openArchives map
+ }
+ }
+
+ @Override
+ public synchronized DataTypeManager getBuiltInDataTypesManager() {
+ return builtInDataTypesManager;
+ }
+
+ @Override
+ public synchronized DataTypeManager[] getDataTypeManagers() {
+ List list = new ArrayList<>();
+ list.add(builtInDataTypesManager);
+ for (PersistentDataTypeArchive archive : openArchives.values()) {
+ list.add(archive.getDataTypeManager());
+ }
+ return list.toArray(DataTypeManager[]::new);
+ }
+
+ @Override
+ public synchronized List getDataTypeArchives() {
+ return new ArrayList(openArchives.values());
+ }
+
+ @Override
+ public synchronized void closeArchive(DataTypeManager dtm) {
+ if (dtm instanceof BuiltInDataTypeManager) {
+ Msg.info(this, "Cannot close the built-in Data Type Manager");
+ return;
+ }
+
+ if (dtm instanceof ProgramDataTypeManager) {
+ Msg.info(this, "Cannot close the Program's Data Type Manager");
+ return;
+ }
+
+ PersistentDataTypeArchive archive = openArchives.get(dtm.getUniversalID());
+ if (archive == null) {
+ Msg.info(this, "Unable close archive; archive not open: '%s'".formatted(dtm.getName()));
+ return;
+ }
+ closeArchive(archive);
+ }
+
+ @Override
+ public synchronized void closeArchive(PersistentDataTypeArchive archive) {
+ openArchives.remove(archive.getDataTypeManager().getUniversalID());
+ archive.release(this);
+ }
+
+ @Override
+ public synchronized FileDataTypeArchive openFileArchive(String archiveName, TaskMonitor monitor)
+ throws IOException, DuplicateIdException, CancelledException {
+ ResourceFile file = DataTypeArchiveUtility.findArchiveFile(archiveName);
+ if (file != null) {
+ return openFileArchive(file, false, Upgrade.NO, monitor);
+ }
+ return null;
+ }
+
+ @Override
+ public synchronized ProjectDataTypeArchive openProjectArchive(DomainFile domainFile,
+ Upgrade upgradeStrategy, Recover recoverStrategy, TaskMonitor monitor)
+ throws VersionException, CancelledException, IOException, DuplicateIdException {
+
+ if (!ProjectDataTypeArchive.class.isAssignableFrom(domainFile.getDomainObjectClass())) {
+ throw new IOException("Unable to open domain file: '%s', not a data type archive"
+ .formatted(domainFile.getName()));
+ }
+
+ ProjectDataTypeArchive archive = getOpenArchive(domainFile);
+ if (archive == null) {
+ boolean okToUpgrade = upgradeStrategy == Upgrade.YES;
+ boolean okToRecover = recoverStrategy == Recover.YES;
+ archive = openDomainFile(domainFile, okToUpgrade, okToRecover, monitor);
+ addArchive(archive);
+ }
+
+ return archive;
+ }
+
+ private ProjectDataTypeArchive openDomainFile(DomainFile domainFile, boolean okToUpgrade,
+ boolean okToRecover, TaskMonitor monitor)
+ throws VersionException, CancelledException, IOException {
+ ProjectDataTypeArchive dta =
+ (ProjectDataTypeArchive) domainFile.getDomainObject(this, false, false, monitor);
+ return dta;
+ }
+
+ @Override
+ public synchronized FileDataTypeArchive openFileArchive(ResourceFile file,
+ boolean openForUpdate, Upgrade upgradeStrategy, TaskMonitor monitor)
+ throws IOException, DuplicateIdException, CancelledException {
+ file = file.getCanonicalFile();
+ FileDataTypeArchive archive = getOpenArchive(file);
+ if (archive == null) {
+ boolean okToUpgrade = upgradeStrategy == Upgrade.YES;
+ archive = doOpenFileArchive(file, openForUpdate, okToUpgrade, monitor);
+ addArchive(archive);
+ }
+ return archive;
+ }
+
+ private FileDataTypeArchive doOpenFileArchive(ResourceFile file, boolean openForUpdate,
+ boolean okToUpgrade, TaskMonitor monitor) throws IOException, CancelledException {
+ try {
+ if (!openForUpdate) {
+ return DataTypeArchiveFactory.openReadOnly(file, this, monitor);
+ }
+ return DataTypeArchiveFactory.openForUpdate(file, okToUpgrade, this, monitor);
+ }
+ catch (VersionException e) {
+ throw new IOException(e);
+ }
+ }
+
+ private void addArchive(PersistentDataTypeArchive archive)
+ throws DuplicateIdException {
+ UniversalID id = archive.getDataTypeManager().getUniversalID();
+ PersistentDataTypeArchive existing = openArchives.get(id);
+ if (existing != null) {
+ if (existing.isClosed()) {
+ openArchives.remove(id);
+ }
+ else {
+ archive.release(this);
+ throw new DuplicateIdException(archive.getName(), existing.getName());
+ }
+ }
+ openArchives.put(id, archive);
+ }
+
+ private FileDataTypeArchive getOpenArchive(ResourceFile file) {
+ for (PersistentDataTypeArchive archive : openArchives.values()) {
+ if (archive instanceof FileDataTypeArchive fileArchive) {
+ if (fileArchive.getFile().equals(file)) {
+ if (fileArchive.isClosed()) {
+ openArchives.remove(fileArchive.getDataTypeManager().getUniversalID());
+ return null;
+ }
+ return fileArchive;
+ }
+ }
+ }
+ return null;
+ }
+
+ private ProjectDataTypeArchive getOpenArchive(DomainFile projectFile) {
+ for (PersistentDataTypeArchive archive : openArchives.values()) {
+ if (archive instanceof ProjectDataTypeArchive projectArchive) {
+ if (archive.getDomainFile().equals(projectFile)) {
+ if (archive.isClosed()) {
+ openArchives.remove(archive.getDataTypeManager().getUniversalID());
+ return null;
+ }
+ return projectArchive;
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/BuiltInArchive.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/BuiltInArchive.java
deleted file mode 100644
index 9a874a75aa..0000000000
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/BuiltInArchive.java
+++ /dev/null
@@ -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;
- }
-}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DataTypeManagerHandler.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DataTypeManagerHandler.java
deleted file mode 100644
index 28baeeba2b..0000000000
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DataTypeManagerHandler.java
+++ /dev/null
@@ -1,1810 +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 static ghidra.framework.main.DataTreeDialogType.*;
-
-import java.awt.Component;
-import java.awt.event.ActionListener;
-import java.io.*;
-import java.rmi.ConnectException;
-import java.util.*;
-
-import docking.widgets.OptionDialog;
-import docking.widgets.pathmanager.PathManager;
-import generic.jar.ResourceFile;
-import generic.util.Path;
-import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
-import ghidra.app.plugin.core.datamgr.editor.DataTypeEditorManager;
-import ghidra.app.plugin.core.datamgr.util.DataTypeArchiveUtility;
-import ghidra.app.util.HelpTopics;
-import ghidra.framework.client.*;
-import ghidra.framework.main.DataTreeDialog;
-import ghidra.framework.main.DataTreeDialogType;
-import ghidra.framework.model.*;
-import ghidra.framework.options.SaveState;
-import ghidra.framework.plugintool.PluginTool;
-import ghidra.framework.store.FileSystem;
-import ghidra.program.database.DataTypeArchiveContentHandler;
-import ghidra.program.database.DataTypeArchiveDB;
-import ghidra.program.database.data.ProgramDataTypeManager;
-import ghidra.program.model.data.*;
-import ghidra.program.model.listing.DataTypeArchive;
-import ghidra.program.model.listing.Program;
-import ghidra.util.*;
-import ghidra.util.exception.*;
-import ghidra.util.task.*;
-
-/**
- * Helper class to manage the archive files.
- */
-
-public class DataTypeManagerHandler {
-
- private static final String CONTENT_NAME = "Data Type Archive";
- private final static String ARCHIVE_NAMES = "ArchiveNames";
- private static final String RELATIVE_PATH_PREFIX = ".";
- private static final String PROJECT_NAME_DELIMETER = ":";
- private final static String RECENT_NAMES = "RecentArchiveNames";
- private static final String FAVORITES = "Favorite Dts";
-
- private static final String[] UNALLOWED_ARCHIVE_PATH_FRAGMENTS = new String[] {
- "/Ghidra/Extensions/", "/Ghidra/docs/", "/Ghidra/Features/", "/Ghidra/Test/" };
-
- public static final String OLD_DATA_TYPE_ARCHIVE_PATH_KEY = "DATA_TYPE_ARCHIVE_PATH";
- public static final String DATA_TYPE_ARCHIVE_PATH_KEY = "DATATYPE_ARCHIVE_PATHS";
- public static final String DISABLED_DATA_TYPE_ARCHIVE_PATH_KEY =
- "DISABLED_DATA_TYPE_ARCHIVE_PATH";
-
- private ProgramArchive programArchive;
- private List openArchives = new ArrayList<>();
- private Set initiallyOpenedFileArchiveNames = new HashSet<>();
- private Set userOpenedFileArchiveNames = new HashSet<>();
- private Set knownOpenFileArchiveNames = new HashSet<>();
- private Map invalidArchives = new HashMap<>();
-
- private boolean treeDialogCancelled = false;
- private DomainFileFilter archiveFileFilter;
-
- private DataTypeIndexer dataTypeIndexer;
- private List archiveManagerlisteners = new ArrayList<>();
- private List dataTypeManagerListeners = new ArrayList<>();
-
- private RecentlyUsedDataType recentlyUsedDataType = new RecentlyUsedDataType();
-
- private BuiltInDataTypeManager builtInDataTypesManager;
- private final DataTypeManagerPlugin plugin;
- private PluginTool tool;
- private DataTypeManagerListenerDelegate listenerDelegate;
- private MyFolderListener folderListener;
-
- // Updated anytime any datatype or category changes in any open archive, including the program
- // archive. Currently used by data type tree nodes to know if their tooltip cache is stale.
- private long modCount = 0;
-
- public DataTypeManagerHandler(DataTypeManagerPlugin plugin) {
- this.plugin = plugin;
- this.tool = plugin.getTool();
- listenerDelegate = new DataTypeManagerListenerDelegate();
- builtInDataTypesManager = BuiltInDataTypeManager.getDataTypeManager();
- builtInDataTypesManager.addDataTypeManagerListener(listenerDelegate);
- initializeFavorites();
-
- dataTypeIndexer = new DataTypeIndexer();
- dataTypeIndexer.addDataTypeManager(builtInDataTypesManager);
- openArchives.add(new BuiltInArchive(this, builtInDataTypesManager));
-
- archiveFileFilter = new DefaultDomainFileFilter(DataTypeArchive.class, true);
-
- folderListener = new MyFolderListener();
- tool.getProject().getProjectData().addDomainFolderChangeListener(folderListener);
- }
-
- public void dispose() {
- dataTypeIndexer.removeDataTypeManager(builtInDataTypesManager);
- builtInDataTypesManager.removeDataTypeManagerListener(listenerDelegate);
- tool.getProject().getProjectData().removeDomainFolderChangeListener(folderListener);
- }
-
- /**
- * Returns the current modification count which is incremented anytime any archive or any
- * category or datatype it contains is changed in any way. This includes the datatypes in
- * the current program.
- * @return the current modification id.
- */
- public long getModificationCount() {
- return modCount;
- }
-
- /**
- * Notification that the given program is open. Add the root category
- * for the program to any provider that is open.
- * @param program the program
- */
- public void programOpened(Program program) {
- boolean wasChanged = tool.hasConfigChanged();
- programArchive = new ProgramArchive(program);
- openProgramArchives(program);
- addArchive(programArchive);
-
- // Do not mark tool configs as changed when restoring archives used by the program. The
- // archives opened by the program are considered transient. Alternatively, archives opened
- // by the user will trigger config state changes.
- tool.setConfigChanged(wasChanged);
- }
-
- /**
- * Notification that the program is closed. Remove the root category
- * for the program from the provider.
- */
- public void programClosed() {
-
- programArchive.getDataTypeManager().removeDataTypeManagerListener(listenerDelegate);
- dataTypeIndexer.removeDataTypeManager(programArchive.getDataTypeManager());
- openArchives.remove(programArchive);
- fireArchiveClosed(programArchive);
- programArchive = null;
- }
-
- private void openProgramArchives(Program program) {
- DataTypeManager programDataTypeManager = program.getDataTypeManager();
- List sources = programDataTypeManager.getSourceArchives();
- for (SourceArchive dataTypeSource : sources) {
- if (isOpen(dataTypeSource) || isKnownInvalidArchive(dataTypeSource)) {
- continue;
- }
- switch (dataTypeSource.getArchiveType()) {
- case PROJECT:
- openProjectArchive(dataTypeSource);
- break;
- case FILE:
- openFileArchive(dataTypeSource);
- break;
- default:
- // all other cases do nothing
- break;
- }
-
- }
- }
-
- private boolean isOpen(SourceArchive dataTypeSource) {
- List allArchives = getAllArchives();
- for (Archive archive : allArchives) {
- DataTypeManager dataTypeManager = archive.getDataTypeManager();
- UniversalID universalID = dataTypeManager.getUniversalID();
- if ((universalID != null) && universalID.equals(dataTypeSource.getSourceArchiveID())) {
- return true;
- }
- }
- return false;
- }
-
- private void openProjectArchive(SourceArchive dataTypeSource) {
- String domainFileID = dataTypeSource.getDomainFileID();
- DomainFile domainFile =
- plugin.getTool().getProject().getProjectData().getFileByID(domainFileID);
- if (domainFile == null) {
- createInvalidArchiveNode(dataTypeSource);
- return;
- }
- plugin.openArchive(domainFile);
- }
-
- private void updateSourceArchiveName(DataTypeManager dataTypeManager, String fileID,
- String name) {
- int transactionID =
- dataTypeManager.startTransaction("Update Data Type Source Archive Name");
- try {
- dataTypeManager.updateSourceArchiveName(fileID, name);
- }
- finally {
- dataTypeManager.endTransaction(transactionID, true);
- }
- }
-
- /**
- * @return all archive search paths (both enabled and disabled are included)
- */
- private Path[] getArchivePaths() {
- return PathManager.getPathsFromPreferences(DATA_TYPE_ARCHIVE_PATH_KEY, null,
- DISABLED_DATA_TYPE_ARCHIVE_PATH_KEY);
- }
-
- private FileArchive openFileArchive(String archiveName, UniversalID archiveID,
- boolean acquireWriteLock) {
-
- if (archiveName.endsWith(FileDataTypeManager.SUFFIX)) {
- archiveName = archiveName.substring(0,
- archiveName.length() - FileDataTypeManager.SUFFIX.length());
- }
-
- String archiveFileName = archiveName + FileDataTypeManager.SUFFIX;
-
- List allArchives = getAllArchives();
- for (Archive archive : allArchives) {
- if (archive instanceof FileArchive) {
- if (archive.getName().equals(archiveName)) {
- if (archiveID == null ||
- archiveID.equals(archive.getDataTypeManager().getUniversalID())) {
- if (acquireWriteLock && !archive.isModifiable()) {
- // Close archive - hopefully it will get reopened below
- closeArchive(archive);
- }
- break;
- }
- }
- }
- }
-
- Path[] pathsFromPreferences = getArchivePaths();
- for (Path path : pathsFromPreferences) {
- if (!path.isEnabled() || !isAllowedArchivePath(path.getPathAsString())) {
- continue;
- }
- ResourceFile archiveFile = new ResourceFile(path.getPath(), archiveFileName);
- if (archiveFile.exists()) {
- FileArchive archive = openFileArchive(archiveFile, archiveID, acquireWriteLock);
- if (archive != null) {
- return archive;
- }
- }
- }
-
- // Look for archive provided with installation (read-only)
- ResourceFile archiveFile = DataTypeArchiveUtility.findArchiveFile(archiveFileName);
- if (archiveFile == null) {
- Msg.showError(this, plugin.getProvider().getComponent(), "Open Archive Failed",
- "Archive file not found: " + archiveFileName);
- return null;
- }
- return openFileArchive(archiveFile, archiveID, false);
- }
-
- private FileArchive openFileArchive(ResourceFile archiveFile, UniversalID archiveID,
- boolean acquireWriteLock) {
- try {
- FileArchive archive = new FileArchive(this, archiveFile, acquireWriteLock);
- if (archiveID == null ||
- archiveID.equals(archive.getDataTypeManager().getUniversalID())) {
- addArchive(archive);
- return archive;
- }
- archive.close();
- }
- catch (Throwable t) {
- // Show and/or log error
- handleArchiveFileException(plugin, archiveFile, t);
- }
- return null;
- }
-
- private void openFileArchive(SourceArchive dataTypeSource) {
- if (openFileArchive(dataTypeSource.getName(), dataTypeSource.getSourceArchiveID(),
- false) == null) {
- createInvalidArchiveNode(dataTypeSource);
- }
- }
-
- public Archive createArchive(File file) {
- try {
- Archive archive = new FileArchive(this, file);
- addArchivePath(new ResourceFile(file));
- addArchive(archive);
- userOpenedFileArchiveNames.add(getSaveableArchive(file.getAbsolutePath()));
- return archive;
- }
- catch (Exception e) {
- Msg.showError(this, plugin.getProvider().getComponent(), "Create Archive Failed",
- "Error creating archive file (" + file.getName() + "): " + e.getMessage());
- }
- return null;
- }
-
- public Archive createProjectArchive() throws CancelledException {
- CreateDataTypeArchiveDataTreeDialog dialog = getCreateDialog();
-
- treeDialogCancelled = true;
- tool.showDialog(dialog);
- if (treeDialogCancelled) {
- throw new CancelledException();
- }
-
- DataTypeArchive dataTypeArchive = dialog.getNewDataTypeArchiveDB();
- Archive archive =
- new ProjectArchive(this, dataTypeArchive, dataTypeArchive.getDomainFile());
- addArchive(archive);
- return archive;
- }
-
- @SuppressWarnings("unused")
- private void copyArchive(Archive originalArchive, Archive newArchive, TaskMonitor monitor) {
- DataTypeManager originalManager = originalArchive.getDataTypeManager();
- DataTypeManager newManager = newArchive.getDataTypeManager();
-
- Category originalRoot = originalManager.getRootCategory();
- Category newRoot = newManager.getRootCategory();
- Category[] categories = originalRoot.getCategories();
-
- monitor.setMessage(
- "Copy Archive " + originalArchive.getName() + " to " + newArchive.getName());
- monitor.initialize(categories.length);
-
- int transactionID = newManager.startTransaction("Copy Archive");
- try {
- for (Category category : categories) {
- newRoot.copyCategory(category, null, monitor);
- monitor.incrementProgress(1);
- }
- DataType[] dataTypes = originalRoot.getDataTypes();
- for (DataType type : dataTypes) {
- if (monitor.isCancelled()) {
- return;
- }
- newRoot.addDataType(type, null);
- }
- }
- finally {
- newManager.endTransaction(transactionID, true);
- }
- }
-
- private void openArchives(String[] archiveFilenames) {
- for (String filename : archiveFilenames) {
- String[] projectPathname = DataTypeManagerHandler.parseProjectPathname(filename);
- if (projectPathname != null) {
- DomainFile df =
- plugin.getProjectArchiveFile(projectPathname[0], projectPathname[1]);
- if (df != null) {
- plugin.openArchive(df);
- }
- }
- else {
- File file = new File(filename);
- if (!file.exists()) {
- continue; // if the file does not exist, skip it.
- }
- try {
- openArchive(file, false, false);
- }
- catch (Throwable t) {
- DataTypeManagerHandler.handleArchiveFileException(plugin,
- new ResourceFile(file), t);
- }
- }
- }
- }
-
- /**
- * Determine if archive path is allowed.
- * An attempt is made to disallow any path which appears to be contained
- * within a Ghidra installation.
- * @param path directory or file archive path
- * @return true if path is allowed
- */
- public boolean isAllowedArchivePath(String path) {
-
- if (path.startsWith(Path.GHIDRA_HOME)) {
- return false; // Ghidra typeinfo directories will always be searched
- }
-
- for (String unallowed : UNALLOWED_ARCHIVE_PATH_FRAGMENTS) {
- if (path.indexOf(unallowed) > 0) {
- // Remembering paths to older Ghidra installations is bad
- return false;
- }
- }
-
- return true;
- }
-
- private void addArchivePath(ResourceFile archiveFilePath) {
-
- Path newPath = new Path(archiveFilePath.getParentFile());
- if (!isAllowedArchivePath(newPath.getPathAsString())) {
- return;
- }
-
- Path[] paths = getArchivePaths();
- for (Path path : paths) {
- if (path.equals(newPath)) {
- if (!path.isEnabled()) {
- path.setEnabled(true);
- PathManager.savePathsToPreferences(DATA_TYPE_ARCHIVE_PATH_KEY,
- DISABLED_DATA_TYPE_ARCHIVE_PATH_KEY, paths);
- }
- return;
- }
- }
-
- Path[] newPaths = new Path[paths.length + 1];
- System.arraycopy(paths, 0, newPaths, 0, paths.length);
- newPaths[paths.length] = newPath;
-
- PathManager.savePathsToPreferences(DATA_TYPE_ARCHIVE_PATH_KEY,
- DISABLED_DATA_TYPE_ARCHIVE_PATH_KEY, newPaths);
- }
-
- public Archive openArchive(File file, boolean acquireWriteLock, boolean isUserAction)
- throws IOException, DuplicateIdException {
- return openArchive(new ResourceFile(file), acquireWriteLock, isUserAction);
- }
-
- public FileArchive openArchive(ResourceFile file, boolean acquireWriteLock,
- boolean isUserAction) throws IOException, DuplicateIdException {
-
- file = file.getCanonicalFile();
-
- FileArchive archive = getArchiveForFile(file);
- if (archive == null) {
- archive = new FileArchive(this, file, acquireWriteLock);
- Archive existingArchive =
- findOpenFileArchiveWithID(archive.getDataTypeManager().getUniversalID());
- if (existingArchive != null) {
- archive.close();
- throw new DuplicateIdException(archive.getName(), existingArchive.getName());
- }
- addArchivePath(file);
- addArchive(archive);
- }
- if (isUserAction) {
- userOpenedFileArchiveNames.add(getSaveableArchive(file.getAbsolutePath()));
- }
- return archive;
- }
-
- private Archive findOpenFileArchiveWithID(UniversalID universalID) {
- if (universalID == null) {
- return null;
- }
- List allArchives = getAllArchives();
- for (Archive archive : allArchives) {
- if (universalID.equals(archive.getDataTypeManager().getUniversalID())) {
- return archive;
- }
- }
- return null;
- }
-
- public Archive openArchive(DomainFile domainFile, boolean okToUpgrade, boolean okToRecover,
- TaskMonitor monitor) throws VersionException, CancelledException, IOException {
-
- Archive archive = getArchiveForDomainFile(domainFile);
- if (archive != null) {
- return archive;
- }
-
- DataTypeArchive dataTypeArchive =
- (DataTypeArchive) domainFile.getDomainObject(tool, okToUpgrade, okToRecover, monitor);
- archive = new ProjectArchive(this, dataTypeArchive, domainFile);
- addArchive(archive);
- return archive;
- }
-
- public Archive openArchive(DataTypeArchive dataTypeArchive) {
- return openArchive(dataTypeArchive, dataTypeArchive.getDomainFile());
- }
-
- public Archive openArchive(DataTypeArchive dataTypeArchive, DomainFile domainFile) {
- Archive archive = getArchiveForDomainFile(domainFile);
- if (archive != null) {
- return archive; // already created
- }
-
- // this file comes to us created from somewhere else, so we must register ourselves as
- // a consumer of this file
- dataTypeArchive.addConsumer(tool);
-
- archive = new ProjectArchive(this, dataTypeArchive, domainFile);
- addArchive(archive);
- return archive;
- }
-
- private void createInvalidArchiveNode(SourceArchive sourceArchive) {
- addInvalidArchive(new InvalidFileArchive(this, sourceArchive));
- }
-
- public DataTypeManager openArchive(String archiveName)
- throws IOException, DuplicateIdException {
- ResourceFile file = DataTypeArchiveUtility.findArchiveFile(archiveName);
- if (file != null) {
- Archive archive = openArchive(file, false, false);
- if (archive != null) {
- return archive.getDataTypeManager();
- }
- }
- return null;
- }
-
- private FileArchive getArchiveForFile(ResourceFile file) {
- for (Archive archive : openArchives) {
- if (archive instanceof FileArchive) {
- FileArchive fileArchive = (FileArchive) archive;
- if (file.equals(fileArchive.getFile())) {
- return fileArchive;
- }
- }
- }
- return null;
- }
-
- private Archive getArchiveForDomainFile(DomainFile domainFile) {
- for (Archive archive : openArchives) {
- if (archive instanceof ProjectArchive) {
- ProjectArchive projectArchive = (ProjectArchive) archive;
- if (domainFile.equals(projectArchive.getDomainFile())) {
- return projectArchive;
- }
- }
- }
- return null;
- }
-
- private void addArchive(Archive archive) {
- updateArchiveNameInfo(archive);
- openArchives.add(archive);
- archive.getDataTypeManager().addDataTypeManagerListener(listenerDelegate);
- dataTypeIndexer.addDataTypeManager(archive.getDataTypeManager());
- if (!(archive instanceof ProgramArchive)) {
- tool.setConfigChanged(true);
- }
- if (archive instanceof ProjectArchive) {
- String projectPath = getProjectPathname((ProjectArchive) archive, true);
- if (projectPath != null) {
- userOpenedFileArchiveNames.add(projectPath);
- }
- }
- fireArchiveOpened(archive);
- }
-
- private void updateArchiveNameInfo(Archive archive) {
-
- DataTypeManager dataTypeManager = archive.getDataTypeManager();
- int transactionID;
- try {
- transactionID =
- dataTypeManager.startTransaction("Update Data Type Source Archive Names");
- }
- catch (Exception e) {
- // can't update now - no big deal
- return;
- }
- try {
-
- // Notify each open archive about this archives ID and name in case it has changed.
- for (Archive existingArchive : openArchives) {
-
- if (!existingArchive.isModifiable()) {
- continue;
- }
-
- DataTypeManager existingDataTypeManager = existingArchive.getDataTypeManager();
-
- dataTypeManager.updateSourceArchiveName(existingDataTypeManager.getUniversalID(),
- existingDataTypeManager.getName());
-
- int existingTxID = existingDataTypeManager
- .startTransaction("Update Data Type Source Archive Name");
- try {
- existingDataTypeManager.updateSourceArchiveName(
- dataTypeManager.getUniversalID(), dataTypeManager.getName());
- }
- finally {
- existingDataTypeManager.endTransaction(existingTxID, true);
- }
- }
- }
- finally {
- dataTypeManager.endTransaction(transactionID, true);
- }
- }
-
- private boolean isKnownInvalidArchive(SourceArchive sourceArchive) {
- return invalidArchives.get(sourceArchive.getSourceArchiveID()) != null;
- }
-
- private void addInvalidArchive(InvalidFileArchive archive) {
- invalidArchives.put(archive.getUniversalID(), archive);
- fireArchiveOpened(archive);
- }
-
- public List getAllArchives() {
- return new ArrayList<>(openArchives);
- }
-
- void archiveClosed(Archive archive) {
- if (archive instanceof InvalidFileArchive) {
- invalidArchives.remove(((InvalidFileArchive) archive).getUniversalID());
- }
- else {
- if (archive instanceof ProjectArchive) {
- ((ProjectArchive) archive).getDomainObject().release(tool);
- }
- archive.getDataTypeManager().removeDataTypeManagerListener(listenerDelegate);
- dataTypeIndexer.removeDataTypeManager(archive.getDataTypeManager());
- openArchives.remove(archive);
- }
- tool.setConfigChanged(true);
- fireArchiveClosed(archive);
- }
-
- void dataTypeManagerChanged(FileArchive archive, DataTypeManager oldManager,
- DataTypeManager newManager) {
- oldManager.removeDataTypeManagerListener(listenerDelegate);
- newManager.addDataTypeManagerListener(listenerDelegate);
- dataTypeIndexer.removeDataTypeManager(oldManager);
- dataTypeIndexer.addDataTypeManager(newManager);
- fireDataTypeManagerChanged(archive);
- }
-
- public void setRecentlyUsedDataType(DataType dataType) {
- recentlyUsedDataType = new RecentlyUsedDataType(dataType);
-
- }
-
- public DataType getRecentlyDataType() {
- return recentlyUsedDataType.getDataType();
- }
-
- public DataTypeManager getBuiltInDataTypesManager() {
- return builtInDataTypesManager;
- }
-
- public DataTypeManager getProgramDataTypeManager() {
- if (programArchive != null) {
- return programArchive.getDataTypeManager();
- }
- return null;
- }
-
- public DataTypeIndexer getDataTypeIndexer() {
- return dataTypeIndexer;
- }
-
- public void closeAllArchives() {
- // this list will get modified as we close archives, so work from a copy
- Archive[] archives = openArchives.toArray(new Archive[openArchives.size()]);
- for (Archive archive : archives) {
- archive.close();
- }
- }
-
- public void closeArchive(DataTypeManager dtm) {
-
- if (dtm instanceof BuiltInDataTypeManager) {
- Msg.info(this, "Cannot close the built-in Data Type Manager");
- return;
- }
-
- if (dtm instanceof ProgramDataTypeManager) {
- Msg.info(this, "Cannot close the Program's Data Type Manager");
- return;
- }
-
- Archive archive = getArchive(dtm);
- if (archive == null) {
- Msg.info(this, "Unable close archive; archive not open: '" + dtm.getName() + "'");
- }
-
- closeArchive(archive);
- Msg.info(this, "Closed archive: '" + archive.getName() + "'");
- }
-
- public Archive getArchive(DataTypeManager dtm) {
- for (Archive archive : openArchives) {
- DataTypeManager dataTypeManager = archive.getDataTypeManager();
- if (dataTypeManager.equals(dtm)) {
- return archive;
- }
- }
- return null;
- }
-
- public void closeArchive(Archive archive) {
- DataTypeEditorManager editorManager = DataTypeManagerHandler.this.plugin.getEditorManager();
- editorManager.dismissEditors(archive.getDataTypeManager());
-
- archive.close(); // this will call us back
- }
-
- public void removeInvalidArchive(InvalidFileArchive archive) {
- archive.close();
-
- if (programArchive == null) {
- return;
- }
-
- ProgramDataTypeManager programDataTypeManager =
- (ProgramDataTypeManager) programArchive.getDataTypeManager();
- Program program = programArchive.getProgram();
- int ID = program.startTransaction("Remove Invalid Source Archive From Program");
- try {
- UniversalID sourceArchiveID = archive.getUniversalID();
- SourceArchive sourceArchive = programDataTypeManager.getSourceArchive(sourceArchiveID);
- if (sourceArchive != null) {
- programDataTypeManager.removeSourceArchive(sourceArchive);
- }
- }
- finally {
- program.endTransaction(ID, true);
- }
- }
-
- public void addArchiveManagerListener(ArchiveManagerListener listener) {
- archiveManagerlisteners.add(listener);
- }
-
- public void removeArchiveManagerListener(ArchiveManagerListener listener) {
- archiveManagerlisteners.remove(listener);
- }
-
- private void fireArchiveOpened(final Archive archive) {
- SystemUtilities.runSwingNow(() -> {
- for (ArchiveManagerListener listener : archiveManagerlisteners) {
- listener.archiveOpened(archive);
- }
- });
- }
-
- private void fireArchiveClosed(final Archive archive) {
- SystemUtilities.runSwingNow(() -> {
- for (ArchiveManagerListener listener : archiveManagerlisteners) {
- listener.archiveClosed(archive);
- }
- });
- }
-
- public void fireDataTypeManagerChanged(final FileArchive archive) {
- SystemUtilities.runSwingNow(() -> {
- for (ArchiveManagerListener listener : archiveManagerlisteners) {
- listener.archiveDataTypeManagerChanged(archive);
- }
- });
- }
-
- public void fireArchiveStateChanged(final Archive archive) {
- SystemUtilities.runSwingNow(() -> {
- for (ArchiveManagerListener listener : archiveManagerlisteners) {
- listener.archiveStateChanged(archive);
- }
- });
- }
-
- public boolean isInUse(File file) {
- for (Archive archive : openArchives) {
- if (archive instanceof FileArchive) {
- if (file.equals(((FileArchive) archive).getFile().getFile(false))) {
- return true;
- }
- }
- }
- return false;
- }
-
- public List getAllFileOrProjectArchives() {
- List archiveList = new ArrayList<>();
- for (Archive archive : openArchives) {
- if (archive instanceof FileArchive || archive instanceof ProjectArchive) {
- archiveList.add(archive);
- }
- }
- return archiveList;
- }
-
- public List getAllModifiedFileArchives() {
- List archiveList = new ArrayList<>();
- for (Archive archive : openArchives) {
- if (archive.isModifiable() && archive instanceof FileArchive) {
- archiveList.add(archive);
- }
- }
- return archiveList;
- }
-
- /**
- * Returns all favorite DataTypes in all archives.
- * @return all favorite DataTypes in all archives.
- */
- public List getFavoriteDataTypes() {
- List list = new ArrayList<>();
- List allArchives = getAllArchives();
- for (Archive archive : allArchives) {
- DataTypeManager dataTypeManager = archive.getDataTypeManager();
- list.addAll(dataTypeManager.getFavorites());
- }
-
- return list;
- }
-
- private void initializeFavorites() {
-
- builtInDataTypesManager
- .setFavorite(builtInDataTypesManager.resolve(PointerDataType.dataType, null), true);
-
- builtInDataTypesManager
- .setFavorite(builtInDataTypesManager.resolve(CharDataType.dataType, null), true);
-
- builtInDataTypesManager
- .setFavorite(builtInDataTypesManager.resolve(StringDataType.dataType, null), true);
- builtInDataTypesManager.setFavorite(
- builtInDataTypesManager.resolve(TerminatedStringDataType.dataType, null), true);
- builtInDataTypesManager.setFavorite(
- builtInDataTypesManager.resolve(TerminatedUnicodeDataType.dataType, null), true);
-
- builtInDataTypesManager
- .setFavorite(builtInDataTypesManager.resolve(FloatDataType.dataType, null), true);
- builtInDataTypesManager
- .setFavorite(builtInDataTypesManager.resolve(DoubleDataType.dataType, null), true);
- builtInDataTypesManager.setFavorite(
- builtInDataTypesManager.resolve(LongDoubleDataType.dataType, null), true);
-
- builtInDataTypesManager
- .setFavorite(builtInDataTypesManager.resolve(IntegerDataType.dataType, null), true);
- builtInDataTypesManager
- .setFavorite(builtInDataTypesManager.resolve(LongDataType.dataType, null), true);
- builtInDataTypesManager.setFavorite(
- builtInDataTypesManager.resolve(UnsignedIntegerDataType.dataType, null), true);
- builtInDataTypesManager.setFavorite(
- builtInDataTypesManager.resolve(UnsignedLongDataType.dataType, null), true);
-
- builtInDataTypesManager
- .setFavorite(builtInDataTypesManager.resolve(ByteDataType.dataType, null), true);
- builtInDataTypesManager
- .setFavorite(builtInDataTypesManager.resolve(WordDataType.dataType, null), true);
- builtInDataTypesManager
- .setFavorite(builtInDataTypesManager.resolve(DWordDataType.dataType, null), true);
- builtInDataTypesManager
- .setFavorite(builtInDataTypesManager.resolve(QWordDataType.dataType, null), true);
-
- }
-
-//==================================================================================================
-// Storage Methods
-//==================================================================================================
-
- public void save(SaveState saveState) {
- saveArchiveNames(saveState);
- saveFavorites(saveState);
- }
-
- public void restore(SaveState saveState) {
- restoreArchiveNames(saveState);
- restoreFavorites(saveState);
- }
-
- private void saveArchiveNames(SaveState saveState) {
- List openNameList = new ArrayList<>();
- if (knownOpenFileArchiveNames.isEmpty()) {
- for (Archive archive : openArchives) {
- String filePath = null;
- if (archive instanceof FileArchive) {
- FileArchive fileArchive = (FileArchive) archive;
- ResourceFile file = fileArchive.getFile();
- if (file != null) {
- filePath = file.getAbsolutePath();
- }
- }
- else if (archive instanceof ProjectArchive) {
- filePath = getProjectPathname((ProjectArchive) archive, true);
- }
- if (filePath != null) {
- openNameList.add(filePath);
- }
- }
- }
- else {
- openNameList.addAll(knownOpenFileArchiveNames);
- }
- saveState.putStrings(ARCHIVE_NAMES, getSaveableArchiveNames(openNameList));
-
- List recentMenuList = new ArrayList<>();
- Collection recentlyOpenedArchives = plugin.getRecentlyOpenedArchives();
- for (String file : recentlyOpenedArchives) {
- recentMenuList.add(file);
- }
- saveState.putStrings(RECENT_NAMES, getSaveableArchiveNames(recentMenuList));
-
- // update the initialArchives list so that future checks on that list do not trigger a
- // state change
- initiallyOpenedFileArchiveNames = getOpenFileArchiveNames(openArchives);
- }
-
- private String[] getSaveableArchiveNames(List absoluteFilenameList) {
- String[] saveableFilenames = new String[absoluteFilenameList.size()];
- for (int i = 0; i < absoluteFilenameList.size(); i++) {
- saveableFilenames[i] = getSaveableArchive(absoluteFilenameList.get(i));
- }
- return saveableFilenames;
- }
-
- private String getSaveableArchive(String absoluteFilename) {
- if (absoluteFilename.startsWith(PROJECT_NAME_DELIMETER)) {
- return absoluteFilename;
- }
- Path path = new Path(absoluteFilename);
- return path.getPathAsString();
- }
-
- private void restoreArchiveNames(SaveState saveState) {
- String[] savedFilenames = saveState.getStrings(ARCHIVE_NAMES, new String[0]);
-// for (int i = 0 ; i < savedFilenames.length ; ++i) {
-// savedFilenames[i] = StringUtilities.fixupPathSeparator(savedFilenames[i]);
-// }
- String[] filenames = getAbsoluteArchiveNames(savedFilenames);
-
- openArchives(filenames);
-
- String[] recentFilenames = saveState.getStrings(RECENT_NAMES, null);
- filenames = getAbsoluteArchiveNames(recentFilenames);
- for (String filename : filenames) {
- if (filename.startsWith(PROJECT_NAME_DELIMETER)) {
- String[] projectPathname = parseProjectPathname(filename);
- if (projectPathname != null) {
- plugin.addRecentlyOpenedProjectArchive(projectPathname[0], projectPathname[1]);
- }
- }
- else {
- ResourceFile file = new ResourceFile(filename);
- if (file.exists()) {
- file = file.getCanonicalFile();
- plugin.addRecentlyOpenedArchiveFile(file);
- }
- }
- }
-
- for (String filename : savedFilenames) {
- initiallyOpenedFileArchiveNames.add(filename);
- }
- userOpenedFileArchiveNames = new HashSet<>();
- knownOpenFileArchiveNames = new HashSet<>();
- }
-
- /**
- * Determine if we can remember the specified project archive using a simple project path
- * (e.g., we can't remember specific versions).
- * @param pa project archive
- * @param activeProjectOnly if true pa must be contained within the
- * active project to be remembered.
- * @return return project path which can be remembered or null
- */
- public String getProjectPathname(ProjectArchive pa, boolean activeProjectOnly) {
- // Project archives are always opened by a user.
- // Only remember it if it is the current version within the current project
- DomainFile df = pa.getDomainObject().getDomainFile();
- ProjectLocator projectLocator = df.getProjectLocator();
- String projectName = projectLocator.getName();
- String dfProjectName = projectName;
- boolean remember = df.isInWritableProject();
- if (!remember) {
- // handle read-only case
- Project project = tool.getProjectManager().getActiveProject();
- remember = (project != null && project.getName().equals(dfProjectName) &&
- df.getVersion() == DomainFile.DEFAULT_VERSION);
- }
- return remember ? getProjectPathname(projectName, df.getPathname()) : null;
- }
-
- private static String[] getAbsoluteArchiveNames(String[] saveableFilenames) {
- if (saveableFilenames == null) {
- return new String[0];
- }
- List absoluteFilenameList = new ArrayList<>();
- for (String filename : saveableFilenames) {
- try {
- filename = filename.startsWith(PROJECT_NAME_DELIMETER) ? filename
- : getAbsoluteArchive(filename);
- absoluteFilenameList.add(filename);
- }
- catch (FileNotFoundException e) {
- Msg.error(DataTypeManagerHandler.class, e.getMessage());
- }
- }
- String[] absoluteFilenames = new String[absoluteFilenameList.size()];
- for (int i = 0; i < absoluteFilenames.length; i++) {
- absoluteFilenames[i] = absoluteFilenameList.get(i);
- }
- return absoluteFilenames;
- }
-
- private static String getAbsoluteArchive(String saveableFilename) throws FileNotFoundException {
- if (saveableFilename.startsWith(RELATIVE_PATH_PREFIX)) {
- ResourceFile file = DataTypeArchiveUtility.findArchiveFile(saveableFilename);
- if (file == null) {
- throw new FileNotFoundException("Archive not found: " + saveableFilename);
- }
- return file.getAbsolutePath();
- }
- Path path = new Path(saveableFilename);
- return path.getPath().getAbsolutePath();
- }
-
- void saveFavorites(SaveState saveState) {
- List favoritesList = builtInDataTypesManager.getFavorites();
- String[] names = new String[favoritesList.size()];
- for (int i = 0; i < names.length; i++) {
- DataType dataType = favoritesList.get(i);
- names[i] = dataType.getPathName();
- }
-
- saveState.putStrings(FAVORITES, names);
- }
-
- void restoreFavorites(SaveState saveState) {
- String[] names = saveState.getStrings(FAVORITES, new String[0]);
- if (names.length == 0) {
- return;
- }
- Set favorites = new HashSet<>();
- for (String name : names) {
- DataType dataType = builtInDataTypesManager.getDataType(name);
- if (dataType != null) {
- favorites.add(dataType);
- }
- }
-
- List currentFavoritesList = builtInDataTypesManager.getFavorites();
- for (DataType type : currentFavoritesList) {
- if (favorites.contains(type)) {
- favorites.remove(type);
- }
- else {
- builtInDataTypesManager.setFavorite(type, false);
- }
- }
- for (DataType dataType : favorites) {
- builtInDataTypesManager.setFavorite(dataType, true);
- }
- }
-
- class RecentlyUsedDataType {
-
- private String dataTypeManagerName;
- private CategoryPath path;
- private String dataTypeName;
-
- RecentlyUsedDataType() {
- // default constructor
- }
-
- RecentlyUsedDataType(DataType dt) {
- dataTypeName = dt.getName();
- path = dt.getCategoryPath();
- DataTypeManager dtMgr = dt.getDataTypeManager();
- dataTypeManagerName = dtMgr == null ? null : dtMgr.getName();
-
- if (dataTypeManagerName == null && programArchive != null) {
- DataTypeManager programDataTypeManager = programArchive.getDataTypeManager();
- dataTypeManagerName = programDataTypeManager.getName();
- }
- }
-
- public DataType getDataType() {
- if (dataTypeName == null) {
- return null;
- }
- DataTypeManager dtMgr = findDataTypeManager();
- Category category = dtMgr.getCategory(path);
- if (category != null) {
- DataType dt = category.getDataType(dataTypeName);
- if (dt != null) {
- return dt;
- }
- }
- return getBuiltInDataType();
- }
-
- private DataType getBuiltInDataType() {
- DataTypeManager dtMgr = getBuiltInDataTypesManager();
- Category category = dtMgr.getCategory(path);
- if (category != null) {
- DataType dt = category.getDataType(dataTypeName);
- if (dt != null) {
- return dt;
- }
- }
- return null;
- }
-
- private DataTypeManager findDataTypeManager() {
- for (Archive archive : openArchives) {
- if (archive.getName().equals(dataTypeManagerName)) {
- return archive.getDataTypeManager();
- }
- }
- return builtInDataTypesManager;
- }
- }
-
- public DataTypeManager[] getDataTypeManagers() {
- DataTypeManager[] managers = new DataTypeManager[openArchives.size()];
- for (int i = 0; i < managers.length; i++) {
- managers[i] = openArchives.get(i).getDataTypeManager();
- }
- return managers;
- }
-
- public void addDataTypeManagerChangeListener(DataTypeManagerChangeListener listener) {
- dataTypeManagerListeners.add(listener);
- }
-
- public void removeDataTypeManagerChangeListener(DataTypeManagerChangeListener listener) {
- dataTypeManagerListeners.remove(listener);
- }
-
- class DataTypeManagerListenerDelegate implements DataTypeManagerChangeListener {
-
- @Override
- public void categoryAdded(DataTypeManager dtm, CategoryPath path) {
- modCount++;
- for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
- listener.categoryAdded(dtm, path);
- }
- }
-
- @Override
- public void categoryMoved(DataTypeManager dtm, CategoryPath oldPath, CategoryPath newPath) {
- modCount++;
- for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
- listener.categoryMoved(dtm, oldPath, newPath);
- }
- }
-
- @Override
- public void categoryRemoved(DataTypeManager dtm, CategoryPath path) {
- modCount++;
- for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
- listener.categoryRemoved(dtm, path);
- }
- }
-
- @Override
- public void categoryRenamed(DataTypeManager dtm, CategoryPath oldPath,
- CategoryPath newPath) {
- modCount++;
- for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
- listener.categoryRenamed(dtm, oldPath, newPath);
- }
- }
-
- @Override
- public void dataTypeAdded(DataTypeManager dtm, DataTypePath path) {
- modCount++;
- for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
- listener.dataTypeAdded(dtm, path);
- }
- }
-
- @Override
- public void dataTypeChanged(DataTypeManager dtm, DataTypePath path) {
- modCount++;
- for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
- listener.dataTypeChanged(dtm, path);
- }
- }
-
- @Override
- public void dataTypeMoved(DataTypeManager dtm, DataTypePath oldPath, DataTypePath newPath) {
- modCount++;
- for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
- listener.dataTypeMoved(dtm, oldPath, newPath);
- }
- }
-
- @Override
- public void dataTypeRemoved(DataTypeManager dtm, DataTypePath path) {
- modCount++;
- for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
- listener.dataTypeRemoved(dtm, path);
- }
- }
-
- @Override
- public void dataTypeRenamed(DataTypeManager dtm, DataTypePath oldPath,
- DataTypePath newPath) {
- modCount++;
- for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
- listener.dataTypeRenamed(dtm, oldPath, newPath);
- }
- }
-
- @Override
- public void dataTypeReplaced(DataTypeManager dtm, DataTypePath oldPath,
- DataTypePath newPath, DataType newDataType) {
- modCount++;
- for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
- listener.dataTypeReplaced(dtm, oldPath, newPath, newDataType);
- }
- }
-
- @Override
- public void favoritesChanged(DataTypeManager dtm, DataTypePath path, boolean isFavorite) {
- modCount++;
- for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
- listener.favoritesChanged(dtm, path, isFavorite);
- }
- }
-
- @Override
- public void sourceArchiveAdded(DataTypeManager dataTypeManager,
- SourceArchive dataTypeSource) {
- modCount++;
- for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
- listener.sourceArchiveAdded(dataTypeManager, dataTypeSource);
- }
- }
-
- @Override
- public void sourceArchiveChanged(DataTypeManager dataTypeManager,
- SourceArchive dataTypeSource) {
- modCount++;
- for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
- listener.sourceArchiveChanged(dataTypeManager, dataTypeSource);
- }
- }
-
- @Override
- public void programArchitectureChanged(DataTypeManager dataTypeManager) {
- modCount++;
- for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
- listener.programArchitectureChanged(dataTypeManager);
- }
- }
-
- @Override
- public void restored(DataTypeManager dataTypeManager) {
- modCount++;
- for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) {
- listener.restored(dataTypeManager);
- }
- }
- }
-
- /**
- * Signals to this manager to save the knowledge of all currently opened archives and to mark
- * the tool as dirty (changed) if the current open archives are not the same as those that
- * were initially opened.
- */
- public void updateKnownOpenArchives() {
- knownOpenFileArchiveNames = getOpenFileArchiveNames(openArchives);
- if (!knownOpenFileArchiveNames.equals(initiallyOpenedFileArchiveNames)) {
- tool.setConfigChanged(true);
- }
- }
-
- private Set getOpenFileArchiveNames(List archives) {
- Set newSet = new HashSet<>();
- for (Archive archive : archives) {
- String filePath = null;
- if (archive instanceof FileArchive) {
- ResourceFile file = ((FileArchive) archive).getFile();
- if (file != null) {
- filePath = getSaveableArchive(file.getAbsolutePath());
- }
- }
- else if (archive instanceof ProjectArchive) {
- filePath = getProjectPathname((ProjectArchive) archive, true);
- }
- if (filePath != null && (initiallyOpenedFileArchiveNames.contains(filePath) ||
- userOpenedFileArchiveNames.contains(filePath))) {
- newSet.add(filePath);
- }
- }
- return newSet;
- }
-
- public Set getPossibleEquateNames(long value) {
- Set equateNames = new HashSet<>();
- for (Archive element : openArchives) {
- DataTypeManager dtMgr = element.getDataTypeManager();
- dtMgr.findEnumValueNames(value, equateNames);
- }
- return equateNames;
-
- }
-
- public void save(DomainObject domainObject) {
-
- tool.prepareToSave(domainObject);
- if (acquireSaveLock(domainObject)) {
-
- try {
- DomainFileSaveTask task =
- new DomainFileSaveTask(CONTENT_NAME, domainObject.getDomainFile(), tool);
- new TaskLauncher(task, tool.getToolFrame());
- }
- finally {
- domainObject.unlock();
- }
- }
- }
-
- public void saveAs(DomainObject domainObject) {
- if (!getSaveAsLock(domainObject)) {
- return;
- }
- try {
- DataTreeDialog dialog = getSaveDialog();
- treeDialogCancelled = true;
- tool.showDialog(dialog);
- if (!treeDialogCancelled) {
- saveAs(domainObject, dialog.getDomainFolder(), dialog.getNameText());
- }
- }
- finally {
- domainObject.unlock();
- }
- }
-
- private void saveAs(DomainObject domainObject, DomainFolder folder, String name) {
- DomainFile existingFile = folder.getFile(name);
- if (existingFile == domainObject.getDomainFile()) {
- save(domainObject);
- return;
- }
- if (existingFile != null) {
- String msg = "Program " + name + " already exists.\n" + "Do you want to overwrite it?";
- if (OptionDialog.showOptionDialog(tool.getToolFrame(), "Duplicate Name", msg,
- "Overwrite", OptionDialog.QUESTION_MESSAGE) == OptionDialog.CANCEL_OPTION) {
- return;
- }
- }
- tool.prepareToSave(domainObject);
- DomainObjectSaveAsTask task = new DomainObjectSaveAsTask(CONTENT_NAME, domainObject, folder,
- name, existingFile != null);
- new TaskLauncher(task, tool.getToolFrame());
- }
-
- 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 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;
- }
-
- 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 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(tool.getToolFrame(), 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;
- }
-
- private DataTreeDialog getSaveDialog() {
- DataTreeDialog dialog = new DataTreeDialog(null, "Save As", SAVE, archiveFileFilter);
-
- ActionListener listener = event -> {
- DomainFolder folder = dialog.getDomainFolder();
- String newName = dialog.getNameText();
- if (newName.length() == 0) {
- dialog.setStatusText("Please enter a name");
- return;
- }
- else if (folder == null) {
- dialog.setStatusText("Please select a folder");
- return;
- }
-
- DomainFile file = folder.getFile(newName);
- if (file != null && file.isReadOnly()) {
- dialog.setStatusText("Read Only. Choose new name/folder");
- }
- else {
- dialog.close();
- treeDialogCancelled = false;
- }
- };
-
- dialog.addOkActionListener(listener);
- dialog.setHelpLocation(new HelpLocation(HelpTopics.PROGRAM, "Save_As_File"));
- return dialog;
- }
-
- private CreateDataTypeArchiveDataTreeDialog getCreateDialog() {
-
- CreateDataTypeArchiveDataTreeDialog dialog = new CreateDataTypeArchiveDataTreeDialog(null,
- "Create", CREATE, archiveFileFilter);
-
- ActionListener listener = event -> {
- DomainFolder folder = dialog.getDomainFolder();
- String newName = dialog.getNameText();
- if (newName.length() == 0) {
- dialog.setStatusText("Please enter a name");
- return;
- }
- else if (folder == null) {
- dialog.setStatusText("Please select a folder");
- return;
- }
-
- DomainFile file = folder.getFile(newName);
- if (file != null) {
- dialog.setStatusText("Choose a name that doesn't exist.");
- return;
- }
-
- if (!dialog.createNewDataTypeArchive()) {
- return;
- }
-
- // everything is OK
- dialog.close();
- treeDialogCancelled = false;
- };
-
- dialog.addOkActionListener(listener);
- dialog.setHelpLocation(
- new HelpLocation(HelpTopics.DATA_MANAGER, "New_Project_Data_Type_Archive"));
-
- return dialog;
- }
-
- public DataTypeManager getDataTypeManager(SourceArchive source) {
- List allArchives = getAllArchives();
- for (Archive archive : allArchives) {
- DataTypeManager dataTypeManager = archive.getDataTypeManager();
- UniversalID universalID = dataTypeManager.getUniversalID();
- if ((universalID != null) && universalID.equals(source.getSourceArchiveID())) {
- return dataTypeManager;
- }
- }
- return null;
- }
-
-//==================================================================================================
-// Inner Classes
-//==================================================================================================
-
- private class CreateDataTypeArchiveDataTreeDialog extends DataTreeDialog {
-
- private DataTypeArchiveDB dataTypeArchiveDB;
-
- CreateDataTypeArchiveDataTreeDialog(Component parent, String title, DataTreeDialogType type,
- DomainFileFilter filter) {
- super(parent, title, type, filter);
- }
-
- /*
- * Callback method to create the DB and to show errors if they happen.
- */
- boolean createNewDataTypeArchive() {
- dataTypeArchiveDB = null;
- DomainFolder domainFolder = getDomainFolder();
- String archiveName = getNameText();
- try {
- // try to create the archive to make sure we don't get any exceptions
- dataTypeArchiveDB = new DataTypeArchiveDB(domainFolder, archiveName, tool);
- 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;
- }
-
- DataTypeArchiveDB getNewDataTypeArchiveDB() {
- return dataTypeArchiveDB;
- }
- }
-
- static class DomainFileSaveTask extends Task {
-
- private String domainObjectType;
- private DomainFile domainFile;
- private PluginTool pluginTool;
-
- DomainFileSaveTask(String domainObjectType, DomainFile df, PluginTool tool) {
- super("Save " + domainObjectType, true, true, true);
- this.domainObjectType = domainObjectType;
- this.domainFile = df;
- this.pluginTool = tool;
- }
-
- @Override
- public void run(TaskMonitor monitor) {
- monitor.setMessage("Saving " + domainObjectType + "...");
- try {
- domainFile.save(monitor);
- }
- catch (CancelledException e) {
- // O.K., expected
- }
- catch (NotConnectedException e) {
- ClientUtil.promptForReconnect(pluginTool.getProject().getRepository(),
- pluginTool.getToolFrame());
- }
- catch (ConnectException e) {
- ClientUtil.promptForReconnect(pluginTool.getProject().getRepository(),
- pluginTool.getToolFrame());
- }
- catch (IOException e) {
- ClientUtil.handleException(pluginTool.getProject().getRepository(), e, "Save File",
- pluginTool.getToolFrame());
- }
- }
- }
-
- static class DomainObjectSaveAsTask extends Task {
-
- private String domainObjectType;
- private DomainObject domainObject;
- private DomainFolder parentFolder;
- private String newName;
- private boolean doOverwrite;
-
- DomainObjectSaveAsTask(String domainObjectType, DomainObject domainObject,
- DomainFolder folder, String newName, boolean doOverwrite) {
-
- super("Save " + domainObjectType + " As", true, true, true);
- this.domainObjectType = domainObjectType;
- this.domainObject = domainObject;
- this.parentFolder = folder;
- this.newName = newName;
- this.doOverwrite = doOverwrite;
- }
-
- @Override
- public void run(TaskMonitor monitor) {
- monitor.setMessage("Saving " + domainObjectType + "...");
- try {
- if (doOverwrite) {
- DomainFile df = parentFolder.getFile(newName);
- df.delete();
- }
- parentFolder.createFile(newName, domainObject, monitor);
- }
- catch (IOException e) {
- Msg.showError(this, null, "Error Overwriting " + domainObjectType, e.getMessage(),
- e);
- }
- catch (InvalidNameException e) {
- Msg.showError(this, null, "Invalid Name", e.getMessage(), e);
- }
- catch (Throwable e) {
- Msg.showError(this, null, "Error", e.getMessage(), e);
- }
- }
- }
-
- private class MyFolderListener extends DomainFolderListenerAdapter {
-
- @Override
- public void domainFileStatusChanged(DomainFile file, boolean fileIDset) {
- if (!DataTypeArchiveContentHandler.DATA_TYPE_ARCHIVE_CONTENT_TYPE
- .equals(file.getContentType())) {
- return;
- }
- for (Archive archive : openArchives) {
- if (archive instanceof ProjectArchive) {
- ProjectArchive projectArchive = (ProjectArchive) archive;
- DomainFile domainFile = projectArchive.getDomainFile();
- if (file.equals(domainFile) && !projectArchive.isModifiable() &&
- file.isCheckedOut()) {
- replaceArchiveWithFile(projectArchive, file);
- return;
- }
- }
- }
- }
-
- @Override
- public void domainFileRemoved(DomainFolder parentFolder, String name, String fileID) {
- // ignore
- }
-
- @Override
- public void domainFileRenamed(DomainFile file, String oldName) {
- if (!DataTypeArchiveContentHandler.DATA_TYPE_ARCHIVE_CONTENT_TYPE
- .equals(file.getContentType())) {
- return;
- }
- String newName = file.getName();
- String fileID = file.getFileID();
- for (Archive archive : openArchives) {
- if (!archive.isModifiable()) {
- continue;
- }
- DataTypeManager dataTypeManager = archive.getDataTypeManager();
- updateSourceArchiveName(dataTypeManager, fileID, newName);
- }
- }
-
- private void replaceArchiveWithFile(ProjectArchive projectArchive,
- DomainFile newDomainFile) {
- DomainFile archiveDomainFile = projectArchive.getDomainFile();
- DomainObject archiveDomainObject = projectArchive.getDomainObject();
- DomainFile objectDomainFile = archiveDomainObject.getDomainFile();
- if (archiveDomainFile == objectDomainFile) {
- return;
- }
-
- closeArchive(projectArchive);
-
- String contentType = null;
- try {
- contentType = newDomainFile.getContentType();
- try {
- openArchive(newDomainFile, false, false, TaskMonitor.DUMMY);
- }
- catch (VersionException e) {
- // should never happen following check-in (i.e., DomainObjectReplaced)
- if (VersionExceptionHandler.isUpgradeOK(null, newDomainFile, "Re-open", e)) {
- openArchive(newDomainFile, true, false, TaskMonitor.DUMMY);
- }
- }
- }
- catch (VersionException e) {
- VersionExceptionHandler.showVersionError(null, newDomainFile.getName(), contentType,
- "Re-open", false, e);
- }
- catch (CancelledException e) {
- throw new AssertException(e);
- }
- catch (Exception e) {
- if (newDomainFile.isInWritableProject() && (e instanceof IOException)) {
- RepositoryAdapter repo =
- newDomainFile.getParent().getProjectData().getRepository();
- ClientUtil.handleException(repo, e, "Re-open File", null);
- }
- else {
- Msg.showError(this, null, "Error Opening " + newDomainFile.getName(),
- "Opening data type archive failed.\n" + e.getMessage());
- }
- }
- }
- }
-
- //==================================================================================================
- // Static Methods
- //==================================================================================================
-
- /**
- * Provides an exception handler for a failed attempt to open an datatype archive file.
- * This method will display exception information to the user and/or log.
- * @param plugin datatype manager plugin
- * @param archiveFile archive file resource being opened
- * @param t throwable
- */
- public static void handleArchiveFileException(DataTypeManagerPlugin plugin,
- ResourceFile archiveFile, Throwable t) {
- if (t instanceof FileNotFoundException) {
- Msg.showError(plugin, plugin.getProvider().getComponent(), "File Not Found",
- archiveFile.getAbsolutePath() + " not found!");
- }
- else if (t instanceof IOException) {
- Throwable cause = t.getCause();
- if (cause instanceof VersionException) {
- VersionExceptionHandler.showVersionError(null, archiveFile.getName(), "Archive",
- "open", false, (VersionException) cause);
- }
- else {
- Msg.showError(plugin, plugin.getProvider().getComponent(), "Open Archive Failed",
- t.getMessage() + ": " + archiveFile.getName());
- }
- }
- else if (t instanceof DuplicateIdException) {
- DuplicateIdException dupIdExc = (DuplicateIdException) t;
- Msg.showError(plugin, plugin.getProvider().getComponent(), "Duplicate Archive ID Error",
- "Attempted to open a datatype archive with the same ID as datatype archive that is " +
- "already open. " + dupIdExc.getNewArchiveName() + " has same id as " +
- dupIdExc.getExistingArchiveName());
- }
- else {
- Msg.showError(plugin, plugin.getProvider().getComponent(), "Open Archive Failed",
- "Unexpected exception opening archive: " + archiveFile.getName(), t);
- }
- }
-
- /**
- * Create project archive path string for recently used project archive
- * @param projectName the project name
- * @param pathname the pathname used to create the final path
- * @return recently used project pathname string
- */
- public static String getProjectPathname(String projectName, String pathname) {
- if (pathname.length() < 2 || !pathname.startsWith(FileSystem.SEPARATOR)) {
- throw new IllegalArgumentException("Absolute project pathname required");
- }
- return PROJECT_NAME_DELIMETER + projectName + PROJECT_NAME_DELIMETER + pathname;
- }
-
- /**
- * Parse a recently used project pathname string
- * @param projectFilePath project pathname string
- * @return 2-element String array containing project name and pathname of project archive, or null if path is invalid
- */
- public static String[] parseProjectPathname(String projectFilePath) {
- if (projectFilePath.startsWith(PROJECT_NAME_DELIMETER)) {
- int index = projectFilePath.indexOf(PROJECT_NAME_DELIMETER, 1);
- if (index > 0) {
- String projectName = projectFilePath.substring(1, index);
- String pathname = projectFilePath.substring(index + 1);
- if (pathname.length() > 1 && pathname.startsWith(FileSystem.SEPARATOR)) {
- return new String[] { projectName, pathname };
- }
- }
- }
- return null;
- }
-
-}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DefaultDataTypeArchiveService.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DefaultDataTypeArchiveService.java
deleted file mode 100644
index e0a58b78f7..0000000000
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DefaultDataTypeArchiveService.java
+++ /dev/null
@@ -1,236 +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.io.File;
-import java.io.IOException;
-import java.util.*;
-import java.util.stream.Collectors;
-
-import generic.jar.ResourceFile;
-import ghidra.app.plugin.core.datamgr.util.DataTypeArchiveUtility;
-import ghidra.app.services.DataTypeArchiveService;
-import ghidra.framework.model.DomainFile;
-import ghidra.framework.model.DomainObject;
-import ghidra.program.database.data.ProgramDataTypeManager;
-import ghidra.program.model.data.*;
-import ghidra.program.model.listing.DataTypeArchive;
-import ghidra.util.Msg;
-import ghidra.util.UniversalID;
-import ghidra.util.exception.CancelledException;
-import ghidra.util.exception.VersionException;
-import ghidra.util.task.TaskMonitor;
-
-/**
- * Simple, non-ui implementation of the {@link DataTypeArchiveService} interface.
- */
-public class DefaultDataTypeArchiveService implements DataTypeArchiveService {
- protected record DataTypeManagerInfo(ResourceFile file, DomainObject domainObject, String name,
- DataTypeManager dtm) {
- public boolean isClosed() {
- return dtm instanceof FileDataTypeManager fdtm
- ? fdtm.isClosed()
- : false;
- }
- }
-
- protected Map openDTMs = new HashMap<>();
- protected BuiltInDataTypeManager builtInDataTypesManager;
-
- public DefaultDataTypeArchiveService() {
- this.builtInDataTypesManager = BuiltInDataTypeManager.getDataTypeManager();
- }
-
- public synchronized void dispose() {
- for (DataTypeManagerInfo dtmInfo : new ArrayList<>(openDTMs.values())) {
- closeDTM(dtmInfo); // mutates openDTMs map
- }
- }
-
- @Override
- public DataTypeManager getBuiltInDataTypesManager() {
- return builtInDataTypesManager;
- }
-
- @Override
- public DataTypeManager[] getDataTypeManagers() {
- List dtmList = openDTMs.values()
- .stream()
- .filter(dtmInfo -> !dtmInfo.isClosed())
- .map(dtmInfo -> dtmInfo.dtm())
- .collect(Collectors.toList());
- return dtmList.toArray(DataTypeManager[]::new);
- }
-
- @Override
- public synchronized void closeArchive(DataTypeManager dtm) {
- if (dtm instanceof BuiltInDataTypeManager) {
- Msg.info(this, "Cannot close the built-in Data Type Manager");
- return;
- }
-
- if (dtm instanceof ProgramDataTypeManager) {
- Msg.info(this, "Cannot close the Program's Data Type Manager");
- return;
- }
-
- DataTypeManagerInfo dtmInfo = openDTMs.get(dtm.getUniversalID());
- if (dtmInfo == null) {
- Msg.info(this, "Unable close archive; archive not open: '%s'".formatted(dtm.getName()));
- return;
- }
-
- beforeCloseDataTypeManager(dtmInfo);
- openDTMs.remove(dtm.getUniversalID());
-
- if (dtmInfo.domainObject != null) {
- dtmInfo.domainObject.release(this);
- }
- dtmInfo.dtm.close();
-
- afterCloseDataTypeManager(dtmInfo);
- }
-
- @Override
- public Archive openArchive(DataTypeArchive dataTypeArchive) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Archive openArchive(File file, boolean acquireWriteLock)
- throws IOException, DuplicateIdException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public DataTypeManager openDataTypeArchive(String archiveName)
- throws IOException, DuplicateIdException {
- ResourceFile file = DataTypeArchiveUtility.findArchiveFile(archiveName);
- if (file != null) {
- return openArchive(file, false);
- }
- return null;
- }
-
- @Override
- public synchronized DataTypeManager openArchive(DomainFile domainFile, TaskMonitor monitor)
- throws VersionException, CancelledException, IOException, DuplicateIdException {
-
- if (!DataTypeArchive.class.isAssignableFrom(domainFile.getDomainObjectClass())) {
- throw new IOException("Unable to open domain file: '%s', not a data type archive"
- .formatted(domainFile.getName()));
- }
-
- DataTypeManagerInfo dtmInfo = getOpenDTMInfo(domainFile);
- if (dtmInfo == null) {
- DataTypeArchive dta = openDomainFile(domainFile, monitor);
- DataTypeManager dtm = dta.getDataTypeManager();
- dtmInfo = addDTM(new DataTypeManagerInfo(null, dta, domainFile.getPathname(), dtm));
- }
-
- return dtmInfo.dtm;
- }
-
- protected DataTypeArchive openDomainFile(DomainFile domainFile, TaskMonitor monitor)
- throws VersionException, CancelledException, IOException {
- DataTypeArchive dta =
- (DataTypeArchive) domainFile.getDomainObject(this, false, false, monitor);
- return dta;
- }
-
- @Override
- public synchronized DataTypeManager openArchive(ResourceFile file, boolean acquireWriteLock)
- throws IOException, DuplicateIdException {
-
- file = file.getCanonicalFile();
- DataTypeManagerInfo dtmInfo = getOpenDTMInfo(file);
- if (dtmInfo == null) {
- FileDataTypeManager fileDTM =
- FileDataTypeManager.openFileArchive(file, acquireWriteLock);
-
- dtmInfo = addDTM(new DataTypeManagerInfo(file, null, file.getName(), fileDTM));
- }
- return dtmInfo.dtm;
- }
-
- protected DataTypeManagerInfo addDTM(DataTypeManagerInfo dtmInfo) throws DuplicateIdException {
- DataTypeManagerInfo existingDTM = openDTMs.get(dtmInfo.dtm.getUniversalID());
- if (existingDTM != null) {
- if (existingDTM.isClosed()) {
- openDTMs.remove(dtmInfo.dtm.getUniversalID());
- }
- else {
- dtmInfo.dtm.close();
- throw new DuplicateIdException(dtmInfo.name(), existingDTM.name());
- }
- }
- openDTMs.put(dtmInfo.dtm.getUniversalID(), dtmInfo);
- afterAddDataTypeManager(dtmInfo);
- return dtmInfo;
- }
-
- protected void closeDTM(DataTypeManagerInfo dtmInfo) {
- beforeCloseDataTypeManager(dtmInfo);
- openDTMs.remove(dtmInfo.dtm.getUniversalID());
-
- if (dtmInfo.domainObject != null) {
- dtmInfo.domainObject.release(this);
- }
- dtmInfo.dtm.close();
-
- afterCloseDataTypeManager(dtmInfo);
- }
-
- private DataTypeManagerInfo getOpenDTMInfo(ResourceFile file) {
- for (DataTypeManagerInfo dtmInfo : openDTMs.values()) {
- if (dtmInfo.file != null && dtmInfo.file.equals(file)) {
- if (dtmInfo.isClosed()) {
- openDTMs.remove(dtmInfo.dtm.getUniversalID());
- return null;
- }
- return dtmInfo;
- }
- }
- return null;
- }
-
- private DataTypeManagerInfo getOpenDTMInfo(DomainFile projectFile) {
- for (DataTypeManagerInfo dtmInfo : openDTMs.values()) {
- if (dtmInfo.domainObject != null &&
- dtmInfo.domainObject.getDomainFile().equals(projectFile)) {
- if (dtmInfo.isClosed()) {
- openDTMs.remove(dtmInfo.dtm.getUniversalID());
- return null;
- }
- return dtmInfo;
- }
- }
- return null;
- }
-
- protected void afterAddDataTypeManager(DataTypeManagerInfo dtmInfo) {
- // override as needed
- }
-
- protected void afterCloseDataTypeManager(DataTypeManagerInfo dtmInfo) {
- // override as needed
- }
-
- protected void beforeCloseDataTypeManager(DataTypeManagerInfo dtmInfo) {
- // override as needed
- }
-
-}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/FileArchive.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/FileArchive.java
deleted file mode 100644
index 8ea1db5e57..0000000000
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/FileArchive.java
+++ /dev/null
@@ -1,330 +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.File;
-import java.io.IOException;
-import java.util.Objects;
-
-import javax.swing.Icon;
-
-import generic.jar.ResourceFile;
-import generic.theme.GIcon;
-import ghidra.framework.store.LockException;
-import ghidra.program.model.data.*;
-import ghidra.util.exception.DuplicateFileException;
-
-/**
- * Manages a DataTypeFileManager and relative state. For example, whether the manager is writable
- * or whether changes have been made.
- */
-public class FileArchive implements Archive {
-
- private static Icon CLOSED_ICON = new GIcon("icon.plugin.datatypes.archive.file.closed");
- private static Icon OPEN_ICON = new GIcon("icon.plugin.datatypes.archive.file.open");
- private ResourceFile archiveFile;
- private boolean hasWriteLock;
- private boolean changed;
- private DataTypeManagerHandler archiveManager;
- private FileDataTypeManager fileDataTypeManager;
- DataTypeManagerChangeListener categoryListener; // hold on to since it is stored in a weak set
- private String name;
-
- FileArchive(DataTypeManagerHandler archiveManager, File file) throws IOException {
- this(archiveManager, FileDataTypeManager.createFileArchive(file));
- archiveFile = new ResourceFile(file.getCanonicalFile());
- hasWriteLock = true;
- }
-
- FileArchive(DataTypeManagerHandler archiveManager, ResourceFile file, boolean acquireWriteLock)
- throws IOException {
- this(archiveManager, FileDataTypeManager.openFileArchive(file, acquireWriteLock));
- this.archiveFile = file.getCanonicalFile();
- this.hasWriteLock = acquireWriteLock;
- }
-
- private FileArchive(DataTypeManagerHandler archiveManager, FileDataTypeManager manager) {
- this.archiveManager = archiveManager;
- this.fileDataTypeManager = manager;
- categoryListener = new ArchiveCategoryChangeListener();
- manager.addDataTypeManagerListener(categoryListener);
- name = fileDataTypeManager.getName();
- changed = fileDataTypeManager.isChanged(); // may have immediately changed due to upgrade
- }
-
- @Override
- public String getName() {
- return name;
- }
-
- @Override
- public int compareTo(Archive archive) {
- if ((archive instanceof BuiltInArchive) || (archive instanceof ProgramArchive) ||
- (archive instanceof ProjectArchive)) {
- return 1;
- }
- if (archive instanceof FileArchive) {
- return getName().compareToIgnoreCase(archive.getName());
- }
- return -1; // File Archives appear between ProjectArchives and InvalidFileArchives.
- }
-
- @Override
- public void close() {
- fileDataTypeManager.removeDataTypeManagerListener(categoryListener);
- fileDataTypeManager.close();
- archiveManager.archiveClosed(this);
- fileDataTypeManager = null;
- }
-
- public void delete() throws IOException {
- fileDataTypeManager.removeDataTypeManagerListener(categoryListener);
- fileDataTypeManager.delete();
- archiveManager.archiveClosed(this);
- fileDataTypeManager = null;
- }
-
- public void acquireWriteLock() throws LockException, IOException {
- refreshArchive(true);
- hasWriteLock = true;
- fireStateChanged();
- }
-
- public void releaseWriteLock() throws IOException {
- try {
- refreshArchive(false);
- }
- catch (LockException e) {
- // we know this can't happen, since we are already have the write lock
- }
- hasWriteLock = false;
- setChanged(false);
- }
-
- public void saveAs(File file) throws DuplicateFileException, IOException {
- File newFile = FileDataTypeManager.convertFilename(file);
- fileDataTypeManager.saveAs(newFile);
- archiveFile = new ResourceFile(newFile);
- hasWriteLock = true;
- setChanged(false);
- }
-
- @Override
- public void save() throws IOException {
- fileDataTypeManager.save();
- setChanged(false);
- }
-
- public ResourceFile getFile() {
- return archiveFile;
- }
-
- public boolean hasWriteLock() {
- return hasWriteLock;
- }
-
- @Override
- public boolean isChanged() {
- if (isClosed()) {
- return false;
- }
- return changed || fileDataTypeManager.isChanged();
- }
-
- @Override
- public FileDataTypeManager getDataTypeManager() {
- return fileDataTypeManager;
- }
-
- boolean isClosed() {
- return fileDataTypeManager == null;
- }
-
- @Override
- public boolean isSavable() {
- return (archiveFile != null);
- }
-
- @Override
- public boolean isModifiable() {
- return hasWriteLock();
- }
-
- public DataTypeManagerHandler getArchiveManager() {
- return archiveManager;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(archiveFile);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- FileArchive other = (FileArchive) obj;
- return Objects.equals(archiveFile, other.archiveFile);
- }
-
- private void fireStateChanged() {
- archiveManager.fireArchiveStateChanged(this);
- }
-
- /**
- * Re-read the archive file.
- * @param forUpdate true indicates to open the database for update, false for read-only.
- * @throws LockException if the open if for update and a lock could not
- * be obtained
- * @throws IOException if the archive file can't be opened
- */
- private void refreshArchive(boolean forUpdate) throws LockException, IOException {
-
- // re-read archive file if it isn't null
- if (archiveFile != null) {
- FileDataTypeManager newManager =
- FileDataTypeManager.openFileArchive(archiveFile, forUpdate);
-
- FileDataTypeManager oldManager = fileDataTypeManager;
- oldManager.removeDataTypeManagerListener(categoryListener);
- oldManager.close();
-
- fileDataTypeManager = newManager;
- fileDataTypeManager.addDataTypeManagerListener(categoryListener);
-
- archiveManager.dataTypeManagerChanged(this, oldManager, newManager);
- }
- }
-
- private void setChanged(boolean change) {
- if (changed == change) {
- return;
- }
- changed = change;
- fireStateChanged();
- }
-
- class ArchiveCategoryChangeListener implements DataTypeManagerChangeListener {
- @Override
- public void categoryAdded(DataTypeManager dtm, CategoryPath path) {
- setChanged(true);
- }
-
- @Override
- public void categoryMoved(DataTypeManager dtm, CategoryPath oldPath, CategoryPath newPath) {
- setChanged(true);
- }
-
- @Override
- public void categoryRemoved(DataTypeManager dtm, CategoryPath path) {
- setChanged(true);
- }
-
- @Override
- public void categoryRenamed(DataTypeManager dtm, CategoryPath oldPath,
- CategoryPath newPath) {
- if (!oldPath.equals(newPath)) {
- setChanged(true);
- }
- }
-
- @Override
- public void dataTypeAdded(DataTypeManager dtm, DataTypePath path) {
- setChanged(true);
- }
-
- @Override
- public void dataTypeChanged(DataTypeManager dtm, DataTypePath path) {
- setChanged(true);
- }
-
- @Override
- public void dataTypeMoved(DataTypeManager dtm, DataTypePath oldPath, DataTypePath newPath) {
- setChanged(true);
- }
-
- @Override
- public void dataTypeRemoved(DataTypeManager dtm, DataTypePath path) {
- setChanged(true);
- }
-
- @Override
- public void dataTypeRenamed(DataTypeManager dtm, DataTypePath oldPath,
- DataTypePath newPath) {
- setChanged(true);
- }
-
- @Override
- public void dataTypeReplaced(DataTypeManager dtm, DataTypePath oldPath,
- DataTypePath newPath, DataType newDataType) {
- setChanged(true);
- }
-
- @Override
- public void favoritesChanged(DataTypeManager dtm, DataTypePath path, boolean isFavorite) {
- // don't care
- }
-
- @Override
- public void sourceArchiveAdded(DataTypeManager dtm, SourceArchive dataTypeSource) {
- setChanged(true);
- }
-
- @Override
- public void sourceArchiveChanged(DataTypeManager dtm, SourceArchive dataTypeSource) {
- setChanged(true);
- }
-
- @Override
- public void programArchitectureChanged(DataTypeManager dataTypeManager) {
- setChanged(true);
- }
-
- @Override
- public void restored(DataTypeManager dataTypeManager) {
- archiveManager.dataTypeManagerChanged(FileArchive.this, dataTypeManager,
- dataTypeManager);
- }
- }
-
- @Override
- public void saveAs(Component component) throws IOException {
- File saveAsFile = ArchiveUtils.getFile(component, this);
- if (saveAsFile == null) {
- return;
- }
-
- if (saveAsFile.equals(archiveFile.getFile(false))) {
- save();
- }
- else {
- saveAs(saveAsFile);
- }
- }
-
- @Override
- public Icon getIcon(boolean expanded) {
- return expanded ? OPEN_ICON : CLOSED_ICON;
- }
-}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DomainFileArchive.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/InvalidArchive.java
similarity index 62%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DomainFileArchive.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/InvalidArchive.java
index 2660379a8a..2f9ae893bf 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DomainFileArchive.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/InvalidArchive.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -15,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();
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/InvalidFileArchive.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/InvalidFileArchive.java
deleted file mode 100644
index 526fc35932..0000000000
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/InvalidFileArchive.java
+++ /dev/null
@@ -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;
- }
-}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ProgramArchive.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ProgramArchive.java
deleted file mode 100644
index bbfbd94ee4..0000000000
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ProgramArchive.java
+++ /dev/null
@@ -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;
- }
-}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ProjectArchive.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ProjectArchive.java
deleted file mode 100644
index 3cb1adda5f..0000000000
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ProjectArchive.java
+++ /dev/null
@@ -1,231 +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.framework.model.DomainFile;
-import ghidra.program.model.data.*;
-import ghidra.program.model.listing.DataTypeArchive;
-import ghidra.util.exception.ClosedException;
-
-public class ProjectArchive implements DomainFileArchive {
-
- private static Icon CLOSED_ICON = new GIcon("icon.plugin.datatypes.archive.project.closed");
- private static Icon OPEN_ICON = new GIcon("icon.plugin.datatypes.archive.project.open");
-
- private DataTypeArchive dataTypeArchive;
- private DomainFile sourceDomainFile;
- private DataTypeManagerChangeListener categoryListener; // hold on to since it is stored in a weak set
- private DataTypeManagerHandler archiveManager;
- private StandAloneDataTypeManager dataTypeManager;
-
- ProjectArchive(DataTypeManagerHandler archiveManager, DataTypeArchive dataTypeArchive,
- DomainFile sourceDomainFile) {
- this.archiveManager = archiveManager;
- this.dataTypeArchive = dataTypeArchive;
- this.dataTypeManager = dataTypeArchive.getDataTypeManager();
- this.sourceDomainFile = sourceDomainFile;
- categoryListener = new ArchiveCategoryChangeListener();
- dataTypeManager.addDataTypeManagerListener(categoryListener);
- }
-
- @Override
- public DataTypeManager getDataTypeManager() {
- return dataTypeManager;
- }
-
- @Override
- public String getName() {
- if (dataTypeManager == null) {
- return null;
- }
- return dataTypeManager.getName();
- }
-
- @Override
- public int compareTo(Archive archive) {
- if ((archive instanceof BuiltInArchive) || (archive instanceof ProgramArchive)) {
- return 1;
- }
- if (archive instanceof ProjectArchive) {
- return getName().compareToIgnoreCase(archive.getName());
- }
- return -1; // Project Archives appear between the ProgramArchive and FileArchives.
- }
-
- @Override
- public boolean hasExclusiveAccess() {
- return dataTypeArchive.hasExclusiveAccess();
- }
-
- @Override
- public boolean isModifiable() {
- if (dataTypeManager == null) {
- return false;
- }
- DomainFile df = getDomainObject().getDomainFile();
- return df.canSave();
- }
-
- @Override
- public DomainFile getDomainFile() {
- return sourceDomainFile;
- }
-
- @Override
- public DataTypeArchive getDomainObject() {
- return dataTypeArchive;
- }
-
- @Override
- public boolean isChanged() {
- if (dataTypeManager == null) {
- return false;
- }
- DomainFile df = dataTypeArchive.getDomainFile();
- long lastModifiedTime = df.getLastModifiedTime();
- return (lastModifiedTime == 0) || dataTypeArchive.isChanged();
- }
-
- @Override
- public boolean isSavable() {
- return dataTypeManager != null && !dataTypeArchive.getDomainFile().isReadOnly() &&
- dataTypeArchive.isChangeable();
- }
-
- @Override
- public void save() throws IOException {
- if (dataTypeManager == null) {
- throw new ClosedException();
- }
- archiveManager.save(getDomainObject());
- }
-
- @Override
- public void close() {
- if (dataTypeManager != null) {
- dataTypeManager.close();
- archiveManager.archiveClosed(this);
- dataTypeManager = null;
- }
- }
-
- @Override
- public void saveAs(Component component) throws IOException {
- if (dataTypeManager == null) {
- throw new ClosedException();
- }
- archiveManager.saveAs(dataTypeArchive);
- sourceDomainFile = dataTypeArchive.getDomainFile(); // update with new domain file
- dataTypeManager.updateID();
- }
-
- @Override
- public Icon getIcon(boolean expanded) {
- return expanded ? OPEN_ICON : CLOSED_ICON;
- }
-
- private void fireStateChanged() {
- archiveManager.fireArchiveStateChanged(this);
- }
-
- class ArchiveCategoryChangeListener implements DataTypeManagerChangeListener {
- @Override
- public void categoryAdded(DataTypeManager dtm, CategoryPath path) {
- fireStateChanged();
- }
-
- @Override
- public void categoryMoved(DataTypeManager dtm, CategoryPath oldPath, CategoryPath newPath) {
- fireStateChanged();
- }
-
- @Override
- public void categoryRemoved(DataTypeManager dtm, CategoryPath path) {
- fireStateChanged();
- }
-
- @Override
- public void categoryRenamed(DataTypeManager dtm, CategoryPath oldPath,
- CategoryPath newPath) {
- if (!oldPath.equals(newPath)) {
- fireStateChanged();
- }
- }
-
- @Override
- public void dataTypeAdded(DataTypeManager dtm, DataTypePath path) {
- fireStateChanged();
- }
-
- @Override
- public void dataTypeChanged(DataTypeManager dtm, DataTypePath path) {
- fireStateChanged();
- }
-
- @Override
- public void dataTypeMoved(DataTypeManager dtm, DataTypePath oldPath, DataTypePath newPath) {
- fireStateChanged();
- }
-
- @Override
- public void dataTypeRemoved(DataTypeManager dtm, DataTypePath path) {
- fireStateChanged();
- }
-
- @Override
- public void dataTypeRenamed(DataTypeManager dtm, DataTypePath oldPath,
- DataTypePath newPath) {
- fireStateChanged();
- }
-
- @Override
- public void dataTypeReplaced(DataTypeManager dtm, DataTypePath oldPath,
- DataTypePath newPath, DataType newDataType) {
- fireStateChanged();
- }
-
- @Override
- public void favoritesChanged(DataTypeManager dtm, DataTypePath path, boolean isFavorite) {
- // don't care
- }
-
- @Override
- public void sourceArchiveAdded(DataTypeManager dtm, SourceArchive dataTypeSource) {
- fireStateChanged();
- }
-
- @Override
- public void sourceArchiveChanged(DataTypeManager dtm, SourceArchive dataTypeSource) {
- fireStateChanged();
- }
-
- @Override
- public void programArchitectureChanged(DataTypeManager dtm) {
- fireStateChanged();
- }
-
- @Override
- public void restored(DataTypeManager dtm) {
- fireStateChanged();
- }
- }
-}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/editor/DataTypeEditorManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/editor/DataTypeEditorManager.java
index 6fa0f74901..532bfcbba4 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/editor/DataTypeEditorManager.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/editor/DataTypeEditorManager.java
@@ -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();
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/framework/main/datatree/ArchiveProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ArchiveComparator.java
similarity index 55%
rename from Ghidra/Features/Base/src/main/java/ghidra/framework/main/datatree/ArchiveProvider.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ArchiveComparator.java
index 28dea35b52..de7c452faf 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/framework/main/datatree/ArchiveProvider.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ArchiveComparator.java
@@ -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 {
+
+ @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 getArchives();
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ArchiveNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ArchiveNode.java
index 7858666e85..2074df0a62 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ArchiveNode.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ArchiveNode.java
@@ -15,53 +15,34 @@
*/
package ghidra.app.plugin.core.datamgr.tree;
-import java.util.List;
-
-import javax.swing.Icon;
-
-import docking.widgets.tree.GTree;
-import docking.widgets.tree.GTreeNode;
import generic.theme.GColor;
import generic.theme.GThemeDefaults.Colors.Messages;
-import ghidra.app.plugin.core.datamgr.archive.Archive;
-import ghidra.program.model.data.*;
-import ghidra.program.model.data.StandAloneDataTypeManager.ArchiveWarning;
-import ghidra.program.model.data.StandAloneDataTypeManager.ArchiveWarningLevel;
+import ghidra.program.model.dtarchive.ArchiveWarning;
+import ghidra.program.model.dtarchive.ArchiveWarning.ArchiveWarningLevel;
+import ghidra.program.model.dtarchive.PersistentDataTypeArchive;
import ghidra.util.HTMLUtilities;
-import ghidra.util.task.SwingUpdateManager;
-public class ArchiveNode extends CategoryNode {
+/**
+ * Nodes that represent a file or project datatype archive
+ */
+public class ArchiveNode extends DataTypeStoreNode {
- protected static final String DEFAULT_DATA_ORG_DESCRIPTION =
- "[Using Default Data Organization]";
+ protected PersistentDataTypeArchive archive;
- protected Archive archive;
- protected ArchiveNodeCategoryChangeListener listener;
- private DataTypeManager dataTypeManager; // may be null
-
- public ArchiveNode(Archive archive, DtFilterState filterState) {
- this(archive, archive.getDataTypeManager() == null ? null
- : archive.getDataTypeManager().getRootCategory(),
- filterState);
- this.dataTypeManager = archive.getDataTypeManager();
- updateDataTypeManager();
- }
-
- protected ArchiveNode(Archive archive, Category rootCategory,
- DtFilterState filterState) {
- super(rootCategory, filterState);
+ protected ArchiveNode(PersistentDataTypeArchive archive, DtFilterState filterState) {
+ super(archive, filterState);
this.archive = archive;
}
- protected String buildTooltip(String path) {
- DataTypeManager dtm = archive.getDataTypeManager();
- if (dtm == null) {
- return null;
- }
- StringBuilder buf = new StringBuilder(HTMLUtilities.HTML);
- buf.append(HTMLUtilities.escapeHTML(path));
- buf.append(HTMLUtilities.BR);
- String programArchSummary = dtm.getProgramArchitectureSummary();
+ public PersistentDataTypeArchive getArchive() {
+ return archive;
+ }
+
+ protected String getArchitectureDetails() {
+
+ StringBuilder buf = new StringBuilder();
+
+ String programArchSummary = dataTypeStore.getProgramArchitectureSummary();
if (programArchSummary != null) {
buf.append(HTMLUtilities.HTML_SPACE);
buf.append(HTMLUtilities.HTML_SPACE);
@@ -70,463 +51,22 @@ public class ArchiveNode extends CategoryNode {
else {
buf.append(DEFAULT_DATA_ORG_DESCRIPTION);
}
- addArchiveWarnings(dtm, buf);
+
+ ArchiveWarning warning = archive.getWarning();
+ if (warning != ArchiveWarning.NONE) {
+ GColor c = Messages.NORMAL;
+ ArchiveWarningLevel level = warning.level();
+ if (level == ArchiveWarningLevel.ERROR) {
+ c = Messages.ERROR;
+ }
+ else if (level == ArchiveWarningLevel.WARN) {
+ c = Messages.WARNING;
+ }
+ String msg = archive.getWarningMessage(false);
+ buf.append(HTMLUtilities.BR);
+ buf.append("** " + msg + " **");
+ }
return buf.toString();
}
- private void addArchiveWarnings(DataTypeManager dtm, StringBuilder buf) {
- if (dtm instanceof StandAloneDataTypeManager archiveDtm) {
- ArchiveWarning warning = archiveDtm.getWarning();
- if (warning != ArchiveWarning.NONE) {
- GColor c = Messages.NORMAL;
- ArchiveWarningLevel level = warning.level();
- if (level == ArchiveWarningLevel.ERROR) {
- c = Messages.ERROR;
- }
- else if (level == ArchiveWarningLevel.WARN) {
- c = Messages.WARNING;
- }
- String msg = archiveDtm.getWarningMessage(false);
- buf.append(HTMLUtilities.BR);
- buf.append("** " + msg + " **");
- }
- }
- }
-
- protected void archiveStateChanged() {
- nodeChanged();
- }
-
- protected void dataTypeManagerChanged() {
- updateDataTypeManager();
-
- // old children are no longer valid--clear the cache and fire a node structure changed event
- structureChanged(); // notify children have been refreshed; tree cache needs to be cleared
- nodeChanged(); // notify that this nodes display data has changed
- }
-
- protected void installDataTypeManagerListener() {
- if (dataTypeManager == null) {
- return; // some nodes do not have DataTypeManagers, like InvalidFileArchives
- }
- listener = new ArchiveNodeCategoryChangeListener();
- dataTypeManager.addDataTypeManagerListener(listener);
- }
-
- protected void updateDataTypeManager() {
- if (dataTypeManager == null) {
- return; // some nodes do not have DataTypeManagers, like InvalidFileArchives
- }
-
- if (listener != null) {
- dataTypeManager.removeDataTypeManagerListener(listener);
- listener.dispose();
- }
-
- dataTypeManager = archive.getDataTypeManager();
- installDataTypeManagerListener();
- setCategory(dataTypeManager.getRootCategory());
- }
-
- @Override
- public void dispose() {
- if (dataTypeManager != null) {
- dataTypeManager.removeDataTypeManagerListener(listener);
- }
-
- if (listener != null) {
- listener.dispose();
- }
-
- super.dispose();
- }
-
- @Override
- public Icon getIcon(boolean expanded) {
- return archive.getIcon(expanded);
- }
-
- @Override
- public String getName() {
- return archive.getName();
- }
-
- @Override
- public String getToolTip() {
- return null;
- }
-
- @Override
- public boolean isLeaf() {
- return false;
- }
-
- @Override
- public boolean isEditable() {
- return false;
- }
-
- public Archive getArchive() {
- return archive;
- }
-
- public void structureChanged() {
- setChildren(null);
- }
-
- public void nodeChanged() {
- fireNodeChanged();
-
- GTree tree = getTree();
- if (tree != null) {
- tree.repaint();
- }
- }
-
- @Override
- /**
- * Overridden since you cannot cut an archive node.
- */
- public boolean canCut() {
- return false;
- }
-
- @Override
- public boolean isCut() {
- return false;
- }
-
- @Override
- /**
- * The equals must not be based on the name since it can change based upon the underlying
- * archive. This must be consistent with the hashCode method implementation.
- */
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (getClass() != o.getClass()) {
- return false;
- }
- ArchiveNode otherNode = (ArchiveNode) o;
- return getArchive().equals(otherNode.getArchive());
- }
-
- @Override
- public int compareTo(GTreeNode node) {
- if (node instanceof ArchiveNode) {
- return archive.compareTo(((ArchiveNode) node).archive);
- }
- return -1; // All ArchiveNodes are before any other types of nodes
- }
-
- /**
- * The hashcode must not be based on the name since it can change based upon the underlying
- * archive. This must be consistent with the equals method implementation.
- */
- @Override
- public int hashCode() {
- return getArchive().hashCode();
- }
-
- @Override
- public ArchiveNode getArchiveNode() {
- return this;
- }
-
- @Override
- public boolean isModifiable() {
- return archive.isModifiable();
- }
-
- /**
- * Finds the node that represents the given category.
- *
- *
- * Children will not be loaded when searching for the node. This allows clients to search
- * for data types of interest, only updating the tree when the nodes are loaded.
- *
- * @param localCategory the category of interest
- * @return the node if loaded; null if not loaded
- */
- public CategoryNode findCategoryNode(Category localCategory) {
- return findCategoryNode(localCategory, false);
- }
-
- /**
- * Finds the node that represents the given category.
- *
- * @param localCategory the category of interest
- * @param loadChildren true will load child nodes when searching; false will not load children
- * @return the node
- */
- public CategoryNode findCategoryNode(Category localCategory, boolean loadChildren) {
-
- // if we don't have to loadChildren and we are not loaded get out.
- if (!loadChildren && !isLoaded()) {
- return null;
- }
-
- if (localCategory == null) {
- return null;
- }
-
- if (getCategory() == localCategory) {
- return ArchiveNode.this;
- }
-
- Category parentCategory = localCategory.getParent();
- if (getParent() == null) {
- return null;
- }
-
- CategoryNode node = findCategoryNode(parentCategory, loadChildren);
- if (node == null) {
- return null;
- }
-
- List children = node.getChildren();
- for (GTreeNode child : children) {
- if (!(child instanceof CategoryNode)) {
- continue;
- }
-
- CategoryNode categoryNode = (CategoryNode) child;
- if (categoryNode.getCategory() == localCategory) {
- return categoryNode;
- }
- }
- return null;
- }
-
-//==================================================================================================
-// Inner Classes
-//==================================================================================================
-
- private class ArchiveNodeCategoryChangeListener implements DataTypeManagerChangeListener {
-
- private SwingUpdateManager nodeChangedUpdater = new SwingUpdateManager(() -> nodeChanged());
-
- @Override
- public void categoryAdded(DataTypeManager dtm, CategoryPath path) {
- if (!isLoaded()) {
- return;
- }
-
- Category newCategory = dtm.getCategory(path);
- if (newCategory == null) {
- return;
- }
- Category category = newCategory.getParent();
- CategoryNode categoryNode = findCategoryNode(category);
- if (categoryNode != null) {
- categoryNode.categoryAdded(newCategory);
- }
- }
-
- void dispose() {
- nodeChangedUpdater.dispose();
- }
-
- @Override
- public void categoryMoved(DataTypeManager dtm, CategoryPath oldPath, CategoryPath newPath) {
- if (!isLoaded()) {
- return;
- }
-
- Category newCategory = dtm.getCategory(newPath);
- Category oldParent = dtm.getCategory(oldPath.getParent());
- CategoryNode categoryNode = findCategoryNode(oldParent);
- if (categoryNode != null) {
- categoryNode.categoryRemoved(oldPath.getName());
- }
- categoryNode = findCategoryNode(newCategory.getParent());
- if (categoryNode != null) {
- categoryNode.categoryAdded(newCategory);
- }
- }
-
- @Override
- public void categoryRemoved(DataTypeManager dtm, CategoryPath path) {
- if (!isLoaded()) {
- return;
- }
-
- Category parentCategory = dtm.getCategory(path.getParent());
- CategoryNode categoryNode = findCategoryNode(parentCategory);
- if (categoryNode != null) {
- categoryNode.categoryRemoved(path.getName());
- }
- }
-
- @Override
- public void categoryRenamed(DataTypeManager dtm, CategoryPath oldPath,
- CategoryPath newPath) {
- if (!isLoaded()) {
- return;
- }
-
- if (oldPath.getParent() == null) { // root has no parent
- ArchiveNode.this.fireNodeChanged(); // fire that the root changed
- return;
- }
- Category parentCategory = dtm.getCategory(oldPath.getParent());
- CategoryNode categoryNode = findCategoryNode(parentCategory);
- if (categoryNode != null) {
- categoryNode.categoryRemoved(oldPath.getName());
- Category newCategory = dtm.getCategory(newPath);
- categoryNode.categoryAdded(newCategory);
- }
- }
-
- @Override
- public void dataTypeAdded(DataTypeManager dtm, DataTypePath path) {
- if (!isLoaded()) {
- return;
- }
-
- Category parentCategory = dtm.getCategory(path.getCategoryPath());
- CategoryNode categoryNode = findCategoryNode(parentCategory);
- if (categoryNode != null) {
- DataType dataType = dtm.getDataType(path);
-
- // the data type can be changed before we get this call, since it's asynchronous
- if (dataType != null) {
- categoryNode.dataTypeAdded(dataType);
- }
- }
- }
-
- @Override
- public void favoritesChanged(DataTypeManager dtm, DataTypePath path, boolean isFavorite) {
- if (!isLoaded()) {
- return;
- }
-
- DataType dataType = dtm.getDataType(path);
- Category category = dtm.getCategory(path.getCategoryPath());
- CategoryNode categoryNode = findCategoryNode(category);
- if (categoryNode == null) {
- return;
- }
- List children = categoryNode.getChildren();
- for (GTreeNode node : children) {
- if (node instanceof DataTypeNode) {
- DataTypeNode dataTypeNode = (DataTypeNode) node;
- if (dataTypeNode.getDataType() == dataType) {
- dataTypeNode.dataTypeStatusChanged();
- return;
- }
- }
- }
- }
-
- @Override
- public void dataTypeChanged(DataTypeManager dtm, DataTypePath path) {
- if (!isLoaded()) {
- return;
- }
-
- Category dtmCategory = dtm.getCategory(path.getCategoryPath());
- CategoryNode categoryNode = findCategoryNode(dtmCategory);
- if (categoryNode != null) {
- DataType dataType = dtm.getDataType(path);
-
- // the data type can be changed before we get this call, since it's asynchronous
- if (dataType != null) {
- categoryNode.dataTypeChanged(dataType);
- }
- }
- }
-
- @Override
- public void dataTypeMoved(DataTypeManager dtm, DataTypePath oldPath, DataTypePath newPath) {
- if (!isLoaded()) {
- return;
- }
-
- Category oldParent = dtm.getCategory(oldPath.getCategoryPath());
- CategoryNode categoryNode = findCategoryNode(oldParent);
- if (categoryNode != null) {
- categoryNode.dataTypeRemoved(oldPath.getDataTypeName());
- }
-
- Category newParent = dtm.getCategory(newPath.getCategoryPath());
- categoryNode = findCategoryNode(newParent);
- if (categoryNode != null) {
- DataType dataType = dtm.getDataType(newPath);
-
- // the data type can be changed before we get this call, since it's asynchronous
- if (dataType != null) {
- categoryNode.dataTypeAdded(dataType);
- }
- }
- }
-
- @Override
- public void dataTypeRemoved(DataTypeManager dtm, DataTypePath path) {
- if (!isLoaded()) {
- return;
- }
-
- Category oldParent = dtm.getCategory(path.getCategoryPath());
- CategoryNode categoryNode = findCategoryNode(oldParent);
- if (categoryNode != null) {
- categoryNode.dataTypeRemoved(path.getDataTypeName());
- }
- }
-
- @Override
- public void dataTypeRenamed(DataTypeManager dtm, DataTypePath oldPath,
- DataTypePath newPath) {
- if (!isLoaded()) {
- return;
- }
-
- Category dtmCategory = dtm.getCategory(newPath.getCategoryPath());
- CategoryNode categoryNode = findCategoryNode(dtmCategory);
- if (categoryNode != null) {
- categoryNode.dataTypeRemoved(oldPath.getDataTypeName());
- DataType dataType = dtm.getDataType(newPath);
-
- // the data type can be changed before we get this call, since it's asynchronous
- if (dataType != null) {
- categoryNode.dataTypeAdded(dataType);
- }
- }
- }
-
- @Override
- public void dataTypeReplaced(DataTypeManager dtm, DataTypePath oldPath,
- DataTypePath newPath, DataType newDataType) {
- // Note: the replacement has already been added with its own event
- dataTypeRemoved(dtm, oldPath);
- }
-
- @Override
- public void sourceArchiveAdded(DataTypeManager manager, SourceArchive sourceArchive) {
- // DT should these do anything?
- }
-
- @Override
- public void sourceArchiveChanged(DataTypeManager manager, SourceArchive sourceArchive) {
- nodeChangedUpdater.update();
- }
-
- @Override
- public void programArchitectureChanged(DataTypeManager manager) {
- // need to force all cached datatype tooltips to be cleared
- // due to change in data organization
- unloadChildren();
- nodeChangedUpdater.update();
- }
-
- @Override
- public void restored(DataTypeManager manager) {
- // need to force all cached datatype tooltips to be cleared
- // due to potential changes (e.g., undo/redo)
- unloadChildren();
- nodeChangedUpdater.update();
- }
- }
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ArchiveRootNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ArchiveRootNode.java
index 8b1e8d777a..de9b411fcd 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ArchiveRootNode.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ArchiveRootNode.java
@@ -20,16 +20,20 @@ import java.util.*;
import javax.swing.Icon;
import docking.widgets.tree.GTreeNode;
-import ghidra.app.plugin.core.datamgr.archive.*;
+import ghidra.app.plugin.core.datamgr.ArchiveManager;
+import ghidra.app.plugin.core.datamgr.ArchiveManagerListener;
+import ghidra.app.plugin.core.datamgr.archive.InvalidArchive;
import ghidra.app.plugin.core.datamgr.util.DataTypeUtils;
-import ghidra.program.model.data.Category;
-import ghidra.program.model.data.DataTypeManager;
+import ghidra.program.database.dtarchive.FileDtArchiveDB;
+import ghidra.program.model.data.*;
+import ghidra.program.model.dtarchive.*;
+import ghidra.program.model.listing.Program;
import ghidra.util.exception.AssertException;
public class ArchiveRootNode extends DataTypeTreeNode {
private static final String NAME = "Data Types";
- private DataTypeManagerHandler archiveManager;
+ private ArchiveManager archiveManager;
private RootNodeListener archiveListener;
private boolean programDtmOnly;
@@ -37,11 +41,11 @@ public class ArchiveRootNode extends DataTypeTreeNode {
private DtFilterState dtFilterState = new DtFilterState();
- public ArchiveRootNode(DataTypeManagerHandler archiveManager) {
+ public ArchiveRootNode(ArchiveManager archiveManager) {
this(archiveManager, false);
}
- public ArchiveRootNode(DataTypeManagerHandler archiveManager, boolean programDtmOnly) {
+ public ArchiveRootNode(ArchiveManager archiveManager, boolean programDtmOnly) {
this.archiveManager = archiveManager;
this.programDtmOnly = programDtmOnly;
init();
@@ -60,10 +64,6 @@ public class ArchiveRootNode extends DataTypeTreeNode {
this.listener = listener;
}
- public DataTypeManagerHandler getArchiveHandler() {
- return archiveManager;
- }
-
/**
* Returns the modification count for any changes to any category or datatype in any
* open archive including the program.
@@ -109,30 +109,20 @@ public class ArchiveRootNode extends DataTypeTreeNode {
}
// a factory method to isolate non-OO inheritance checks
- private final ArchiveNode createArchiveNode(Archive archive, DtFilterState filterState) {
+ private final ArchiveNode createArchiveNode(PersistentDataTypeArchive archive,
+ DtFilterState filterState) {
if (programDtmOnly) {
- if (archive instanceof ProgramArchive) {
- return new ProgramArchiveNode((ProgramArchive) archive, filterState);
- }
return null;
}
- if (archive instanceof FileArchive) {
- return new FileArchiveNode((FileArchive) archive, filterState);
+ if (archive instanceof FileDtArchiveDB fileArchive) {
+ return new FileArchiveNode(fileArchive, filterState);
}
- else if (archive instanceof ProjectArchive) {
- return new ProjectArchiveNode((ProjectArchive) archive, filterState);
- }
- else if (archive instanceof InvalidFileArchive) {
- return new InvalidArchiveNode((InvalidFileArchive) archive);
- }
- else if (archive instanceof ProgramArchive) {
- return new ProgramArchiveNode((ProgramArchive) archive, filterState);
- }
- else if (archive instanceof BuiltInArchive) {
- return new BuiltInArchiveNode((BuiltInArchive) archive, filterState);
+ else if (archive instanceof ProjectDataTypeArchive projectArchive) {
+ return new ProjectArchiveNode(projectArchive, filterState);
}
+
return null;
}
@@ -166,7 +156,7 @@ public class ArchiveRootNode extends DataTypeTreeNode {
* @see ghidra.app.plugin.core.datamgr.tree.DataTypeTreeNode#getArchiveNode()
*/
@Override
- public ArchiveNode getArchiveNode() {
+ public DataTypeStoreNode getArchiveNode() {
return null;
}
@@ -177,7 +167,7 @@ public class ArchiveRootNode extends DataTypeTreeNode {
public CategoryNode findCategoryNode(Category category) {
for (GTreeNode node : getChildren()) {
- ArchiveNode archiveNode = (ArchiveNode) node;
+ DataTypeStoreNode archiveNode = (DataTypeStoreNode) node;
CategoryNode categoryNode = archiveNode.findCategoryNode(category);
if (categoryNode != null) {
return categoryNode;
@@ -186,13 +176,14 @@ public class ArchiveRootNode extends DataTypeTreeNode {
return null;
}
- public ArchiveNode getNodeForManager(DataTypeManager dtm) {
+ public DataTypeStoreNode getNodeForManager(DataTypeManager dtm) {
for (GTreeNode node : getChildren()) {
- ArchiveNode archiveNode = (ArchiveNode) node;
- Archive archive = archiveNode.getArchive();
- DataTypeManager manager = archive.getDataTypeManager();
- if (manager.equals(dtm)) {
- return archiveNode;
+ if (node instanceof DataTypeStoreNode storeNode) {
+ DataTypeStore archive = storeNode.getDataTypeStore();
+ DataTypeManager manager = archive.getDataTypeManager();
+ if (manager.equals(dtm)) {
+ return storeNode;
+ }
}
}
return null;
@@ -201,22 +192,54 @@ public class ArchiveRootNode extends DataTypeTreeNode {
@Override
public List generateChildren() {
List list = new ArrayList<>();
- for (Archive element : archiveManager.getAllArchives()) {
- GTreeNode node = createArchiveNode(element, dtFilterState);
- if (node != null) {
- list.add(node);
- }
- }
+ addBuiltInNode(list);
+ addProgramNode(list);
+ addArchiveNodes(list);
+ addInvalidNodes(list);
Collections.sort(list);
return list;
}
- private ArchiveNode getArchiveNode(Archive archive) {
+ private void addBuiltInNode(List list) {
+ if (programDtmOnly) {
+ return;
+ }
+ DataTypeManager builtInDtm = BuiltInDataTypeManager.getDataTypeManager();
+ DataTypeStore dataStore = builtInDtm.getDataStore();
+ list.add(new BuiltInArchiveNode(dataStore, dtFilterState));
+ }
+
+ private void addProgramNode(List list) {
+ Program program = archiveManager.getProgram();
+ if (program != null) {
+ list.add(new ProgramArchiveNode(program, dtFilterState));
+ }
+ }
+
+ private void addArchiveNodes(List list) {
+
+ for (PersistentDataTypeArchive archive : archiveManager.getOpenArchives()) {
+ GTreeNode node = createArchiveNode(archive, dtFilterState);
+ if (node != null) {
+ list.add(node);
+ }
+ }
+ }
+
+ private void addInvalidNodes(List list) {
+ List invalidArchives = archiveManager.getInvalidArchives();
+ for (InvalidArchive invalidArchive : invalidArchives) {
+ InvalidArchiveNode node = new InvalidArchiveNode(invalidArchive);
+ list.add(node);
+ }
+ }
+
+ private DataTypeStoreNode getArchiveNode(DataTypeStore store) {
List allChildrenList = getChildren();
for (GTreeNode node : allChildrenList) {
- if (node instanceof ArchiveNode) {
- ArchiveNode archiveNode = (ArchiveNode) node;
- if (archiveNode.archive == archive) {
+ if (node instanceof DataTypeStoreNode) {
+ DataTypeStoreNode archiveNode = (DataTypeStoreNode) node;
+ if (archiveNode.dataTypeStore == store) {
return archiveNode;
}
}
@@ -229,36 +252,67 @@ public class ArchiveRootNode extends DataTypeTreeNode {
//==================================================================================================
private class RootNodeListener implements ArchiveManagerListener {
-
@Override
- public void archiveClosed(Archive archive) {
+ public void programClosed(Program program) {
if (!isLoaded()) {
return;
}
List allChildrenList = getChildren();
for (GTreeNode node : allChildrenList) {
- ArchiveNode archiveNode = (ArchiveNode) node;
- if (archive == archiveNode.getArchive()) {
- listener.archiveNodeRemoved(archiveNode);
- removeNode(archiveNode);
- archiveNode.dispose();
- return;
+ if (node instanceof ProgramArchiveNode programNode) {
+ if (program == programNode.getProgram()) {
+ listener.archiveNodeRemoved(programNode);
+ removeNode(programNode);
+ programNode.dispose();
+ return;
+ }
}
}
}
@Override
- public void archiveOpened(Archive archive) {
+ public void archiveClosed(PersistentDataTypeArchive archive) {
+ if (!isLoaded()) {
+ return;
+ }
+
+ List allChildrenList = getChildren();
+ for (GTreeNode node : allChildrenList) {
+ if (node instanceof ArchiveNode archiveNode) {
+ if (archive == archiveNode.getArchive()) {
+ listener.archiveNodeRemoved(archiveNode);
+ removeNode(archiveNode);
+ archiveNode.dispose();
+ return;
+ }
+ }
+ }
+ }
+
+ @Override
+ public void programOpened(Program program) {
+ if (!isLoaded()) {
+ return;
+ }
+ ProgramArchiveNode programNode = new ProgramArchiveNode(program, dtFilterState);
+
+ addDataStoreNode(programNode);
+ }
+
+ @Override
+ public void archiveOpened(PersistentDataTypeArchive archive) {
if (!isLoaded()) {
return;
}
ArchiveNode node = createArchiveNode(archive, dtFilterState);
- if (node == null) {
- return;
+ if (node != null) {
+ addDataStoreNode(node);
}
+ }
+ private void addDataStoreNode(DataTypeStoreNode node) {
List allChildrenList = getChildren();
int index = Collections.binarySearch(allChildrenList, node);
if (index < 0) {
@@ -270,18 +324,35 @@ public class ArchiveRootNode extends DataTypeTreeNode {
}
@Override
- public void archiveDataTypeManagerChanged(Archive archive) {
- ArchiveNode archiveNode = getArchiveNode(archive);
+ public void stateChanged(DataTypeStore dataTypeStore) {
+ DataTypeStoreNode archiveNode = getArchiveNode(dataTypeStore);
if (archiveNode != null) {
- archiveNode.dataTypeManagerChanged();
+ archiveNode.nodeChanged();
}
}
@Override
- public void archiveStateChanged(Archive archive) {
- ArchiveNode archiveNode = getArchiveNode(archive);
- if (archiveNode != null) {
- archiveNode.archiveStateChanged();
+ public void invalidArchiveAdded(InvalidArchive invalidArchive) {
+ if (!isLoaded()) {
+ return;
+ }
+ addNode(new InvalidArchiveNode(invalidArchive));
+ }
+
+ @Override
+ public void invalidArchiveRemoved(InvalidArchive invalidArchive) {
+ if (!isLoaded()) {
+ return;
+ }
+ List allChildrenList = getChildren();
+ for (GTreeNode node : allChildrenList) {
+ if (node instanceof InvalidArchiveNode invalidNode) {
+ if (invalidArchive.equals(invalidNode.getInvalidArchive())) {
+ removeNode(node);
+ invalidNode.dispose();
+ return;
+ }
+ }
}
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ArchiveRootNodeListener.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ArchiveRootNodeListener.java
index c0f9448641..5cf2d6440d 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ArchiveRootNodeListener.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ArchiveRootNodeListener.java
@@ -24,11 +24,11 @@ public interface ArchiveRootNodeListener {
* Called when a node has been added to the root node
* @param node the added node
*/
- public void archiveNodeAdded(ArchiveNode node);
+ public void archiveNodeAdded(DataTypeStoreNode node);
/**
* Called when a node is about to be removed from the root node
* @param node the node that is about to be removed
*/
- public void archiveNodeRemoved(ArchiveNode node);
+ public void archiveNodeRemoved(DataTypeStoreNode node);
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/BuiltInArchiveNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/BuiltInArchiveNode.java
index 85a120cd3b..0667efb78f 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/BuiltInArchiveNode.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/BuiltInArchiveNode.java
@@ -17,19 +17,25 @@ package ghidra.app.plugin.core.datamgr.tree;
import javax.swing.Icon;
-import ghidra.app.plugin.core.datamgr.archive.BuiltInArchive;
+import generic.theme.GIcon;
+import ghidra.program.model.dtarchive.DataTypeStore;
import ghidra.util.HTMLUtilities;
import resources.MultiIcon;
-public class BuiltInArchiveNode extends ArchiveNode {
+/**
+ * Node that represents the Built-in datatype archive.
+ */
+public class BuiltInArchiveNode extends DataTypeStoreNode {
+ 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");
- public BuiltInArchiveNode(BuiltInArchive archive, DtFilterState filterState) {
- super(archive, filterState);
+ public BuiltInArchiveNode(DataTypeStore store, DtFilterState filterState) {
+ super(store, filterState);
}
@Override
public Icon getIcon(boolean expanded) {
- Icon baseIcon = archive.getIcon(expanded);
+ Icon baseIcon = expanded ? OPEN_ICON : CLOSED_ICON;
MultiIcon multiIcon = new MultiIcon(baseIcon);
return multiIcon;
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/CategoryNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/CategoryNode.java
index 9420af33da..65852d53de 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/CategoryNode.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/CategoryNode.java
@@ -34,7 +34,7 @@ public class CategoryNode extends DataTypeTreeNode {
private boolean isCut;
private DtFilterState filterState;
- public CategoryNode(Category category, DtFilterState filterState) {
+ protected CategoryNode(Category category, DtFilterState filterState) {
this.filterState = filterState;
setCategory(category);
}
@@ -311,7 +311,7 @@ public class CategoryNode extends DataTypeTreeNode {
}
@Override
- public ArchiveNode getArchiveNode() {
+ public DataTypeStoreNode getArchiveNode() {
GTreeNode parent = getParent();
if (parent == null) {
return null; // could happen during tree mutations
@@ -322,7 +322,7 @@ public class CategoryNode extends DataTypeTreeNode {
@Override
public boolean isModifiable() {
- ArchiveNode archiveNode = getArchiveNode();
+ DataTypeStoreNode archiveNode = getArchiveNode();
if (archiveNode == null) {
return false;
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeArchiveGTree.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeArchiveGTree.java
index 433ca1b593..003186537e 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeArchiveGTree.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeArchiveGTree.java
@@ -33,10 +33,9 @@ import docking.widgets.tree.internal.DefaultGTreeDataTransformer;
import docking.widgets.tree.support.GTreeRenderer;
import generic.theme.GIcon;
import ghidra.app.plugin.core.datamgr.*;
-import ghidra.app.plugin.core.datamgr.archive.DataTypeManagerHandler;
-import ghidra.app.plugin.core.datamgr.archive.FileArchive;
import ghidra.framework.model.*;
import ghidra.framework.plugintool.PluginTool;
+import ghidra.program.database.dtarchive.FileDtArchiveDB;
import ghidra.program.model.data.*;
import ghidra.program.model.data.Composite;
import ghidra.program.model.data.Enum;
@@ -58,7 +57,7 @@ public class DataTypeArchiveGTree extends GTree {
private DataTypeTreeExpansionListener cleanupListener = new DataTypeTreeExpansionListener();
public DataTypeArchiveGTree(DataTypeManagerPlugin dataTypeManagerPlugin) {
- super(new ArchiveRootNode(dataTypeManagerPlugin.getDataTypeManagerHandler()));
+ super(new ArchiveRootNode(dataTypeManagerPlugin.getArchiveManager()));
this.plugin = dataTypeManagerPlugin;
setDragNDropHandler(new DataTypeDragNDropHandler(plugin, this));
@@ -274,13 +273,13 @@ public class DataTypeArchiveGTree extends GTree {
return null;
}
- DataTypeManagerHandler handler = plugin.getDataTypeManagerHandler();
- DataTypeSyncState status = DataTypeSynchronizer.getSyncStatus(handler, dataType);
+ ArchiveManager archiveManager = plugin.getArchiveManager();
+ DataTypeSyncState status = DataTypeSynchronizer.getSyncStatus(archiveManager, dataType);
switch (status) {
case CONFLICT:
case UPDATE:
case COMMIT:
- return DataTypeSynchronizer.getDiffToolTip(handler, dataType);
+ return DataTypeSynchronizer.getDiffToolTip(archiveManager, dataType);
case ORPHAN:
case UNKNOWN:
case IN_SYNC:
@@ -430,9 +429,8 @@ public class DataTypeArchiveGTree extends GTree {
String displayText = ((DataTypeNode) value).getDisplayText();
label.setText(displayText);
}
- else if (value instanceof DomainFileArchiveNode) {
- DomainFileArchiveNode node = (DomainFileArchiveNode) value;
- String info = node.getDomainObjectInfo();
+ else if (value instanceof VersionedNode versionedNode) {
+ String info = versionedNode.getDomainObjectInfo();
if (info.length() > 0) {
label.setText(label.getText() + info);
}
@@ -440,8 +438,8 @@ public class DataTypeArchiveGTree extends GTree {
decorateWithArchiveCharacteristics(value, label, multiIcon);
- if (value instanceof ArchiveNode) {
- updateIconForChangeIndicator((ArchiveNode) value, multiIcon);
+ if (value instanceof DataTypeStoreNode) {
+ updateIconForChangeIndicator((DataTypeStoreNode) value, multiIcon);
}
setIcon(multiIcon);
@@ -453,7 +451,7 @@ public class DataTypeArchiveGTree extends GTree {
if (value instanceof FileArchiveNode) {
FileArchiveNode archiveNode = (FileArchiveNode) value;
- FileArchive archive = (FileArchive) archiveNode.getArchive();
+ FileDtArchiveDB archive = (FileDtArchiveDB) archiveNode.getArchive();
if (archive.isChanged()) {
label.setText(label.getText() + " *");
}
@@ -473,8 +471,8 @@ public class DataTypeArchiveGTree extends GTree {
return;
}
- DataTypeManagerHandler handler = plugin.getDataTypeManagerHandler();
- DataTypeSyncState status = DataTypeSynchronizer.getSyncStatus(handler, dataType);
+ ArchiveManager archiveManager = plugin.getArchiveManager();
+ DataTypeSyncState status = DataTypeSynchronizer.getSyncStatus(archiveManager, dataType);
switch (status) {
case CONFLICT:
multiIcon.addIcon(new TranslateIcon(CONFLICT_ICON, 10, 5));
@@ -494,8 +492,8 @@ public class DataTypeArchiveGTree extends GTree {
}
}
- private void updateIconForChangeIndicator(ArchiveNode node, MultiIcon multiIcon) {
- DataTypeManager dtm = node.getArchive().getDataTypeManager();
+ private void updateIconForChangeIndicator(DataTypeStoreNode node, MultiIcon multiIcon) {
+ DataTypeManager dtm = node.getDataTypeManager();
if (dtm == null) {
return; // for InvalidArchiveNodes
}
@@ -521,7 +519,7 @@ public class DataTypeArchiveGTree extends GTree {
private boolean checkforUpdates(List sourceArchives) {
for (SourceArchive sourceArchive : sourceArchives) {
DataTypeManager sourceDTM =
- plugin.getDataTypeManagerHandler().getDataTypeManager(sourceArchive);
+ plugin.getArchiveManager().getDataTypeManager(sourceArchive);
if (sourceDTM != null &&
sourceArchive.getLastSyncTime() != sourceDTM.getLastChangeTimeForMyManager()) {
return true;
@@ -547,9 +545,8 @@ public class DataTypeArchiveGTree extends GTree {
public void domainFileStatusChanged(DomainFile file, boolean fileIDset) {
List archiveNodes = getModelRoot().getChildren();
for (GTreeNode treeNode : archiveNodes) {
- if (treeNode instanceof ProjectArchiveNode) {
- ProjectArchiveNode projectArchiveNode = (ProjectArchiveNode) treeNode;
- DomainFile nodesDomainFile = projectArchiveNode.getDomainFile();
+ if (treeNode instanceof ProjectArchiveNode projectArchiveNode) {
+ DomainFile nodesDomainFile = projectArchiveNode.getOriginalDomainFile();
if (file.equals(nodesDomainFile)) {
projectArchiveNode.nodeChanged();
return;
@@ -559,8 +556,18 @@ public class DataTypeArchiveGTree extends GTree {
}
@Override
- public void domainFileRemoved(DomainFolder parentFolder, String name, String fileID) {
- // DT What if anything needs to be done here?
+ public void domainFileObjectOpenedForUpdate(DomainFile file, DomainObject doa) {
+ // When a saveAs is performed the existing becomes associated with a new DomainFile.
+ // If this corresponds to an archive in the tree we need to invoke nodeChanged on it
+ List archiveNodes = getModelRoot().getChildren();
+ for (GTreeNode treeNode : archiveNodes) {
+ if (treeNode instanceof ProjectArchiveNode projectArchiveNode) {
+ if (projectArchiveNode.getDomainObject() == doa) {
+ projectArchiveNode.nodeChanged();
+ return;
+ }
+ }
+ }
}
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeDragNDropHandler.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeDragNDropHandler.java
index 4d76378819..a0057fbf71 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeDragNDropHandler.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeDragNDropHandler.java
@@ -27,9 +27,9 @@ import docking.widgets.tree.GTreeNode;
import docking.widgets.tree.support.GTreeDragNDropHandler;
import generic.jar.ResourceFile;
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
-import ghidra.app.plugin.core.datamgr.archive.FileArchive;
import ghidra.app.plugin.core.datamgr.util.DataTypeTreeCopyMoveTask;
import ghidra.app.plugin.core.datamgr.util.DataTypeTreeCopyMoveTask.ActionType;
+import ghidra.program.database.dtarchive.FileDtArchiveDB;
import ghidra.program.model.data.*;
import ghidra.util.Msg;
import ghidra.util.task.Task;
@@ -118,7 +118,7 @@ public class DataTypeDragNDropHandler implements GTreeDragNDropHandler {
}
// we don't support dragging archives in their entirety
- if (node instanceof ArchiveNode) {
+ if (node instanceof DataTypeStoreNode) {
return new DataFlavor[] {};
}
}
@@ -144,14 +144,14 @@ public class DataTypeDragNDropHandler implements GTreeDragNDropHandler {
return dragUserData;
}
else if (flavor.equals(DataFlavor.javaFileListFlavor)) {
- List> nodeList = dragUserData;
+ List nodeList = dragUserData;
ArrayList fileList = new ArrayList();
for (Object node : nodeList) {
-
- ArchiveNode archiveNode = (ArchiveNode) node;
- FileArchive archive = (FileArchive) archiveNode.getArchive();
- ResourceFile file = archive.getFile();
- fileList.add(file);
+ if (node instanceof FileArchiveNode fileArchiveNode) {
+ FileDtArchiveDB archive = (FileDtArchiveDB) fileArchiveNode.getArchive();
+ ResourceFile file = archive.getFile();
+ fileList.add(file);
+ }
}
return fileList;
}
@@ -199,7 +199,7 @@ public class DataTypeDragNDropHandler implements GTreeDragNDropHandler {
// destination node must belong to either a modifiable archive or a program archive.
// i.e. it must be writable.
- ArchiveNode archiveNode = ((DataTypeTreeNode) destinationNode).getArchiveNode();
+ DataTypeStoreNode archiveNode = ((DataTypeTreeNode) destinationNode).getArchiveNode();
if (archiveNode == null || !archiveNode.isModifiable()) {
return false;
}
@@ -221,7 +221,7 @@ public class DataTypeDragNDropHandler implements GTreeDragNDropHandler {
return true;
}
CategoryNode categoryNode = (CategoryNode) destinationNode;
- return (categoryNode instanceof ArchiveNode);
+ return (categoryNode instanceof DataTypeStoreNode);
}
private boolean containsFlavor(DataFlavor[] flavors, DataFlavor flavor) {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeNode.java
index b6ceb9564a..c7e1a2c770 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeNode.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeNode.java
@@ -231,7 +231,7 @@ public class DataTypeNode extends DataTypeTreeNode {
}
@Override
- public ArchiveNode getArchiveNode() {
+ public DataTypeStoreNode getArchiveNode() {
GTreeNode parent = getParent();
if (parent == null) {
return null; // could happen during tree mutations
@@ -242,7 +242,7 @@ public class DataTypeNode extends DataTypeTreeNode {
@Override
public boolean isModifiable() {
- ArchiveNode archiveNode = getArchiveNode();
+ DataTypeStoreNode archiveNode = getArchiveNode();
return archiveNode != null && archiveNode.isModifiable();
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeStoreNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeStoreNode.java
new file mode 100644
index 0000000000..a78dc7191d
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeStoreNode.java
@@ -0,0 +1,447 @@
+/* ###
+ * 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.tree;
+
+import java.util.Comparator;
+import java.util.List;
+
+import docking.widgets.tree.GTree;
+import docking.widgets.tree.GTreeNode;
+import ghidra.program.model.data.*;
+import ghidra.program.model.dtarchive.DataTypeStore;
+import ghidra.util.task.SwingUpdateManager;
+
+/**
+ * That have a valid DataTypeManager (program, file archive, project archive, built-in archive)
+ */
+public abstract class DataTypeStoreNode extends CategoryNode {
+
+ protected static final String DEFAULT_DATA_ORG_DESCRIPTION =
+ "[Using Default Data Organization]";
+
+ protected DataTypeStore dataTypeStore;
+ protected ArchiveNodeCategoryChangeListener listener;
+ private DataTypeManager dataTypeManager; // may be null
+ private Comparator archiveComparator = new ArchiveComparator();
+
+ protected DataTypeStoreNode(DataTypeStore archive, DtFilterState filterState) {
+ super(archive.getDataTypeManager().getRootCategory(), filterState);
+ this.dataTypeStore = archive;
+ dataTypeManager = archive.getDataTypeManager();
+ installDataTypeManagerListener();
+ }
+
+ public DataTypeManager getDataTypeManager() {
+ return dataTypeStore.getDataTypeManager();
+ }
+
+ protected void stateChanged() {
+ nodeChanged(); // notify that this nodes display data has changed
+ }
+
+ protected void installDataTypeManagerListener() {
+ listener = new ArchiveNodeCategoryChangeListener();
+ dataTypeManager.addDataTypeManagerListener(listener);
+ }
+
+ @Override
+ public void dispose() {
+ dataTypeManager.removeDataTypeManagerListener(listener);
+ listener.dispose();
+ super.dispose();
+ }
+
+ @Override
+ public String getName() {
+ return dataTypeStore.getName();
+ }
+
+ @Override
+ public String getToolTip() {
+ return null;
+ }
+
+ @Override
+ public boolean isLeaf() {
+ return false;
+ }
+
+ @Override
+ public boolean isEditable() {
+ return false;
+ }
+
+ public DataTypeStore getDataTypeStore() {
+ return dataTypeStore;
+ }
+
+ public void structureChanged() {
+ setChildren(null);
+ }
+
+ public void nodeChanged() {
+ fireNodeChanged();
+
+ GTree tree = getTree();
+ if (tree != null) {
+ tree.repaint();
+ }
+ }
+
+ @Override
+ public boolean canCut() {
+ return false;
+ }
+
+ @Override
+ public boolean isCut() {
+ return false;
+ }
+
+ /**
+ * The equals must not be based on the name since it can change based upon the underlying
+ * archive. This must be consistent with the hashCode method implementation.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (getClass() != o.getClass()) {
+ return false;
+ }
+ DataTypeStoreNode otherNode = (DataTypeStoreNode) o;
+ return dataTypeStore == otherNode.dataTypeStore;
+ }
+
+ @Override
+ public int compareTo(GTreeNode node) {
+ if (node instanceof DataTypeStoreNode archiveNode) {
+ return archiveComparator.compare(dataTypeStore, archiveNode.dataTypeStore);
+ }
+ return -1; // All ArchiveNodes are before any other types of nodes
+ }
+
+ /**
+ * The hash code must not be based on the name since it can change based upon the underlying
+ * archive. This must be consistent with the equals method implementation.
+ */
+ @Override
+ public int hashCode() {
+ return dataTypeStore.hashCode();
+ }
+
+ @Override
+ public DataTypeStoreNode getArchiveNode() {
+ return this;
+ }
+
+ @Override
+ public boolean isModifiable() {
+ return dataTypeStore.isChangeable();
+ }
+
+ /**
+ * Finds the node that represents the given category.
+ *
+ *
+ * Children will not be loaded when searching for the node. This allows clients to search
+ * for data types of interest, only updating the tree when the nodes are loaded.
+ *
+ * @param localCategory the category of interest
+ * @return the node if loaded; null if not loaded
+ */
+ public CategoryNode findCategoryNode(Category localCategory) {
+ return findCategoryNode(localCategory, false);
+ }
+
+ /**
+ * Finds the node that represents the given category.
+ *
+ * @param localCategory the category of interest
+ * @param loadChildren true will load child nodes when searching; false will not load children
+ * @return the node
+ */
+ public CategoryNode findCategoryNode(Category localCategory, boolean loadChildren) {
+
+ // if we don't have to loadChildren and we are not loaded get out.
+ if (!loadChildren && !isLoaded()) {
+ return null;
+ }
+
+ if (localCategory == null) {
+ return null;
+ }
+
+ if (getCategory() == localCategory) {
+ return DataTypeStoreNode.this;
+ }
+
+ Category parentCategory = localCategory.getParent();
+ if (getParent() == null) {
+ return null;
+ }
+
+ CategoryNode node = findCategoryNode(parentCategory, loadChildren);
+ if (node == null) {
+ return null;
+ }
+
+ List children = node.getChildren();
+ for (GTreeNode child : children) {
+ if (!(child instanceof CategoryNode)) {
+ continue;
+ }
+
+ CategoryNode categoryNode = (CategoryNode) child;
+ if (categoryNode.getCategory() == localCategory) {
+ return categoryNode;
+ }
+ }
+ return null;
+ }
+
+//==================================================================================================
+// Inner Classes
+//==================================================================================================
+
+ private class ArchiveNodeCategoryChangeListener implements DataTypeManagerChangeListener {
+
+ private SwingUpdateManager nodeChangedUpdater = new SwingUpdateManager(() -> nodeChanged());
+
+ @Override
+ public void categoryAdded(DataTypeManager dtm, CategoryPath path) {
+ if (!isLoaded()) {
+ return;
+ }
+
+ Category newCategory = dtm.getCategory(path);
+ if (newCategory == null) {
+ return;
+ }
+ Category category = newCategory.getParent();
+ CategoryNode categoryNode = findCategoryNode(category);
+ if (categoryNode != null) {
+ categoryNode.categoryAdded(newCategory);
+ }
+ }
+
+ void dispose() {
+ nodeChangedUpdater.dispose();
+ }
+
+ @Override
+ public void categoryMoved(DataTypeManager dtm, CategoryPath oldPath, CategoryPath newPath) {
+ if (!isLoaded()) {
+ return;
+ }
+
+ Category newCategory = dtm.getCategory(newPath);
+ Category oldParent = dtm.getCategory(oldPath.getParent());
+ CategoryNode categoryNode = findCategoryNode(oldParent);
+ if (categoryNode != null) {
+ categoryNode.categoryRemoved(oldPath.getName());
+ }
+ categoryNode = findCategoryNode(newCategory.getParent());
+ if (categoryNode != null) {
+ categoryNode.categoryAdded(newCategory);
+ }
+ }
+
+ @Override
+ public void categoryRemoved(DataTypeManager dtm, CategoryPath path) {
+ if (!isLoaded()) {
+ return;
+ }
+
+ Category parentCategory = dtm.getCategory(path.getParent());
+ CategoryNode categoryNode = findCategoryNode(parentCategory);
+ if (categoryNode != null) {
+ categoryNode.categoryRemoved(path.getName());
+ }
+ }
+
+ @Override
+ public void categoryRenamed(DataTypeManager dtm, CategoryPath oldPath,
+ CategoryPath newPath) {
+ if (!isLoaded()) {
+ return;
+ }
+
+ if (oldPath.getParent() == null) { // root has no parent
+ DataTypeStoreNode.this.fireNodeChanged(); // fire that the root changed
+ return;
+ }
+ Category parentCategory = dtm.getCategory(oldPath.getParent());
+ CategoryNode categoryNode = findCategoryNode(parentCategory);
+ if (categoryNode != null) {
+ categoryNode.categoryRemoved(oldPath.getName());
+ Category newCategory = dtm.getCategory(newPath);
+ categoryNode.categoryAdded(newCategory);
+ }
+ }
+
+ @Override
+ public void dataTypeAdded(DataTypeManager dtm, DataTypePath path) {
+ if (!isLoaded()) {
+ return;
+ }
+
+ Category parentCategory = dtm.getCategory(path.getCategoryPath());
+ CategoryNode categoryNode = findCategoryNode(parentCategory);
+ if (categoryNode != null) {
+ DataType dataType = dtm.getDataType(path);
+
+ // the data type can be changed before we get this call, since it's asynchronous
+ if (dataType != null) {
+ categoryNode.dataTypeAdded(dataType);
+ }
+ }
+ }
+
+ @Override
+ public void favoritesChanged(DataTypeManager dtm, DataTypePath path, boolean isFavorite) {
+ if (!isLoaded()) {
+ return;
+ }
+
+ DataType dataType = dtm.getDataType(path);
+ Category category = dtm.getCategory(path.getCategoryPath());
+ CategoryNode categoryNode = findCategoryNode(category);
+ if (categoryNode == null) {
+ return;
+ }
+ List children = categoryNode.getChildren();
+ for (GTreeNode node : children) {
+ if (node instanceof DataTypeNode) {
+ DataTypeNode dataTypeNode = (DataTypeNode) node;
+ if (dataTypeNode.getDataType() == dataType) {
+ dataTypeNode.dataTypeStatusChanged();
+ return;
+ }
+ }
+ }
+ }
+
+ @Override
+ public void dataTypeChanged(DataTypeManager dtm, DataTypePath path) {
+ if (!isLoaded()) {
+ return;
+ }
+
+ Category dtmCategory = dtm.getCategory(path.getCategoryPath());
+ CategoryNode categoryNode = findCategoryNode(dtmCategory);
+ if (categoryNode != null) {
+ DataType dataType = dtm.getDataType(path);
+
+ // the data type can be changed before we get this call, since it's asynchronous
+ if (dataType != null) {
+ categoryNode.dataTypeChanged(dataType);
+ }
+ }
+ }
+
+ @Override
+ public void dataTypeMoved(DataTypeManager dtm, DataTypePath oldPath, DataTypePath newPath) {
+ if (!isLoaded()) {
+ return;
+ }
+
+ Category oldParent = dtm.getCategory(oldPath.getCategoryPath());
+ CategoryNode categoryNode = findCategoryNode(oldParent);
+ if (categoryNode != null) {
+ categoryNode.dataTypeRemoved(oldPath.getDataTypeName());
+ }
+
+ Category newParent = dtm.getCategory(newPath.getCategoryPath());
+ categoryNode = findCategoryNode(newParent);
+ if (categoryNode != null) {
+ DataType dataType = dtm.getDataType(newPath);
+
+ // the data type can be changed before we get this call, since it's asynchronous
+ if (dataType != null) {
+ categoryNode.dataTypeAdded(dataType);
+ }
+ }
+ }
+
+ @Override
+ public void dataTypeRemoved(DataTypeManager dtm, DataTypePath path) {
+ if (!isLoaded()) {
+ return;
+ }
+
+ Category oldParent = dtm.getCategory(path.getCategoryPath());
+ CategoryNode categoryNode = findCategoryNode(oldParent);
+ if (categoryNode != null) {
+ categoryNode.dataTypeRemoved(path.getDataTypeName());
+ }
+ }
+
+ @Override
+ public void dataTypeRenamed(DataTypeManager dtm, DataTypePath oldPath,
+ DataTypePath newPath) {
+ if (!isLoaded()) {
+ return;
+ }
+
+ Category dtmCategory = dtm.getCategory(newPath.getCategoryPath());
+ CategoryNode categoryNode = findCategoryNode(dtmCategory);
+ if (categoryNode != null) {
+ categoryNode.dataTypeRemoved(oldPath.getDataTypeName());
+ DataType dataType = dtm.getDataType(newPath);
+
+ // the data type can be changed before we get this call, since it's asynchronous
+ if (dataType != null) {
+ categoryNode.dataTypeAdded(dataType);
+ }
+ }
+ }
+
+ @Override
+ public void dataTypeReplaced(DataTypeManager dtm, DataTypePath oldPath,
+ DataTypePath newPath, DataType newDataType) {
+ // Note: the replacement has already been added with its own event
+ dataTypeRemoved(dtm, oldPath);
+ }
+
+ @Override
+ public void sourceArchiveAdded(DataTypeManager manager, SourceArchive sourceArchive) {
+ // DT should these do anything?
+ }
+
+ @Override
+ public void sourceArchiveChanged(DataTypeManager manager, SourceArchive sourceArchive) {
+ nodeChangedUpdater.update();
+ }
+
+ @Override
+ public void programArchitectureChanged(DataTypeManager manager) {
+ // need to force all cached datatype tooltips to be cleared
+ // due to change in data organization
+ unloadChildren();
+ nodeChangedUpdater.update();
+ }
+
+ @Override
+ public void restored(DataTypeManager manager) {
+ // need to force all cached datatype tooltips to be cleared
+ // due to potential changes (e.g., undo/redo)
+ unloadChildren();
+ nodeChangedUpdater.update();
+ }
+ }
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeTreeNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeTreeNode.java
index 4f15b1e1bc..9ce1810511 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeTreeNode.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeTreeNode.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -56,7 +56,7 @@ public abstract class DataTypeTreeNode extends GTreeLazyNode {
* Returns the ArchiveNode for this tree node.
* @return the ArchiveNode for this tree node.
*/
- public abstract ArchiveNode getArchiveNode();
+ public abstract DataTypeStoreNode getArchiveNode();
/**
* Returns true if this node is from an archive that can be modified.
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/FileArchiveNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/FileArchiveNode.java
index b01983f62f..cc3fd473ca 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/FileArchiveNode.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/FileArchiveNode.java
@@ -19,45 +19,53 @@ import javax.swing.Icon;
import generic.jar.ResourceFile;
import generic.theme.GIcon;
-import ghidra.app.plugin.core.datamgr.archive.FileArchive;
+import ghidra.program.model.dtarchive.FileDataTypeArchive;
+import ghidra.util.HTMLUtilities;
import resources.MultiIcon;
import resources.icons.TranslateIcon;
+/**
+ * Nodes that represent FileDataTypeArchives
+ */
public class FileArchiveNode extends ArchiveNode {
+ private static Icon CLOSED_ICON = new GIcon("icon.plugin.datatypes.archive.file.closed");
+ private static Icon OPEN_ICON = new GIcon("icon.plugin.datatypes.archive.file.open");
private static Icon CHECKED_OUT_EXCLUSIVE_ICON =
new GIcon("icon.plugin.datatypes.tree.node.archive.file.checked.out.exclusive");
- FileArchive fileArchive; // casted reference for easy access
-
- public FileArchiveNode(FileArchive archive, DtFilterState filterState) {
+ public FileArchiveNode(FileDataTypeArchive archive, DtFilterState filterState) {
super(archive, filterState);
- this.fileArchive = archive;
}
@Override
public Icon getIcon(boolean expanded) {
DtBackgroundIcon bgIcon = new DtBackgroundIcon();
MultiIcon multiIcon = new MultiIcon(bgIcon);
- boolean hasWriteLock = fileArchive.hasWriteLock();
- Icon baseIcon = fileArchive.getIcon(expanded);
+ Icon baseIcon = expanded ? OPEN_ICON : CLOSED_ICON;
multiIcon.addIcon(baseIcon);
- if (hasWriteLock) {
+ if (archive.isChangeable()) {
multiIcon.addIcon(new TranslateIcon(CHECKED_OUT_EXCLUSIVE_ICON, 8, -4));
}
- // TODO: add program architecture state
-
return multiIcon;
}
@Override
public String getToolTip() {
- ResourceFile file = fileArchive.getFile();
- return buildTooltip(file != null ? file.getAbsolutePath() : "[Unsaved New Archive]");
+ ResourceFile file = ((FileDataTypeArchive) archive).getFile();
+ String path = file != null ? file.getAbsolutePath() : "[Unsaved New Archive]";
+
+ StringBuilder buf = new StringBuilder(HTMLUtilities.HTML);
+ buf.append(HTMLUtilities.escapeHTML(path));
+ buf.append(HTMLUtilities.BR);
+ buf.append(getArchitectureDetails());
+ buf.append(HTMLUtilities.HTML_CLOSE);
+ return buf.toString();
}
- public boolean hasWriteLock() {
- return fileArchive.hasWriteLock();
+ @Override
+ public FileDataTypeArchive getArchive() {
+ return (FileDataTypeArchive) super.getArchive();
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/InvalidArchiveNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/InvalidArchiveNode.java
index 88772e9259..6b2cf51b9a 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/InvalidArchiveNode.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/InvalidArchiveNode.java
@@ -15,18 +15,26 @@
*/
package ghidra.app.plugin.core.datamgr.tree;
+import java.util.Collections;
import java.util.List;
+import javax.swing.Icon;
+
import docking.widgets.tree.GTreeNode;
-import ghidra.app.plugin.core.datamgr.archive.Archive;
-import ghidra.app.plugin.core.datamgr.archive.InvalidFileArchive;
-import ghidra.program.model.data.ArchiveType;
+import generic.theme.GIcon;
+import ghidra.app.plugin.core.datamgr.archive.InvalidArchive;
import ghidra.util.HTMLUtilities;
-public class InvalidArchiveNode extends ArchiveNode {
+/**
+ * Archive node for an invalid file data type archive.
+ */
+public class InvalidArchiveNode extends DataTypeTreeNode {
+ private static final Icon INVALID_ARCHIVE_ICON =
+ new GIcon("icon.plugin.datatypes.archive.invalid");
+ private InvalidArchive archive;
- public InvalidArchiveNode(InvalidFileArchive archive) {
- super(archive, new DtFilterState());
+ public InvalidArchiveNode(InvalidArchive archive) {
+ this.archive = archive;
}
@Override
@@ -41,15 +49,13 @@ public class InvalidArchiveNode extends ArchiveNode {
@Override
public String getToolTip() {
- ArchiveType archiveType = ((InvalidFileArchive) archive).getArchiveType();
- String type = archiveType == ArchiveType.FILE ? "File" : "Project";
- return "Unable to locate " + type + " data type archive: " +
- HTMLUtilities.escapeHTML(archive.getName());
+ return "Unable to locate file data type archive: " +
+ HTMLUtilities.escapeHTML(archive.name());
}
@Override
public String getName() {
- return archive.getName();
+ return archive.name();
}
@Override
@@ -63,7 +69,7 @@ public class InvalidArchiveNode extends ArchiveNode {
}
@Override
- public ArchiveNode getArchiveNode() {
+ public FileArchiveNode getArchiveNode() {
return null;
}
@@ -79,11 +85,20 @@ public class InvalidArchiveNode extends ArchiveNode {
@Override
public void setNodeCut(boolean isCut) {
+ // do nothing
}
@Override
- public Archive getArchive() {
+ public Icon getIcon(boolean expanded) {
+ return INVALID_ARCHIVE_ICON;
+ }
+
+ public InvalidArchive getInvalidArchive() {
return archive;
}
+ @Override
+ protected List generateChildren() {
+ return Collections.emptyList();
+ }
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ProgramArchiveNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ProgramArchiveNode.java
index e49c290d87..4d4e3ff915 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ProgramArchiveNode.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ProgramArchiveNode.java
@@ -15,32 +15,82 @@
*/
package ghidra.app.plugin.core.datamgr.tree;
-import ghidra.app.plugin.core.datamgr.archive.ProgramArchive;
+import javax.swing.Icon;
+
+import generic.theme.GIcon;
+import ghidra.framework.data.DomainFileProxy;
import ghidra.framework.model.DomainFile;
-import ghidra.program.model.data.DataTypeManager;
+import ghidra.framework.model.DomainObject;
+import ghidra.program.model.listing.Program;
import ghidra.util.HTMLUtilities;
-public class ProgramArchiveNode extends DomainFileArchiveNode {
+/**
+ * Tree node representing datatypes from the currently active program
+ */
+public class ProgramArchiveNode extends DataTypeStoreNode implements VersionedNode {
+ 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 VersionState versionState;
- public ProgramArchiveNode(ProgramArchive archive, DtFilterState filterState) {
- super(archive, filterState);
+ public ProgramArchiveNode(Program program, DtFilterState filterState) {
+ super(program, filterState);
+ versionState = new VersionState(program);
+ }
+
+ public Program getProgram() {
+ return (Program) dataTypeStore;
}
@Override
public String getToolTip() {
- DataTypeManager dtm = archive.getDataTypeManager();
- DomainFile file = ((ProgramArchive) archive).getDomainFile();
+ DomainFile file = getDomainObject().getDomainFile();
+ DomainFile originalFile = file;
+ if (file instanceof DomainFileProxy proxy) {
+ originalFile = proxy.getOriginalDomainFile();
+ }
StringBuilder buf = new StringBuilder(HTMLUtilities.HTML);
- if (file != null) {
- buf.append(HTMLUtilities.escapeHTML(file.toString()));
+ if (originalFile != null) {
+ buf.append(HTMLUtilities.escapeHTML(originalFile.toString()));
}
else {
- buf.append("[Unsaved New Program Archive]");
+ buf.append("[Unsaved Program]");
}
buf.append(HTMLUtilities.BR);
buf.append(HTMLUtilities.HTML_SPACE);
buf.append(HTMLUtilities.HTML_SPACE);
- buf.append(HTMLUtilities.escapeHTML(dtm.getProgramArchitectureSummary()));
+ buf.append(HTMLUtilities.escapeHTML(dataTypeStore.getProgramArchitectureSummary()));
return buf.toString();
}
+
+ @Override
+ public Icon getIcon(boolean expanded) {
+ Icon baseIcon = expanded ? OPEN_ICON : CLOSED_ICON;
+ return versionState.getIcon(baseIcon);
+ }
+
+ @Override
+ public DomainObject getDomainObject() {
+ return dataTypeStore;
+ }
+
+ @Override
+ public String getDomainObjectInfo() {
+ return versionState.getDomainObjectInfo();
+ }
+
+ @Override
+ public void nodeChanged() {
+ super.nodeChanged();
+ versionState.updateDomainFileInfo();
+ }
+
+ @Override
+ public DomainFile getOriginalDomainFile() {
+ return versionState.getOriginalDomainFile();
+ }
+
+ @Override
+ public DomainFile getDomainFile() {
+ return dataTypeStore.getDomainFile();
+ }
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ProjectArchiveNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ProjectArchiveNode.java
index 53c3054a73..6cdf1b2352 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ProjectArchiveNode.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ProjectArchiveNode.java
@@ -15,53 +15,86 @@
*/
package ghidra.app.plugin.core.datamgr.tree;
-import ghidra.app.plugin.core.datamgr.archive.ProjectArchive;
+import javax.swing.Icon;
+
+import generic.theme.GIcon;
+import ghidra.framework.data.DomainFileProxy;
import ghidra.framework.model.DomainFile;
+import ghidra.framework.model.DomainObject;
+import ghidra.program.model.dtarchive.ProjectDataTypeArchive;
+import ghidra.util.HTMLUtilities;
-public class ProjectArchiveNode extends DomainFileArchiveNode {
+/**
+ * Tree node for representing open project datatype archives.
+ */
+public class ProjectArchiveNode extends ArchiveNode implements VersionedNode {
+ private static Icon CLOSED_ICON = new GIcon("icon.plugin.datatypes.archive.project.closed");
+ private static Icon OPEN_ICON = new GIcon("icon.plugin.datatypes.archive.project.open");
+ private VersionState versionState;
- public ProjectArchiveNode(ProjectArchive archive, DtFilterState filterState) {
+ public ProjectArchiveNode(ProjectDataTypeArchive archive, DtFilterState filterState) {
super(archive, filterState);
- }
-
- @Override
- protected void dataTypeManagerChanged() {
- setChildren(null); // old children are no longer valid.
- installDataTypeManagerListener();
- nodeChanged();
+ versionState = new VersionState(archive);
}
@Override
public String getToolTip() {
- DomainFile file = ((ProjectArchive) archive).getDomainFile();
- return buildTooltip(file != null ? file.getPathname() : "[Unsaved New Project Archive]");
+ DomainFile file = getDomainObject().getDomainFile();
+ DomainFile originalFile = file;
+ if (file instanceof DomainFileProxy proxy) {
+ originalFile = proxy.getOriginalDomainFile();
+ }
+ StringBuilder buf = new StringBuilder(HTMLUtilities.HTML);
+ if (originalFile != null) {
+ buf.append(HTMLUtilities.escapeHTML(originalFile.toString()));
+ }
+ else {
+ buf.append("[Unsaved Project Archive]");
+ }
+ buf.append(HTMLUtilities.BR);
+ buf.append(getArchitectureDetails());
+ buf.append(HTMLUtilities.HTML_CLOSE);
+ return buf.toString();
}
public boolean hasWriteLock() {
return false;
}
- /**
- * Overridden to avoid path conflicts that arise in CategoryNode.equals()
- *
- * @see java.lang.Object#equals(java.lang.Object)
- */
@Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (getClass() != o.getClass()) {
- return false;
- }
-
- if (super.equals(o)) {
- DomainFile myFile = ((ProjectArchive) archive).getDomainFile();
- DomainFile otherFile =
- ((ProjectArchive) ((ProjectArchiveNode) o).archive).getDomainFile();
- return myFile.equals(otherFile);
- }
- return false;
+ public void nodeChanged() {
+ super.nodeChanged();
+ versionState.updateDomainFileInfo();
}
+ @Override
+ public DomainObject getDomainObject() {
+ return getArchive();
+ }
+
+ @Override
+ public Icon getIcon(boolean expanded) {
+ Icon baseIcon = expanded ? OPEN_ICON : CLOSED_ICON;
+ return versionState.getIcon(baseIcon);
+ }
+
+ @Override
+ public ProjectDataTypeArchive getArchive() {
+ return (ProjectDataTypeArchive) super.getArchive();
+ }
+
+ @Override
+ public String getDomainObjectInfo() {
+ return versionState.getDomainObjectInfo();
+ }
+
+ @Override
+ public DomainFile getOriginalDomainFile() {
+ return versionState.getOriginalDomainFile();
+ }
+
+ @Override
+ public DomainFile getDomainFile() {
+ return archive.getDomainFile();
+ }
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DomainFileArchiveNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/VersionState.java
similarity index 58%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DomainFileArchiveNode.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/VersionState.java
index 1d2deec4cb..f7c453c47a 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DomainFileArchiveNode.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/VersionState.java
@@ -18,15 +18,18 @@ package ghidra.app.plugin.core.datamgr.tree;
import javax.swing.Icon;
import generic.theme.GIcon;
-import ghidra.app.plugin.core.datamgr.archive.DomainFileArchive;
+import ghidra.framework.data.DomainFileProxy;
import ghidra.framework.model.DomainFile;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.listing.Program;
import resources.MultiIcon;
import resources.icons.TranslateIcon;
-public abstract class DomainFileArchiveNode extends ArchiveNode {
-
+/**
+ * Class to keep track of version information. Used by the {@link ProgramArchiveNode} and the
+ * {@link ProjectArchiveNode}
+ */
+public class VersionState {
//@formatter:off
private static Icon CHECKED_OUT_ICON = new GIcon("icon.plugin.datatypes.tree.node.archive.file.checked.out");
private static Icon CHECKED_OUT_EXCLUSIVE_ICON = new GIcon("icon.plugin.datatypes.tree.node.archive.file.checked.out.exclusive");
@@ -43,71 +46,61 @@ public abstract class DomainFileArchiveNode extends ArchiveNode {
private boolean isVersioned;
private int version;
private int latestVersion;
-
+ private DomainObject domainObject;
private String domainFileInfoString;
- public DomainFileArchiveNode(DomainFileArchive archive, DtFilterState filterState) {
- super(archive, filterState);
-
+ VersionState(DomainObject domainObject) {
+ this.domainObject = domainObject;
updateDomainFileInfo();
}
- private void updateDomainFileInfo() {
- DomainObject domainObject = ((DomainFileArchive) archive).getDomainObject();
- DomainFile domainFile = ((DomainFileArchive) archive).getDomainFile();
+ void updateDomainFileInfo() {
+ DomainFile domainFile = domainObject.getDomainFile();
+ DomainFile originalDomainFile = getOriginalDomainFile();
isChanged = domainObject.isChanged();
- isReadOnly = domainFile.isReadOnly() || !domainFile.isInWritableProject();
- isHijacked = domainFile.isHijacked();
- isVersioned = domainFile.isVersioned();
- version = (isVersioned || !domainFile.canSave()) ? domainFile.getVersion()
- : DomainFile.DEFAULT_VERSION;
- isCheckedOutExclusive =
- (!isVersioned && domainObject.hasExclusiveAccess() && !isReadOnly) ||
- (isVersioned && domainFile.isCheckedOutExclusive());
- isCheckedOut = isCheckedOutExclusive || domainFile.isCheckedOut();
- latestVersion = domainFile.getLatestVersion();
+ isReadOnly = domainFile.isReadOnly();
+
+ isVersioned = originalDomainFile.isVersioned();
+
+ // NOTE: DomainFileProxy may indicate version as DEFAULT_VERSION (-1) if latest version
+ // was open read-only. A specific version is only provided when that version was
+ // explicitly opened read-only.
+ latestVersion = originalDomainFile.getLatestVersion();
+ version = domainFile.getVersion();
+ if (version == DomainFile.DEFAULT_VERSION && isVersioned && latestVersion > 0) {
+ version = latestVersion; // default version tracks latest version
+ }
+
+ isHijacked = !isReadOnly && originalDomainFile.isHijacked();
+ isCheckedOutExclusive = !isReadOnly && originalDomainFile.isCheckedOutExclusive();
+ isCheckedOut = !isReadOnly && originalDomainFile.isCheckedOut();
domainFileInfoString = createDomainFileInfoString();
}
- private String createDomainFileInfoString() {
- DomainObject domainObject = ((DomainFileArchive) archive).getDomainObject();
- String name = "";
- if (isHijacked) {
- name += " (hijacked)";
- }
- else if (isVersioned) {
- if (version == latestVersion && !isCheckedOut) {
- name += " (" + version + ")";
- }
- else {
- name += " (" + version + " of " + latestVersion + ")";
+ /**
+ * {@return the original domain file associated with this archive node or
+ * the same as {@link #getDomainFile()} if not opened from project storage}
+ */
+ public DomainFile getOriginalDomainFile() {
+ DomainFile domainFile = domainObject.getDomainFile();
+ if (domainFile instanceof DomainFileProxy proxy) {
+ DomainFile originalDomainFile = proxy.getOriginalDomainFile();
+ if (originalDomainFile != null) {
+ return originalDomainFile;
}
}
- else if (version != DomainFile.DEFAULT_VERSION) {
- name += " @ " + version;
- }
- if (!(domainObject instanceof Program) && isChanged) {
- name += " *";
- }
-
- return name;
+ return domainFile;
}
- @Override
- public abstract String getToolTip();
-
- @Override
- public boolean canDelete() {
- return false;
- }
-
- @Override
- public Icon getIcon(boolean expanded) {
-
- Icon baseIcon = archive.getIcon(expanded);
+ /**
+ * Returns an icon that overlays a given base icon with version state information.
+ * @param baseIcon the base icon to be decorated
+ * @return a new Icon that decorates a base icon with version state information
+ */
+ public Icon getIcon(Icon baseIcon) {
DtBackgroundIcon bgIcon = new DtBackgroundIcon(isVersioned);
MultiIcon multiIcon = new MultiIcon(bgIcon);
multiIcon.addIcon(baseIcon);
@@ -130,22 +123,31 @@ public abstract class DomainFileArchiveNode extends ArchiveNode {
}
}
- // TODO: add program architecture state
-
return multiIcon;
}
- protected String getDomainObjectInfo() {
+ private String createDomainFileInfoString() {
+ String name = "";
+ if (isHijacked) {
+ name += " (hijacked)";
+ }
+ if (isVersioned && version != DomainFile.DEFAULT_VERSION) {
+ if (version == latestVersion) {
+ name += " (" + version + ")";
+ }
+ else {
+ name += " (" + version + " of " + latestVersion + ")";
+ }
+ }
+ if (!(domainObject instanceof Program) && isChanged) {
+ name += " *";
+ }
+
+ return name;
+ }
+
+ public String getDomainObjectInfo() {
return domainFileInfoString;
}
- public DomainFile getDomainFile() {
- return ((DomainFileArchive) archive).getDomainFile();
- }
-
- @Override
- public void nodeChanged() {
- super.nodeChanged();
- updateDomainFileInfo();
- }
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/VersionedNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/VersionedNode.java
new file mode 100644
index 0000000000..812e68b90f
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/VersionedNode.java
@@ -0,0 +1,45 @@
+/* ###
+ * 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.tree;
+
+import ghidra.framework.model.DomainFile;
+import ghidra.framework.model.DomainObject;
+
+/**
+ * Common interface for DataTypeStoreNodes that support versioning.
+ */
+public interface VersionedNode {
+ /**
+ * {@return the domainObject (this will be the program or archive)}
+ */
+ public DomainObject getDomainObject();
+
+ /**
+ * {@return the actual project DomainFile that was used to open this DataTypeStore}
+ */
+ public DomainFile getOriginalDomainFile();
+
+ /**
+ * {@return the current DomainFile associated with this DataTypeStore. This may be a proxy}
+ * if the program or archive was opened read-only
+ */
+ public DomainFile getDomainFile();
+
+ /**
+ * {@return a string that describes the current version state of this program or archive}
+ */
+ public String getDomainObjectInfo();
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/DataTypeArchiveUtility.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/DataTypeArchiveUtility.java
index 98d23a5cd2..571492328f 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/DataTypeArchiveUtility.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/DataTypeArchiveUtility.java
@@ -18,10 +18,10 @@ package ghidra.app.plugin.core.datamgr.util;
import java.util.*;
import generic.jar.ResourceFile;
-import ghidra.app.plugin.core.datamgr.archive.DataTypeManagerHandler;
import ghidra.app.util.opinion.*;
import ghidra.framework.Application;
-import ghidra.program.model.data.FileDataTypeManager;
+import ghidra.program.database.dtarchive.FileDtArchiveDB;
+import ghidra.program.model.dtarchive.FileDataTypeArchive;
import ghidra.program.model.listing.Program;
import ghidra.util.Msg;
@@ -40,14 +40,14 @@ public class DataTypeArchiveUtility {
new HashMap();
static {
for (ResourceFile file : Application
- .findFilesByExtensionInApplication(FileDataTypeManager.SUFFIX)) {
+ .findFilesByExtensionInApplication(FileDtArchiveDB.SUFFIX)) {
String name = file.getName();
ResourceFile resourceFile = GHIDRA_ARCHIVES.get(name);
if (resourceFile == null) {
GHIDRA_ARCHIVES.put(file.getName(), file);
}
else {
- Msg.showError(DataTypeManagerHandler.class, null, "Duplicate Archive Name Error",
+ Msg.showError(DataTypeArchiveUtility.class, null, "Duplicate Archive Name Error",
"Duplicate datatype archive name detected and is not supported:\n " +
resourceFile.getAbsolutePath() + "\n " + file.getAbsolutePath());
}
@@ -76,8 +76,8 @@ public class DataTypeArchiveUtility {
* @return existing resource file or null if not found
*/
public static ResourceFile findArchiveFile(String archiveName) {
- if (!archiveName.endsWith(FileDataTypeManager.SUFFIX)) {
- archiveName = archiveName + FileDataTypeManager.SUFFIX;
+ if (!archiveName.endsWith(FileDataTypeArchive.SUFFIX)) {
+ archiveName = archiveName + FileDataTypeArchive.SUFFIX;
}
archiveName = archiveName.replace('\\', '/');
if (archiveName.indexOf(':') >= 0 || archiveName.charAt(0) == '/') {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/DataTypeChooserDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/DataTypeChooserDialog.java
index 873a022744..1325ee6789 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/DataTypeChooserDialog.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/DataTypeChooserDialog.java
@@ -33,11 +33,12 @@ import docking.widgets.filter.FilterOptions;
import docking.widgets.filter.TextFilterStrategy;
import docking.widgets.label.GDLabel;
import docking.widgets.tree.*;
+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.plugin.core.datamgr.tree.*;
import ghidra.app.util.datatype.DataTypeSelectionDialog;
import ghidra.program.model.data.*;
+import ghidra.program.model.listing.Program;
import ghidra.util.HelpLocation;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
@@ -124,17 +125,17 @@ public class DataTypeChooserDialog extends DialogComponentProvider {
}
public void setShowProgramArchiveOnly(boolean programOnly) {
- DataTypeManagerHandler handler = plugin.getDataTypeManagerHandler();
+ ArchiveManager archiveManager = plugin.getArchiveManager();
if (programOnly) {
- DataTypeManager programDtm = handler.getProgramDataTypeManager();
- if (programDtm != null) {
- ArchiveRootNode root = new ArchiveRootNode(handler, true);
+ Program program = archiveManager.getProgram();
+ if (program != null) {
+ ArchiveRootNode root = new ArchiveRootNode(archiveManager, true);
tree.setRootNode(root);
return;
}
}
- ArchiveRootNode root = new ArchiveRootNode(handler);
+ ArchiveRootNode root = new ArchiveRootNode(archiveManager);
tree.setRootNode(root);
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/DataTypeTreeCopyMoveTask.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/DataTypeTreeCopyMoveTask.java
index 3d86e8836f..8c95a3b93f 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/DataTypeTreeCopyMoveTask.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/DataTypeTreeCopyMoveTask.java
@@ -22,10 +22,10 @@ import java.util.regex.Pattern;
import docking.widgets.OptionDialog;
import docking.widgets.tree.GTreeNode;
import docking.widgets.tree.GTreeState;
-import ghidra.app.plugin.core.datamgr.archive.Archive;
-import ghidra.app.plugin.core.datamgr.archive.ProgramArchive;
import ghidra.app.plugin.core.datamgr.tree.*;
import ghidra.program.model.data.*;
+import ghidra.program.model.dtarchive.DataTypeStore;
+import ghidra.program.model.listing.Program;
import ghidra.util.*;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.DuplicateNameException;
@@ -51,8 +51,8 @@ public class DataTypeTreeCopyMoveTask extends Task {
private DataTypeArchiveGTree gTree;
private Category destinationCategory;
private List copyMoveNodes;
- private Archive sourceArchive;
- private Archive destinationArchive;
+ private DataTypeStore sourceDataTypeStore;
+ private DataTypeStore destinationDataTypeStore;
private boolean promptToAssociateTypes = true;
private ActionType actionType;
private DataTypeConflictHandler conflictHandler;
@@ -66,11 +66,11 @@ public class DataTypeTreeCopyMoveTask extends Task {
public DataTypeTreeCopyMoveTask(CategoryNode destinationNode, List droppedNodeList,
ActionType actionType, DataTypeArchiveGTree gTree,
DataTypeConflictHandler conflictHandler) {
- this(findArchive(destinationNode), destinationNode.getCategory(), droppedNodeList,
+ this(findDataStore(destinationNode), destinationNode.getCategory(), droppedNodeList,
actionType, gTree, conflictHandler);
}
- public DataTypeTreeCopyMoveTask(Archive destinationArchive, Category destinationCategory,
+ public DataTypeTreeCopyMoveTask(DataTypeStore destination, Category destinationCategory,
List droppedNodeList, ActionType actionType, DataTypeArchiveGTree gTree,
DataTypeConflictHandler conflictHandler) {
super("Drag/Drop", true, true, true);
@@ -79,16 +79,16 @@ public class DataTypeTreeCopyMoveTask extends Task {
this.actionType = actionType;
this.gTree = gTree;
this.conflictHandler = conflictHandler;
- this.destinationArchive = destinationArchive;
+ this.destinationDataTypeStore = destination;
GTreeNode firstNode = copyMoveNodes.get(0);
- this.sourceArchive = findArchive(firstNode);
+ this.sourceDataTypeStore = findDataStore(firstNode);
}
- 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();
}
@@ -178,7 +178,7 @@ public class DataTypeTreeCopyMoveTask extends Task {
private boolean checkForDifferentSourceArchives() {
for (GTreeNode node : copyMoveNodes) {
- if (sourceArchive != findArchive(node)) {
+ if (sourceDataTypeStore != findDataStore(node)) {
Msg.showError(this, gTree, "Copy Failed",
"All data types must be from the same archive!");
return true;
@@ -189,7 +189,7 @@ public class DataTypeTreeCopyMoveTask extends Task {
}
private void doCopy(TaskMonitor monitor) {
- DataTypeManager dtm = destinationArchive.getDataTypeManager();
+ DataTypeManager dtm = destinationDataTypeStore.getDataTypeManager();
int txId = dtm.startTransaction("Copy/Move Category/DataType");
try {
copyOrMoveNodesToCategory(monitor);
@@ -202,9 +202,9 @@ public class DataTypeTreeCopyMoveTask extends Task {
private boolean needToCreateAssociation() {
// copying from the program archive into another archive
- return sourceArchive != destinationArchive &&
- !(destinationArchive instanceof ProgramArchive) &&
- (sourceArchive instanceof ProgramArchive);
+ return sourceDataTypeStore != destinationDataTypeStore &&
+ !(destinationDataTypeStore instanceof Program) &&
+ (sourceDataTypeStore instanceof Program);
}
private void collapseArchives() {
@@ -223,8 +223,9 @@ public class DataTypeTreeCopyMoveTask extends Task {
monitor.initialize(copyMoveNodes.size());
- SourceArchive destination = destinationArchive.getDataTypeManager().getLocalSourceArchive();
- DataTypeManager dtm = sourceArchive.getDataTypeManager();
+ SourceArchive destination =
+ destinationDataTypeStore.getDataTypeManager().getLocalSourceArchive();
+ DataTypeManager dtm = sourceDataTypeStore.getDataTypeManager();
int txId = dtm.startTransaction("Associate Data Types");
try {
for (GTreeNode node : copyMoveNodes) {
@@ -348,7 +349,7 @@ public class DataTypeTreeCopyMoveTask extends Task {
monitor.setMessage("Adding " + node.getName());
// COPY is only allowed action if the source and destination archives are different.
- if (actionType == ActionType.COPY || sourceArchive != destinationArchive) {
+ if (actionType == ActionType.COPY || sourceDataTypeStore != destinationDataTypeStore) {
copyNode(toCategory, node, monitor);
}
else {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/DataTypeTreeDeleteTask.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/DataTypeTreeDeleteTask.java
index f9441689ad..eebab1cea8 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/DataTypeTreeDeleteTask.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/DataTypeTreeDeleteTask.java
@@ -22,7 +22,6 @@ import docking.widgets.tree.GTreeNode;
import docking.widgets.tree.GTreeState;
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.tree.*;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.Program;
@@ -36,7 +35,7 @@ public class DataTypeTreeDeleteTask extends Task {
// if the total number of nodes is small, we won't need to collapse the tree before deleting
// the nodes to avoid excess tree events
private static final int NODE_COUNT_FOR_COLLAPSING_TREE = 100;
- private Map> nodesByArchive;
+ private Map> nodesByArchive;
private DataTypeManagerPlugin plugin;
private int nodeCount;
@@ -51,11 +50,11 @@ public class DataTypeTreeDeleteTask extends Task {
nodesByArchive = groupNodeByArchive(nodes);
}
- private Map> groupNodeByArchive(List nodes) {
+ private Map> groupNodeByArchive(List nodes) {
- Map