diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/CoffLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/CoffLoader.java index c0789671a0..92589232c7 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/CoffLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/CoffLoader.java @@ -827,6 +827,11 @@ public class CoffLoader extends AbstractLibrarySupportLoader { return COFF_NAME; } + @Override + public Collection getAssociatedFileExtensions() { + return List.of("o", "obj"); + } + class CoffPair { public long offset; public long size; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ComLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ComLoader.java index b4d0a39d57..db7ea88300 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ComLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ComLoader.java @@ -51,6 +51,11 @@ public class ComLoader extends AbstractLibrarySupportLoader { return COM_NAME; } + @Override + public Collection getAssociatedFileExtensions() { + return List.of("com"); + } + @Override public boolean isFallback() { return true; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfLoader.java index dd341a4e76..75db5131ab 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfLoader.java @@ -193,6 +193,11 @@ public class ElfLoader extends AbstractLibrarySupportLoader { return ELF_NAME; } + @Override + public Collection getAssociatedFileExtensions() { + return List.of("so", "o"); + } + /** * Attempts to detect a more specific compiler from the ELF * diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/IntelHexLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/IntelHexLoader.java index ce65c771b4..c718d844c5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/IntelHexLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/IntelHexLoader.java @@ -289,4 +289,9 @@ public class IntelHexLoader extends AbstractProgramLoader { public String getName() { return INTEL_HEX_NAME; } + + @Override + public Collection getAssociatedFileExtensions() { + return List.of("hex"); + } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/Loader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/Loader.java index 72421eb159..ec01c37e7c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/Loader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/Loader.java @@ -297,6 +297,13 @@ public interface Loader extends ExtensionPoint, Comparable { return COMMAND_LINE_ARG_PREFIX + arg; } + /** + * {@return a {@link Collection} of file extensions associated with this {@link Loader}} + */ + public default Collection getAssociatedFileExtensions() { + return List.of(); + } + @Override public default int compareTo(Loader o) { int compareTiers = getTier().compareTo(o.getTier()); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/LoaderService.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/LoaderService.java index f52d023cad..cf6af173ac 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/LoaderService.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/LoaderService.java @@ -168,7 +168,7 @@ public class LoaderService { * @return An instance of every known {@link Loader}. The {@link Loader} instances are sorted * according to their {@link Loader#compareTo(Loader) natural ordering}. */ - private synchronized static Collection getAllLoaders() { + public synchronized static Collection getAllLoaders() { List loaders = new ArrayList<>(ClassSearcher.getInstances(Loader.class)); Collections.sort(loaders); return loaders; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoLoader.java index 716df7bf46..e0dd3974da 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoLoader.java @@ -178,6 +178,11 @@ public class MachoLoader extends AbstractLibrarySupportLoader { return MACH_O_NAME; } + @Override + public Collection getAssociatedFileExtensions() { + return List.of("dylib"); + } + @Override protected boolean isValidSearchPath(FSRL fsrl, ImporterSettings settings) throws CancelledException { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/NeLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/NeLoader.java index a06295188b..64f43cf560 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/NeLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/NeLoader.java @@ -829,4 +829,9 @@ public class NeLoader extends AbstractOrdinalSupportLoader { return NE_NAME; } + @Override + public Collection getAssociatedFileExtensions() { + return List.of("exe", "dll"); + } + } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/Omf51Loader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/Omf51Loader.java index 107136e35d..9aa026502b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/Omf51Loader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/Omf51Loader.java @@ -480,4 +480,9 @@ public class Omf51Loader extends AbstractProgramWrapperLoader { public String getName() { return OMF51_NAME; } + + @Override + public Collection getAssociatedFileExtensions() { + return List.of("obj"); + } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/OmfLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/OmfLoader.java index e40e9faa4f..c202e4ad46 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/OmfLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/OmfLoader.java @@ -107,6 +107,11 @@ public class OmfLoader extends AbstractProgramWrapperLoader { return OMF_NAME; } + @Override + public Collection getAssociatedFileExtensions() { + return List.of("obj"); + } + @Override protected void load(Program program, ImporterSettings settings) throws IOException, CancelledException { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/PeLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/PeLoader.java index 64bfb1acd3..7093e7609a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/PeLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/PeLoader.java @@ -870,6 +870,11 @@ public class PeLoader extends AbstractPeDebugLoader { return PE_NAME; } + @Override + public Collection getAssociatedFileExtensions() { + return List.of("exe", "dll", "sys"); + } + public static class CompilerOpinion { static final char[] errString_borland = "This program must be run under Win32\r\n$".toCharArray(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/GFileSystem.java b/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/GFileSystem.java index 5a9d442b51..4bb2830f80 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/GFileSystem.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/GFileSystem.java @@ -79,6 +79,13 @@ public interface GFileSystem extends Closeable, Iterable, ExtensionPoint return FSUtilities.getFilesystemDescriptionFromClass(this.getClass()); } + /** + * {@return a {@link Collection} of file extensions associated with this {@link GFileSystem}} + */ + public default Collection getAssociatedFileExtensions() { + return List.of(); + } + /** * File system's FSRL * diff --git a/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/annotations/FileSystemInfo.java b/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/annotations/FileSystemInfo.java index a4b80acb43..aeb4236ad9 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/annotations/FileSystemInfo.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/annotations/FileSystemInfo.java @@ -45,6 +45,11 @@ public @interface FileSystemInfo { */ String description() default ""; + /** + * {@return an array of file extensions associated with this filesystem} + */ + public String[] extensions() default {}; + /** * The {@link GFileSystemFactory} class that will be responsible for probing and * creating instances of this filesystem. diff --git a/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/factory/FileSystemFactoryMgr.java b/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/factory/FileSystemFactoryMgr.java index 682887e368..9b283aae7c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/factory/FileSystemFactoryMgr.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/factory/FileSystemFactoryMgr.java @@ -17,6 +17,7 @@ package ghidra.formats.gfilesystem.factory; import java.io.IOException; import java.util.*; +import java.util.stream.Collectors; import ghidra.app.util.bin.ByteProvider; import ghidra.formats.gfilesystem.*; @@ -116,6 +117,18 @@ public class FileSystemFactoryMgr { //@formatter:on } + /** + * {@return a map of associated file system extensions keyed by file system description} + */ + public Map getFilesystemExtensionsByDescription() { + return sortedFactories + .stream() + .collect( + Collectors.toMap(FileSystemInfoRec::getDescription, + FileSystemInfoRec::getExtensions)); + + } + /** * Returns the file system type of the specified {@link GFileSystem} class. * diff --git a/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/factory/FileSystemInfoRec.java b/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/factory/FileSystemInfoRec.java index 8e7fc3674d..18d1001912 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/factory/FileSystemInfoRec.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/factory/FileSystemInfoRec.java @@ -36,6 +36,7 @@ public class FileSystemInfoRec { private final int priority; private final Class fsClass; private final GFileSystemFactory factory; + private final String[] extensions; /** * A static {@link Comparator} that will order {@link FileSystemInfoRec} by their @@ -54,6 +55,7 @@ public class FileSystemInfoRec { * @return new {@link FileSystemInfoRec}, or null if the class doesn't have * valid file system meta data. */ + @SuppressWarnings("unchecked") public static FileSystemInfoRec fromClass(Class fsClazz) { FileSystemInfo fsi = fsClazz.getAnnotation(FileSystemInfo.class); if (fsi == null) { @@ -81,24 +83,26 @@ public class FileSystemInfoRec { // Hack to allow GFileSystemBaseFactory to know which fsclass is using it // so instances can be created by the single GFileSystemBaseFactory impl. - if (factory instanceof GFileSystemBaseFactory) { - ((GFileSystemBaseFactory) factory).setFileSystemClass( - (Class) fsClazz); + if (factory instanceof GFileSystemBaseFactory base) { + base.setFileSystemClass((Class) fsClazz); } FileSystemInfoRec fsir = - new FileSystemInfoRec(fsType, fsi.description(), fsi.priority(), fsClazz, factory); + new FileSystemInfoRec(fsType, fsi.description(), fsi.priority(), fsClazz, factory, + fsi.extensions()); return fsir; } private FileSystemInfoRec(String type, String description, int priority, - Class fsClass, GFileSystemFactory factory) { + Class fsClass, GFileSystemFactory factory, + String[] extensions) { this.type = type; this.description = description; this.priority = priority; this.fsClass = fsClass; this.factory = factory; + this.extensions = extensions; } /** @@ -148,4 +152,11 @@ public class FileSystemInfoRec { public GFileSystemFactory getFactory() { return factory; } + + /** + * {@return the associated file extensions for this filesystem} + */ + public String[] getExtensions() { + return extensions; + } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterPlugin.java index 1f53a1843d..e016a4793d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterPlugin.java @@ -465,8 +465,8 @@ public class ImporterPlugin extends Plugin private void initializeChooser(String title, String buttonText, boolean multiSelect) { if (chooser == null) { chooser = new GhidraFileChooser(tool.getActiveWindow()); - chooser.addFileFilter(ImporterUtilities.LOADABLE_FILES_FILTER); - chooser.addFileFilter(ImporterUtilities.CONTAINER_FILES_FILTER); + ImporterUtilities.addLoadableFileFilters(chooser); + ImporterUtilities.addFileSystemFileFilters(chooser); chooser.setSelectedFileFilter(GhidraFileFilter.ALL); } chooser.setFileSelectionMode(GhidraFileChooserMode.FILES_ONLY); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterUtilities.java b/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterUtilities.java index 33a18a7a9a..9b14336a27 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterUtilities.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterUtilities.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.util.*; import docking.widgets.OptionDialog; +import docking.widgets.filechooser.GhidraFileChooser; import ghidra.app.events.ProgramAddedToPluginEvent; import ghidra.app.plugin.core.help.AboutDomainObjectUtils; import ghidra.app.services.FileSystemBrowserService; @@ -31,6 +32,7 @@ import ghidra.app.util.importer.MessageLog; import ghidra.app.util.opinion.*; import ghidra.app.util.opinion.Loader.ImporterSettings; import ghidra.formats.gfilesystem.*; +import ghidra.formats.gfilesystem.factory.FileSystemFactoryMgr; import ghidra.framework.main.AppInfo; import ghidra.framework.main.FrontEndTool; import ghidra.framework.model.*; @@ -46,7 +48,6 @@ import ghidra.util.*; import ghidra.util.exception.CancelledException; import ghidra.util.exception.CryptoException; import ghidra.util.filechooser.ExtensionFileFilter; -import ghidra.util.filechooser.GhidraFileFilter; import ghidra.util.task.TaskLauncher; import ghidra.util.task.TaskMonitor; import util.CollectionUtils; @@ -60,20 +61,44 @@ import util.CollectionUtils; public class ImporterUtilities { /** - * File extension filter for well known 'loadable' files for GhidraFileChoosers. + * Adds file filters for associated {@link Loader} file extensions to the given + * {@link GhidraFileChooser} + * + * @param chooser The {@link GhidraFileChooser} to add extension file filters to */ - public static final GhidraFileFilter LOADABLE_FILES_FILTER = ExtensionFileFilter.forExtensions( - "Loadable files", "exe", "dll", "obj", "drv", "bin", "hex", "o", "a", "so", "class", "lib", - "dylib"); + public static void addLoadableFileFilters(GhidraFileChooser chooser) { + Set all = new HashSet<>(); + for (Loader loader : LoaderService.getAllLoaders()) { + Collection exts = loader.getAssociatedFileExtensions(); + if (!exts.isEmpty()) { + chooser.addFileFilter(new ExtensionFileFilter(exts, loader.getName())); + all.addAll(exts); + } + } + if (!all.isEmpty()) { + chooser.addFileFilter(new ExtensionFileFilter(all, "Loadable files")); + } + } /** - * File extension filter for well known 'container' files for GhidraFileChoosers. + * Adds file filters for associated {@link GFileSystem} file extensions to the given + * {@link GhidraFileChooser} + * + * @param chooser The {@link GhidraFileChooser} to add extension file filters to */ - public static final GhidraFileFilter CONTAINER_FILES_FILTER = - ExtensionFileFilter.forExtensions("Container files", "zip", "tar", "tgz", "jar", "gz", - "ipsw", "img3", "dmg", "apk", "cpio", "rpm", "lib"); - - private static final FileSystemService fsService = FileSystemService.getInstance(); + public static void addFileSystemFileFilters(GhidraFileChooser chooser) { + Set all = new HashSet<>(); + FileSystemFactoryMgr mgr = FileSystemFactoryMgr.getInstance(); + mgr.getFilesystemExtensionsByDescription().forEach((description, exts) -> { + if (exts.length > 0) { + chooser.addFileFilter(new ExtensionFileFilter(exts, description)); + Collections.addAll(all, exts); + } + }); + if (!all.isEmpty()) { + chooser.addFileFilter(new ExtensionFileFilter(all, "Container files")); + } + } static List getPairs(Collection loadSpecs) { Set pairs = new HashSet<>(); @@ -133,6 +158,8 @@ public class ImporterUtilities { Objects.requireNonNull(monitor); + FileSystemService fsService = FileSystemService.getInstance(); + try (RefdFile referencedFile = fsService.getRefdFile(fsrl, monitor)) { if (!ensureFileImportable(referencedFile, monitor)) { return; @@ -222,6 +249,7 @@ public class ImporterUtilities { } try { + FileSystemService fsService = FileSystemService.getInstance(); ByteProvider provider = fsService.getByteProvider(fsrl, false, monitor); if (provider.length() == 0) { Msg.showWarn(null, null, "Error opening " + fsrl.getName(), @@ -319,6 +347,7 @@ public class ImporterUtilities { TaskMonitor monitor) { try { + FileSystemService fsService = FileSystemService.getInstance(); ByteProvider provider = fsService.getByteProvider(fsrl, true, monitor); LoaderMap loaderMap = LoaderService.getAllSupportedLoadSpecs(provider, monitor); @@ -421,6 +450,8 @@ public class ImporterUtilities { Objects.requireNonNull(monitor); + FileSystemService fsService = FileSystemService.getInstance(); + try (ByteProvider bp = fsService.getByteProvider(fsrl, false, monitor)) { MessageLog messageLog = new MessageLog(); @@ -511,6 +542,7 @@ public class ImporterUtilities { Objects.requireNonNull(monitor); + FileSystemService fsService = FileSystemService.getInstance(); MessageLog messageLog = new MessageLog(); Object consumer = new Object(); program.addConsumer(consumer); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FileSystemBrowserPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FileSystemBrowserPlugin.java index 3c3a42cebd..af7caa9f80 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FileSystemBrowserPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FileSystemBrowserPlugin.java @@ -203,8 +203,8 @@ public class FileSystemBrowserPlugin extends Plugin private void openChooser(String title, String buttonText, boolean multiSelect) { if (chooserOpen == null) { chooserOpen = new GhidraFileChooser(tool.getActiveWindow()); - chooserOpen.addFileFilter(ImporterUtilities.LOADABLE_FILES_FILTER); - chooserOpen.addFileFilter(ImporterUtilities.CONTAINER_FILES_FILTER); + ImporterUtilities.addLoadableFileFilters(chooserOpen); + ImporterUtilities.addFileSystemFileFilters(chooserOpen); chooserOpen.setSelectedFileFilter(GhidraFileFilter.ALL); } chooserOpen.setFileSelectionMode(GhidraFileChooserMode.FILES_ONLY); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchImportDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchImportDialog.java index 59e3f92c0e..e381784a70 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchImportDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchImportDialog.java @@ -464,8 +464,8 @@ public class BatchImportDialog extends DialogComponentProvider { chooser.setTitle("Choose File to Batch Import"); chooser.setApproveButtonText("Select files"); chooser.setFileSelectionMode(GhidraFileChooserMode.FILES_AND_DIRECTORIES); - chooser.addFileFilter(ImporterUtilities.LOADABLE_FILES_FILTER); - chooser.addFileFilter(ImporterUtilities.CONTAINER_FILES_FILTER); + ImporterUtilities.addLoadableFileFilters(chooser); + ImporterUtilities.addFileSystemFileFilters(chooser); chooser.setSelectedFileFilter(GhidraFileFilter.ALL); chooser.setLastDirectoryPreference(LAST_IMPORT_DIR); diff --git a/Ghidra/Features/FileFormats/src/main/java/ghidra/app/util/opinion/DyldCacheExtractLoader.java b/Ghidra/Features/FileFormats/src/main/java/ghidra/app/util/opinion/DyldCacheExtractLoader.java index 8e2f637778..d4145acc3c 100644 --- a/Ghidra/Features/FileFormats/src/main/java/ghidra/app/util/opinion/DyldCacheExtractLoader.java +++ b/Ghidra/Features/FileFormats/src/main/java/ghidra/app/util/opinion/DyldCacheExtractLoader.java @@ -133,6 +133,11 @@ public class DyldCacheExtractLoader extends MachoLoader { return DYLD_CACHE_EXTRACT_NAME; } + @Override + public Collection getAssociatedFileExtensions() { + return List.of(); + } + @Override public int getTierPriority() { return 49; // Higher priority than MachoLoader diff --git a/Ghidra/Features/FileFormats/src/main/java/ghidra/app/util/opinion/MachoFileSetExtractLoader.java b/Ghidra/Features/FileFormats/src/main/java/ghidra/app/util/opinion/MachoFileSetExtractLoader.java index 098c26c3d3..40f79a6e36 100644 --- a/Ghidra/Features/FileFormats/src/main/java/ghidra/app/util/opinion/MachoFileSetExtractLoader.java +++ b/Ghidra/Features/FileFormats/src/main/java/ghidra/app/util/opinion/MachoFileSetExtractLoader.java @@ -104,6 +104,11 @@ public class MachoFileSetExtractLoader extends MachoLoader { return MACHO_FILESET_EXTRACT_NAME; } + @Override + public Collection getAssociatedFileExtensions() { + return List.of(); + } + @Override public int getTierPriority() { return 49; // Higher priority than MachoLoader diff --git a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/android/apk/ApkFileSystem.java b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/android/apk/ApkFileSystem.java index 066a93db5e..ee6228736b 100644 --- a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/android/apk/ApkFileSystem.java +++ b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/android/apk/ApkFileSystem.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -33,7 +33,12 @@ import ghidra.util.task.TaskMonitor; * APK is really just a ZIP file. * */ -@FileSystemInfo(type = "apk", description = "Android APK", factory = GFileSystemBaseFactory.class) +@FileSystemInfo( + type = "apk", + description = "Android APK", + factory = GFileSystemBaseFactory.class, + extensions = { "apk" } +) public class ApkFileSystem extends GFileSystemBase { public ApkFileSystem(String fileSystemName, ByteProvider provider) { diff --git a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/coff/CoffArchiveFileSystem.java b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/coff/CoffArchiveFileSystem.java index 4be79dbc56..569c79169e 100644 --- a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/coff/CoffArchiveFileSystem.java +++ b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/coff/CoffArchiveFileSystem.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -30,7 +30,12 @@ import ghidra.formats.gfilesystem.annotations.FileSystemInfo; import ghidra.formats.gfilesystem.fileinfo.FileAttributes; import ghidra.util.task.TaskMonitor; -@FileSystemInfo(type = "coff", description = "COFF Archive", factory = CoffArchiveFileSystemFactory.class) +@FileSystemInfo( + type = "coff", + description = "COFF Archive", + factory = CoffArchiveFileSystemFactory.class, + extensions = { "a" } +) public class CoffArchiveFileSystem extends AbstractFileSystem { private ByteProvider provider; diff --git a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/cpio/CpioFileSystem.java b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/cpio/CpioFileSystem.java index aff9ae9998..8f3e88222c 100644 --- a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/cpio/CpioFileSystem.java +++ b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/cpio/CpioFileSystem.java @@ -32,7 +32,12 @@ import ghidra.formats.gfilesystem.fileinfo.FileType; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; -@FileSystemInfo(type = "cpio", description = "CPIO", factory = CpioFileSystemFactory.class) +@FileSystemInfo( + type = "cpio", + description = "CPIO", + factory = CpioFileSystemFactory.class, + extensions = { "cpio" } +) public class CpioFileSystem extends AbstractFileSystem { private static final int MAX_SANE_SYMLINK = 64 * 1024; diff --git a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/gzip/GZipFileSystem.java b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/gzip/GZipFileSystem.java index 5b548f5384..4a9b7a115e 100644 --- a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/gzip/GZipFileSystem.java +++ b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/gzip/GZipFileSystem.java @@ -28,7 +28,13 @@ import ghidra.formats.gfilesystem.fileinfo.FileAttributes; * If the filename can be recovered from the embedded metadata, it will be used as the * name of the singleton file, otherwise the name "gzip_decompressed" will be used. */ -@FileSystemInfo(type = "gzip", description = "GZIP", priority = FileSystemInfo.PRIORITY_LOW, factory = GZipFileSystemFactory.class) +@FileSystemInfo( + type = "gzip", + description = "GZIP", + priority = FileSystemInfo.PRIORITY_LOW, + factory = GZipFileSystemFactory.class, + extensions = { "gz" } +) public class GZipFileSystem extends AbstractSinglePayloadFileSystem { public GZipFileSystem(FSRLRoot fsFSRL, ByteProvider payloadProvider, String payloadFilename, diff --git a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/ios/dmg/DmgClientFileSystem.java b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/ios/dmg/DmgClientFileSystem.java index 5e238ad2e4..43cf079e5b 100644 --- a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/ios/dmg/DmgClientFileSystem.java +++ b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/ios/dmg/DmgClientFileSystem.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. @@ -44,7 +44,12 @@ import ghidra.util.task.*; * DMG server process seems to leak memory. Currently it is killed every N commands and * restarted. */ -@FileSystemInfo(type = "dmg", description = "iOS Disk Image (DMG)", factory = DmgClientFileSystemFactory.class) +@FileSystemInfo( + type = "dmg", + description = "iOS Disk Image (DMG)", + factory = DmgClientFileSystemFactory.class, + extensions = { "dmg" } +) public class DmgClientFileSystem extends AbstractFileSystem { private File decryptedDmgFile; diff --git a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/ios/img3/Img3FileSystem.java b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/ios/img3/Img3FileSystem.java index 3aadc1ca40..08212c3b07 100644 --- a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/ios/img3/Img3FileSystem.java +++ b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/ios/img3/Img3FileSystem.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. @@ -28,8 +28,12 @@ import ghidra.util.exception.CancelledException; import ghidra.util.exception.CryptoException; import ghidra.util.task.TaskMonitor; -@FileSystemInfo(type = "img3", description = "iOS " + - Img3Constants.IMG3_SIGNATURE, factory = Img3FileSystemFactory.class) +@FileSystemInfo( + type = "img3", + description = "iOS " + Img3Constants.IMG3_SIGNATURE, + factory = Img3FileSystemFactory.class, + extensions = { "img3" } +) public class Img3FileSystem extends AbstractFileSystem { private ByteProvider provider; diff --git a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/ios/ipsw/IpswFileSystem.java b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/ios/ipsw/IpswFileSystem.java index a9dc62ba06..ead7284497 100644 --- a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/ios/ipsw/IpswFileSystem.java +++ b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/ios/ipsw/IpswFileSystem.java @@ -34,7 +34,12 @@ import ghidra.util.task.TaskMonitor; *

* This implementation is currently unused (isValid always returns false). */ -@FileSystemInfo(type = "ipsw", description = "iOS Firmware (IPSW)", factory = GFileSystemBaseFactory.class) +@FileSystemInfo( + type = "ipsw", + description = "iOS Firmware (IPSW)", + factory = GFileSystemBaseFactory.class, + extensions = { "ipsw" } +) public class IpswFileSystem extends GFileSystemBase { public IpswFileSystem(String fileSystemName, ByteProvider provider) { diff --git a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/sevenzip/SevenZipFileSystem.java b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/sevenzip/SevenZipFileSystem.java index 97abdab00a..17e880ed66 100644 --- a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/sevenzip/SevenZipFileSystem.java +++ b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/sevenzip/SevenZipFileSystem.java @@ -46,7 +46,12 @@ import net.sf.sevenzipjbinding.simple.ISimpleInArchiveItem; * WARNING: care is taken to synchronize access to the underlying sevenzip library methods as * some race conditions have been encountered that cause the entire jdk to core dump. */ -@FileSystemInfo(type = "7zip", description = "7Zip", factory = SevenZipFileSystemFactory.class) +@FileSystemInfo( + type = "7zip", + description = "7Zip", + factory = SevenZipFileSystemFactory.class, + extensions = { "7z", "rpm" } +) public class SevenZipFileSystem extends AbstractFileSystem { private Map passwords = new HashMap<>(); @@ -203,7 +208,7 @@ public class SevenZipFileSystem extends AbstractFileSystem // that file will not be readable unless a password is found for it (see // getPasswordForFile()). - try (CryptoSession cryptoSession = fsService.newCryptoSession()) { + try (CryptoSession _ = fsService.newCryptoSession()) { List encryptedItems = getEncryptedItemsWithoutPasswords(); ISimpleInArchiveItem encryptedItem = null; while ((encryptedItem = getFirstItemWithoutPassword(encryptedItems)) != null && diff --git a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/tar/TarFileSystem.java b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/tar/TarFileSystem.java index e97098f345..344a2993bc 100644 --- a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/tar/TarFileSystem.java +++ b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/tar/TarFileSystem.java @@ -36,7 +36,13 @@ import ghidra.util.task.TaskMonitor; * The factory supports detecting both compressed (gz) and uncompressed tar files, * and keys both on the tar filename extension as well as the data in the file. */ -@FileSystemInfo(type = "tar", description = "TAR", priority = FileSystemInfo.PRIORITY_HIGH, factory = TarFileSystemFactory.class) +@FileSystemInfo( + type = "tar", + description = "TAR", + priority = FileSystemInfo.PRIORITY_HIGH, + factory = TarFileSystemFactory.class, + extensions = { "tar", "tgz" } +) public class TarFileSystem extends AbstractFileSystem { private ByteProvider provider; diff --git a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/zip/ZipFileSystem.java b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/zip/ZipFileSystem.java index 61ea9f492b..d4a850418f 100644 --- a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/zip/ZipFileSystem.java +++ b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/zip/ZipFileSystem.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,7 +25,13 @@ import ghidra.formats.gfilesystem.annotations.FileSystemInfo; *

* 7Zip's features are superior to the native java zip handling (ie. passwords) */ -@FileSystemInfo(type = "zip", description = "ZIP", factory = ZipFileSystemFactory.class, priority = FileSystemInfo.PRIORITY_HIGH) +@FileSystemInfo( + type = "zip", + description = "ZIP", + factory = ZipFileSystemFactory.class, + priority = FileSystemInfo.PRIORITY_HIGH, + extensions = { "zip", "jar" } +) public class ZipFileSystem extends SevenZipFileSystem { public ZipFileSystem(FSRLRoot fsrl, FileSystemService fsService) { diff --git a/Ghidra/Framework/Gui/src/main/java/ghidra/util/filechooser/ExtensionFileFilter.java b/Ghidra/Framework/Gui/src/main/java/ghidra/util/filechooser/ExtensionFileFilter.java index d9aa279f10..381d95af03 100644 --- a/Ghidra/Framework/Gui/src/main/java/ghidra/util/filechooser/ExtensionFileFilter.java +++ b/Ghidra/Framework/Gui/src/main/java/ghidra/util/filechooser/ExtensionFileFilter.java @@ -19,6 +19,7 @@ import java.io.File; import java.io.FileFilter; import java.util.*; import java.util.stream.Collectors; +import java.util.stream.Stream; import ghidra.util.Msg; import utilities.util.reflection.ReflectionUtilities; @@ -56,6 +57,7 @@ public class ExtensionFileFilter implements GhidraFileFilter { /** * Creates a file filter that accepts the given file type. + *

* Example: new ExtensionFileFilter("jpg", "JPEG Images"); * * @param extension file extension to match, without leading dot @@ -67,16 +69,38 @@ public class ExtensionFileFilter implements GhidraFileFilter { /** * Creates a file filter from the given string array and description. + *

* Example: new ExtensionFileFilter(String {"gif", "jpg"}, "Gif and JPG Images"); * * @param filters array of file name extensions, each without a leading dot * @param description descriptive string of the filter */ public ExtensionFileFilter(String[] filters, String description) { - this.extensions = Arrays.asList(filters) - .stream() - .map(ExtensionFileFilter::clean) - .collect(Collectors.toList()); + this(Arrays.stream(filters), description); + } + + /** + * Creates a file filter from the given string {@link Collection} and description. + *

+ * Example: new ExtensionFileFilter(List.of("gif", "jpg"), "Gif and JPG Images"); + * + * @param filters array of file name extensions, each without a leading dot + * @param description descriptive string of the filter + */ + public ExtensionFileFilter(Collection filters, String description) { + this(filters.stream(), description); + } + + /** + * Creates a file filter from the given string {@link Stream} and description. + *

+ * Example: new ExtensionFileFilter(Stream.of("gif", "jpg"), "Gif and JPG Images"); + * + * @param filters {@link List} of file name extensions, each without a leading dot + * @param description descriptive string of the filter + */ + private ExtensionFileFilter(Stream filters, String description) { + this.extensions = filters.map(ExtensionFileFilter::clean).collect(Collectors.toList()); this.description = description; } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/opinion/JavaLoader.java b/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/opinion/JavaLoader.java index 4cd3e6210d..e1b1245acb 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/opinion/JavaLoader.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/opinion/JavaLoader.java @@ -86,6 +86,11 @@ public class JavaLoader extends AbstractProgramWrapperLoader { return JAVA_NAME; } + @Override + public Collection getAssociatedFileExtensions() { + return List.of("class"); + } + @Override public void load(Program program, ImporterSettings settings) throws IOException { try {