diff options
| -rw-r--r-- | binaryninjaapi.h | 17 | ||||
| -rw-r--r-- | binaryninjacore.h | 8 | ||||
| -rw-r--r-- | interaction.cpp | 25 | ||||
| -rw-r--r-- | python/interaction.py | 41 | ||||
| -rw-r--r-- | ui/metadatachoicedialog.h | 20 |
5 files changed, 97 insertions, 14 deletions
diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 7f7fca60..7a4efee4 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -1517,7 +1517,18 @@ namespace BinaryNinja { \return Whether a choice was successfully picked */ bool GetChoiceInput( - size_t& idx, const std::string& prompt, const std::string& title, const std::vector<std::string>& choices); + size_t& idx, const std::string& prompt, const std::string& title, const std::vector<std::string>& choices); + + /*! Prompts the user to select the one of the provided choices out of a large list, with the option to filter choices + + \ingroup interaction + \param[out] idx Reference to the size_t the resulting index selected will be copied to + \param[in] title Title for the input popup / prompt for headless + \param[in] prompt Prompt for the input (shown on the 'Select' button in UI) + \param[in] choices List of string choices for the user to select from + \return Whether a choice was successfully picked + */ + bool GetLargeChoiceInput(size_t& idx, const std::string& title, const std::string& prompt, const std::vector<std::string>& choices); /*! Prompts the user for a file name to open @@ -14527,7 +14538,9 @@ namespace BinaryNinja { virtual bool GetAddressInput(uint64_t& result, const std::string& prompt, const std::string& title, Ref<BinaryView> view, uint64_t currentAddr); virtual bool GetChoiceInput(size_t& idx, const std::string& prompt, const std::string& title, - const std::vector<std::string>& choices) = 0; + const std::vector<std::string>& choices) = 0; + virtual bool GetLargeChoiceInput(size_t& idx, const std::string& prompt, const std::string& title, + const std::vector<std::string>& choices) = 0; virtual bool GetOpenFileNameInput(std::string& result, const std::string& prompt, const std::string& ext = ""); virtual bool GetSaveFileNameInput(std::string& result, const std::string& prompt, const std::string& ext = "", const std::string& defaultName = ""); diff --git a/binaryninjacore.h b/binaryninjacore.h index 0461a16c..a92c7a09 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -2733,7 +2733,9 @@ extern "C" bool (*getAddressInput)(void* ctxt, uint64_t* result, const char* prompt, const char* title, BNBinaryView* view, uint64_t currentAddr); bool (*getChoiceInput)( - void* ctxt, size_t* result, const char* prompt, const char* title, const char** choices, size_t count); + void* ctxt, size_t* result, const char* prompt, const char* title, const char** choices, size_t count); + bool (*getLargeChoiceInput)( + void* ctxt, size_t* result, const char* prompt, const char* title, const char** choices, size_t count); bool (*getOpenFileNameInput)(void* ctxt, char** result, const char* prompt, const char* ext); bool (*getSaveFileNameInput)( void* ctxt, char** result, const char* prompt, const char* ext, const char* defaultName); @@ -6073,7 +6075,9 @@ extern "C" BINARYNINJACOREAPI bool BNGetAddressInput( uint64_t* result, const char* prompt, const char* title, BNBinaryView* view, uint64_t currentAddr); BINARYNINJACOREAPI bool BNGetChoiceInput( - size_t* result, const char* prompt, const char* title, const char** choices, size_t count); + size_t* result, const char* prompt, const char* title, const char** choices, size_t count); + BINARYNINJACOREAPI bool BNGetLargeChoiceInput( + size_t* result, const char* prompt, const char* title, const char** choices, size_t count); BINARYNINJACOREAPI bool BNGetOpenFileNameInput(char** result, const char* prompt, const char* ext); BINARYNINJACOREAPI bool BNGetSaveFileNameInput( char** result, const char* prompt, const char* ext, const char* defaultName); diff --git a/interaction.cpp b/interaction.cpp index 7bc1d2fa..037edca6 100644 --- a/interaction.cpp +++ b/interaction.cpp @@ -255,7 +255,7 @@ static bool GetAddressInputCallback( static bool GetChoiceInputCallback( - void* ctxt, size_t* result, const char* prompt, const char* title, const char** choices, size_t count) + void* ctxt, size_t* result, const char* prompt, const char* title, const char** choices, size_t count) { InteractionHandler* handler = (InteractionHandler*)ctxt; vector<string> choiceStrs; @@ -265,6 +265,17 @@ static bool GetChoiceInputCallback( } +static bool GetLargeChoiceInputCallback( + void* ctxt, size_t* result, const char* prompt, const char* title, const char** choices, size_t count) +{ + InteractionHandler* handler = (InteractionHandler*)ctxt; + vector<string> choiceStrs; + for (size_t i = 0; i < count; i++) + choiceStrs.push_back(choices[i]); + return handler->GetLargeChoiceInput(*result, prompt,title, choiceStrs); +} + + static bool GetOpenFileNameInputCallback(void* ctxt, char** result, const char* prompt, const char* ext) { InteractionHandler* handler = (InteractionHandler*)ctxt; @@ -445,6 +456,7 @@ void BinaryNinja::RegisterInteractionHandler(InteractionHandler* handler) cb.getIntegerInput = GetIntegerInputCallback; cb.getAddressInput = GetAddressInputCallback; cb.getChoiceInput = GetChoiceInputCallback; + cb.getLargeChoiceInput = GetLargeChoiceInputCallback; cb.getOpenFileNameInput = GetOpenFileNameInputCallback; cb.getSaveFileNameInput = GetSaveFileNameInputCallback; cb.getDirectoryNameInput = GetDirectoryNameInputCallback; @@ -533,6 +545,17 @@ bool BinaryNinja::GetChoiceInput(size_t& idx, const string& prompt, const string } +bool BinaryNinja::GetLargeChoiceInput(size_t& idx, const string& prompt, const string& title, const vector<string>& choices) +{ + const char** choiceStrs = new const char*[choices.size()]; + for (size_t i = 0; i < choices.size(); i++) + choiceStrs[i] = choices[i].c_str(); + bool ok = BNGetLargeChoiceInput(&idx, prompt.c_str(), title.c_str(), choiceStrs, choices.size()); + delete[] choiceStrs; + return ok; +} + + bool BinaryNinja::GetOpenFileNameInput(string& result, const string& prompt, const string& ext) { char* value = nullptr; diff --git a/python/interaction.py b/python/interaction.py index 123a095f..56d9a6fb 100644 --- a/python/interaction.py +++ b/python/interaction.py @@ -492,6 +492,7 @@ class InteractionHandler: self._cb.getIntegerInput = self._cb.getIntegerInput.__class__(self._get_int_input) self._cb.getAddressInput = self._cb.getAddressInput.__class__(self._get_address_input) self._cb.getChoiceInput = self._cb.getChoiceInput.__class__(self._get_choice_input) + self._cb.getLargeChoiceInput = self._cb.getLargeChoiceInput.__class__(self._get_large_choice_input) self._cb.getOpenFileNameInput = self._cb.getOpenFileNameInput.__class__(self._get_open_filename_input) self._cb.getSaveFileNameInput = self._cb.getSaveFileNameInput.__class__(self._get_save_filename_input) self._cb.getDirectoryNameInput = self._cb.getDirectoryNameInput.__class__(self._get_directory_name_input) @@ -597,6 +598,19 @@ class InteractionHandler: except: log_error(traceback.format_exc()) + def _get_large_choice_input(self, ctxt, result, prompt, title, choice_buf, count): + try: + choices = [] + for i in range(0, count): + choices.append(choice_buf[i]) + value = self.get_large_choice_input(prompt, title, choices) + if value is None: + return False + result[0] = value + return True + except: + log_error(traceback.format_exc()) + def _get_open_filename_input(self, ctxt, result, prompt, ext): try: value = self.get_open_filename_input(prompt, ext) @@ -760,6 +774,9 @@ class InteractionHandler: def get_choice_input(self, prompt, title, choices): return NotImplemented + def get_large_choice_input(self, prompt, title, choices): + return NotImplemented + def get_open_filename_input(self, prompt, ext): return get_text_line_input(prompt, "Open File") @@ -1215,6 +1232,30 @@ def get_choice_input(prompt, title, choices): return value.value +def get_large_choice_input(prompt, title, choices): + """ + ``get_large_choice_input`` prompts the user to select the one of the provided choices from a large pool + + .. note:: This API function differently on the command-line vs the UI. In the UI a pop-up is used. On the command-line \ + a text prompt is used. The UI uses a filterable list of entries + + :param str prompt: Text for the button when executed in the UI. Prompt shown for selection headless. + :param str title: Title of the window when executed in the UI. + :param choices: A list of strings for the user to choose from. + :type choices: list(str) + :rtype: integer array index of the selected option + :Example: + >>> get_large_choice_input("Select Function", "Select a Function", [f.symbol.short_name for f in bv.functions]) + """ + choice_buf = (ctypes.c_char_p * len(choices))() + for i in range(0, len(choices)): + choice_buf[i] = str(choices[i]).encode('charmap') + value = ctypes.c_ulonglong() + if not core.BNGetLargeChoiceInput(value, prompt, title, choice_buf, len(choices)): + return None + return value.value + + def get_open_filename_input(prompt: str, ext: str = "") -> Optional[str]: """ ``get_open_filename_input`` prompts the user for a file name to open diff --git a/ui/metadatachoicedialog.h b/ui/metadatachoicedialog.h index ed25f3e1..b34dccdc 100644 --- a/ui/metadatachoicedialog.h +++ b/ui/metadatachoicedialog.h @@ -43,7 +43,7 @@ public: }; // Model that is blind and queries info from its delegate. -class ManagedTableModel : public QAbstractTableModel +class BINARYNINJAUIAPI ManagedTableModel : public QAbstractTableModel { ManagedTableDelegate* m_delegate; @@ -228,8 +228,6 @@ class BINARYNINJAUIAPI MetadataChoiceDialog : public QDialog, public ManagedTabl protected: std::vector<EntryItem> m_entries; - - QHBoxLayout* m_midRowLayout; // ManagedTableDelegate @@ -297,11 +295,12 @@ protected: QPushButton* m_choose; bool ExtraFilterEnabled() { return m_extraFilter.exists && m_extraFilter.enabled; }; - +public: void AddWidthRequiredByItem(void* item, size_t widthRequired); void RemoveWidthRequiredByItem(QWidget* item); void AddHeightRequiredByItem(void* item, size_t widthRequired); void RemoveHeightRequiredByItem(QWidget* item); +protected: void UpdateMinimumSpace(); std::optional<EntryItem> m_chosenEntry; @@ -328,10 +327,11 @@ public: \param parent Parent Widget \param title Title of the dialog + \param prompt Text of the button to select a choice \param entries List of entries \param metadata Map of indices to the metadata for those entries. */ - MetadataChoiceDialog(QWidget* parent, const QString& title, const QStringList& entries, + MetadataChoiceDialog(QWidget* parent, const QString& title, const QString& prompt, const QStringList& entries, std::unordered_map<size_t, QString> metadata); /*! Create a choice selection dialog with a Title, list of entries, and pre-built set of metadata for those entries. @@ -343,10 +343,11 @@ public: \param parent Parent Widget \param title Title of the dialog + \param prompt Text of the button to select a choice \param entries List of entries \param metadata Map of indices to the metadata (as InstructionTextTokens) for those entries. */ - MetadataChoiceDialog(QWidget* parent, const QString& title, const QStringList& entries, + MetadataChoiceDialog(QWidget* parent, const QString& title, const QString& prompt, const QStringList& entries, std::unordered_map<size_t, std::vector<BinaryNinja::DisassemblyTextLine>> metadata); /*! Create a choice selection dialog with a Title and list of entries. @@ -355,12 +356,13 @@ public: \param parent Parent Widget \param title Title of the dialog + \param prompt Text of the button to select a choice \param entries List of entries */ - MetadataChoiceDialog(QWidget* parent, const QString& title, const QStringList& entries); + MetadataChoiceDialog(QWidget* parent, const QString& title, const QString& prompt, const QStringList& entries); - MetadataChoiceDialog(QWidget* parent, const QString& title) : - MetadataChoiceDialog(parent, title, {}) {} + MetadataChoiceDialog(QWidget* parent, const QString& title, const QString& prompt = "Select") : + MetadataChoiceDialog(parent, title, prompt, {}) {} /*! Set the callback the dialog will execute to retrieve metadata for a given item. |
