diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterLanguageDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterLanguageDialog.java index eecf71d3fe..acb3079571 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterLanguageDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterLanguageDialog.java @@ -135,7 +135,7 @@ public class ImporterLanguageDialog extends DialogComponentProvider { } } - LanguageCompilerSpecPair getSelectedLanguage() { + public LanguageCompilerSpecPair getSelectedLanguage() { if (wasDialogCancelled) { return null; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchGroup.java b/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchGroup.java index fbb53138f1..23334d7646 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchGroup.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchGroup.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. @@ -59,12 +59,10 @@ public class BatchGroup { } public LoadSpec getLoadSpec(BatchGroupLoadSpec batchGroupLoadSpec) { - for (LoadSpec loadSpec : loadSpecs) { - if (batchGroupLoadSpec.matches(loadSpec)) { - return loadSpec; - } - } - return null; + return loadSpecs.stream() + .filter(batchGroupLoadSpec::matches) + .findFirst() + .orElse(new LoadSpec(loader, 0, batchGroupLoadSpec.lcsPair(), false)); } public UserAddedSourceInfo getUasi() { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchGroupLoadSpec.java b/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchGroupLoadSpec.java index 0cdb7ce725..c783d6f9d1 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchGroupLoadSpec.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchGroupLoadSpec.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,14 +24,15 @@ import ghidra.program.model.lang.LanguageCompilerSpecPair; *

* This has the same information as a {@link LoadSpec}, but for all the members of a * {@link BatchGroup}. + * + * @param lcsPair The language/compiler spec ID + * @param preferred true if this {@link BatchGroupLoadSpec} is preferred; otherwise, false */ -public class BatchGroupLoadSpec implements Comparable { - public LanguageCompilerSpecPair lcsPair; - public boolean preferred; +public record BatchGroupLoadSpec(LanguageCompilerSpecPair lcsPair, boolean preferred) + implements Comparable { public BatchGroupLoadSpec(LoadSpec loadSpec) { - lcsPair = loadSpec.getLanguageCompilerSpec(); - preferred = loadSpec.isPreferred(); + this(loadSpec.getLanguageCompilerSpec(), loadSpec.isPreferred()); } @Override @@ -45,41 +46,6 @@ public class BatchGroupLoadSpec implements Comparable { loadSpec.getLanguageCompilerSpec().equals(lcsPair)); } - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((lcsPair == null) ? 0 : lcsPair.hashCode()); - result = prime * result + (preferred ? 1231 : 1237); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof BatchGroupLoadSpec)) { - return false; - } - BatchGroupLoadSpec other = (BatchGroupLoadSpec) obj; - if (lcsPair == null) { - if (other.lcsPair != null) { - return false; - } - } - else if (!lcsPair.equals(other.lcsPair)) { - return false; - } - if (preferred != other.preferred) { - return false; - } - return true; - } - @Override public int compareTo(BatchGroupLoadSpec o) { String s1 = this.toString(); 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 70cbfd1b66..59e3f92c0e 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 @@ -40,15 +40,18 @@ import docking.widgets.label.GDLabel; import docking.widgets.table.*; import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.app.services.ProgramManager; +import ghidra.app.util.opinion.LoadSpec; import ghidra.formats.gfilesystem.FSRL; import ghidra.formats.gfilesystem.FileSystemService; import ghidra.framework.main.AppInfo; import ghidra.framework.model.DomainFolder; import ghidra.framework.plugintool.PluginTool; import ghidra.framework.preferences.Preferences; +import ghidra.plugin.importer.ImporterLanguageDialog; import ghidra.plugin.importer.ImporterUtilities; import ghidra.plugins.importer.batch.BatchGroup.BatchLoadConfig; import ghidra.plugins.importer.tasks.ImportBatchTask; +import ghidra.program.model.lang.LanguageCompilerSpecPair; import ghidra.util.*; import ghidra.util.filechooser.GhidraFileFilter; import ghidra.util.task.TaskLauncher; @@ -76,7 +79,8 @@ public class BatchImportDialog extends DialogComponentProvider { */ public static void showAndImport(PluginTool tool, BatchInfo batchInfo, List initialFiles, DomainFolder defaultFolder, ProgramManager programManager) { - BatchImportDialog dialog = new BatchImportDialog(batchInfo, defaultFolder, programManager); + BatchImportDialog dialog = + new BatchImportDialog(batchInfo, defaultFolder, programManager, tool); Swing.runLater(() -> { if (initialFiles != null && !initialFiles.isEmpty()) { dialog.addSources(initialFiles); @@ -91,6 +95,7 @@ public class BatchImportDialog extends DialogComponentProvider { private BatchInfo batchInfo; private DomainFolder destinationFolder; private ProgramManager programManager; + private PluginTool tool; private boolean stripLeading = getBooleanPref(PREF_STRIPLEADING, true); private boolean stripContainer = getBooleanPref(PREF_STRIPCONTAINER, false); private boolean mirrorFs = getBooleanPref(PREF_MIRRORFS, false); @@ -109,13 +114,14 @@ public class BatchImportDialog extends DialogComponentProvider { private SourcesListModel sourceListModel; private BatchImportDialog(BatchInfo batchInfo, DomainFolder defaultFolder, - ProgramManager programManager) { + ProgramManager programManager, PluginTool tool) { super("Batch Import", true); this.batchInfo = (batchInfo != null) ? batchInfo : new BatchInfo(); this.destinationFolder = defaultFolder != null ? defaultFolder : AppInfo.getActiveProject().getProjectData().getRootFolder(); this.programManager = programManager; + this.tool = tool; setHelpLocation(new HelpLocation("ImporterPlugin", "Batch_Import_Dialog")); @@ -150,6 +156,9 @@ public class BatchImportDialog extends DialogComponentProvider { if (modelIndex == BatchImportTableModel.COLS.FILES.ordinal()) { showFiles(row); } + else if (modelIndex == BatchImportTableModel.COLS.LANG.ordinal()) { + showLanguages(row); + } } }); @@ -171,7 +180,6 @@ public class BatchImportDialog extends DialogComponentProvider { TableColumn langColumn = table.getColumnModel().getColumn(BatchImportTableModel.COLS.LANG.ordinal()); - langColumn.setCellEditor(createLangColumnCellEditor()); langColumn.setCellRenderer(createLangColumnCellRenderer()); JScrollPane scrollPane = new JScrollPane(table); @@ -377,13 +385,10 @@ public class BatchImportDialog extends DialogComponentProvider { BatchGroup group = tableModel.getRowObject(row); List batchLoadConfigs = group.getBatchLoadConfig(); - //@formatter:off List names = batchLoadConfigs.stream() - .map(batchLoadConfig -> batchLoadConfig.getPreferredFileName()) - .sorted() - .collect(Collectors.toList()) - ; - //@formatter:on + .map(batchLoadConfig -> batchLoadConfig.getPreferredFileName()) + .sorted() + .collect(Collectors.toList()); ListSelectionTableDialog dialog = new ListSelectionTableDialog<>("Application Files", names); @@ -391,6 +396,36 @@ public class BatchImportDialog extends DialogComponentProvider { dialog.showSelectMultiple(table); } + private void showLanguages(int row) { + + BatchGroup group = tableModel.getRowObject(row); + List batchLoadConfigs = group.getBatchLoadConfig(); + + List loadSpecs = batchLoadConfigs.stream() + .flatMap(entry -> entry.getLoadSpecs().stream()) + .distinct() + .collect(Collectors.toList()); + + BatchGroupLoadSpec selectedLoadSpec = group.getSelectedBatchGroupLoadSpec(); + ImporterLanguageDialog dialog = + new ImporterLanguageDialog(loadSpecs, tool, selectedLoadSpec.lcsPair()); + dialog.show(getComponent()); + LanguageCompilerSpecPair dialogResult = dialog.getSelectedLanguage(); + if (dialogResult != null) { + for (BatchLoadConfig loadConfig : batchLoadConfigs) { + for (LoadSpec loadSpec : loadConfig.getLoadSpecs()) { + if (dialogResult.equals(loadSpec.getLanguageCompilerSpec())) { + tableModel.setValueAt(new BatchGroupLoadSpec(loadSpec), row, + BatchImportTableModel.COLS.LANG.ordinal()); + return; + } + } + } + tableModel.setValueAt(new BatchGroupLoadSpec(dialogResult, false), row, + BatchImportTableModel.COLS.LANG.ordinal()); + } + } + private void setOpenAfterImporting(boolean b) { this.openAfterImporting = b; } @@ -534,30 +569,6 @@ public class BatchImportDialog extends DialogComponentProvider { return cellRenderer; } - private TableCellEditor createLangColumnCellEditor() { - JComboBox comboBox = new GComboBox<>(); - DefaultCellEditor cellEditor = new DefaultCellEditor(comboBox) { - @Override - public boolean shouldSelectCell(EventObject anEvent) { - return false; - } - - @Override - public Component getTableCellEditorComponent(JTable jtable, Object value, - boolean isSelected, int row, int column) { - comboBox.removeAllItems(); - BatchGroup batchGroup = tableModel.getRowObject(row); - for (BatchGroupLoadSpec bo : batchGroup.getCriteria().getBatchGroupLoadSpecs()) { - comboBox.addItem(bo); - } - - return super.getTableCellEditorComponent(jtable, value, isSelected, row, column); - } - }; - - return cellEditor; - } - private TableCellRenderer createLangColumnCellRenderer() { TableCellRenderer cellRenderer = new GTableCellRenderer() { { @@ -579,7 +590,6 @@ public class BatchImportDialog extends DialogComponentProvider { "\">Click to set language"; } }; - return cellRenderer; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchImportTableModel.java b/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchImportTableModel.java index 31be182df2..a55d3b0c15 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchImportTableModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchImportTableModel.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,13 +15,10 @@ */ package ghidra.plugins.importer.batch; -import java.util.Comparator; -import java.util.List; +import java.util.*; import javax.swing.table.TableModel; -import org.apache.commons.lang3.StringUtils; - import docking.widgets.table.AbstractSortedTableModel; import ghidra.util.Msg; @@ -33,7 +30,7 @@ class BatchImportTableModel extends AbstractSortedTableModel { SELECTED("Selected", true), FILETYPE("File Type", false), LOADER("Loader", false), - LANG("Language", true), + LANG("Language", false), FILES("Files", false); public final String columnLabel; @@ -165,7 +162,7 @@ class BatchImportTableModel extends AbstractSortedTableModel { case SELECTED: return Boolean.valueOf(row.isEnabled()); case FILETYPE: - return StringUtils.defaultString(row.getCriteria().getFileExt(), ""); + return Objects.toString(row.getCriteria().getFileExt(), ""); case LOADER: return row.getCriteria().getLoader(); case LANG: diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchSegregatingCriteria.java b/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchSegregatingCriteria.java index d01eba03ce..27a5a0a699 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchSegregatingCriteria.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchSegregatingCriteria.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. @@ -70,7 +70,7 @@ public class BatchSegregatingCriteria { public BatchGroupLoadSpec getFirstPreferredLoadSpec() { for (BatchGroupLoadSpec groupLoadSpec : groupLoadSpecs) { - if (groupLoadSpec.preferred) { + if (groupLoadSpec.preferred()) { return groupLoadSpec; } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/tasks/ImportBatchTask.java b/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/tasks/ImportBatchTask.java index 9a91ddd50f..86aa2f32f2 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/tasks/ImportBatchTask.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/tasks/ImportBatchTask.java @@ -141,12 +141,6 @@ public class ImportBatchTask extends Task { try (ByteProvider byteProvider = FileSystemService.getInstance() .getByteProvider(batchLoadConfig.getFSRL(), true, monitor)) { LoadSpec loadSpec = batchLoadConfig.getLoadSpec(selectedBatchGroupLoadSpec); - if (loadSpec == null) { - Msg.error(this, - "Failed to get load spec from application that matches chosen batch load spec " + - selectedBatchGroupLoadSpec); - return; - } Pair destInfo = getDestinationInfo(batchLoadConfig, destFolder); try {