#pragma once #include #include #include #include #include #include #include "sidebar.h" #include "viewframe.h" #include "filter.h" #include "progresstask.h" #include "typeeditor.h" enum BINARYNINJAUIAPI TypeBrowserFilterMode { NamesOnly = 0, NamesAndMembers = 1, FullDefinitions = 2 }; class BINARYNINJAUIAPI TypeBrowserTreeNode : public std::enable_shared_from_this { public: struct UpdateData { enum UpdateType { NodeInserted, NodeUpdated, NodeRemoved, UpdatesFinished, }; UpdateType type; std::shared_ptr parent; std::shared_ptr node; std::function commit; }; typedef std::function UpdateNodeCallback; protected: class TypeBrowserModel* m_model; std::optional> m_parent; std::vector> m_children; std::map m_childIndices; bool m_hasGeneratedChildren; TypeBrowserTreeNode(class TypeBrowserModel* model, std::optional> parent); virtual ~TypeBrowserTreeNode() = default; virtual void generateChildren() = 0; void updateChildIndices(); void removeChild(std::shared_ptr child); void addChild(std::shared_ptr child); public: class TypeBrowserModel* model() const { return m_model; } std::optional> parent() const; const std::vector>& children(); int indexOfChild(std::shared_ptr child) const; virtual std::string text(int column) const = 0; virtual bool lessThan(const TypeBrowserTreeNode& other, int column) const = 0; virtual bool filter(const std::string& filter, TypeBrowserFilterMode mode) const = 0; virtual void updateChildren(bool recursive, UpdateNodeCallback update); }; class BINARYNINJAUIAPI EmptyTreeNode : public TypeBrowserTreeNode { public: EmptyTreeNode(class TypeBrowserModel* model, std::optional> parent); virtual ~EmptyTreeNode() = default; virtual std::string text(int column) const override; virtual bool lessThan(const TypeBrowserTreeNode& other, int column) const override; virtual bool filter(const std::string& filter, TypeBrowserFilterMode mode) const override; protected: virtual void generateChildren() override; virtual void updateChildren(bool recursive, UpdateNodeCallback update) override; }; class BINARYNINJAUIAPI RootTreeNode : public TypeBrowserTreeNode { std::map> m_containerNodes; public: RootTreeNode(class TypeBrowserModel* model, std::optional> parent); virtual ~RootTreeNode() = default; virtual std::string text(int column) const override; virtual bool lessThan(const TypeBrowserTreeNode& other, int column) const override; virtual bool filter(const std::string& filter, TypeBrowserFilterMode mode) const override; protected: virtual void generateChildren() override; virtual void updateChildren(bool recursive, UpdateNodeCallback update) override; }; class BINARYNINJAUIAPI TypeTreeNode : public TypeBrowserTreeNode { public: enum SourceType { None, TypeLibrary, DebugInfo, Platform, Other }; private: std::string m_id; BinaryNinja::QualifiedName m_name; TypeRef m_type; std::string m_sortName; SourceType m_sourceType; std::optional m_sourceLibrary; std::optional m_sourceDebugInfoParser; std::optional m_sourcePlatform; std::optional m_sourceOtherName; std::optional m_sourceOriginalName; public: TypeTreeNode(class TypeBrowserModel* model, std::optional> parent, const std::string& id, BinaryNinja::QualifiedName name, TypeRef type); virtual ~TypeTreeNode() = default; const std::string& id() const { return m_id; } const BinaryNinja::QualifiedName& name() const { return m_name; } const TypeRef& type() const { return m_type; } void setType(const std::string& id, const BinaryNinja::QualifiedName& name, const TypeRef& type); const SourceType& sourceType() const { return m_sourceType; } std::optional typeContainer() const; std::optional sourceTypeContainer() const; PlatformRef sourcePlatform() const; virtual std::string text(int column) const override; virtual bool lessThan(const TypeBrowserTreeNode& other, int column) const override; virtual bool filter(const std::string& filter, TypeBrowserFilterMode mode) const override; protected: virtual void generateChildren() override; }; class BINARYNINJAUIAPI TypeContainerTreeNode : public TypeBrowserTreeNode { std::string m_containerId; // TODO: Gross std::map, std::shared_ptr>> m_typeNodes; public: TypeContainerTreeNode(class TypeBrowserModel* model, std::optional> parent, const std::string& m_containerId); virtual ~TypeContainerTreeNode(); virtual std::string text(int column) const override; virtual bool filter(const std::string& filter, TypeBrowserFilterMode mode) const override; virtual bool lessThan(const TypeBrowserTreeNode& other, int column) const override; const std::string& containerId() const { return m_containerId; } std::optional platform() const; std::optional typeContainer() const; std::optional containerType() const; virtual void updateChildren(bool recursive, UpdateNodeCallback update) override; protected: virtual void generateChildren() override; }; //----------------------------------------------------------------------------- class BINARYNINJAUIAPI TypeBrowserModel : public QAbstractItemModel, public BinaryNinja::BinaryDataNotification { Q_OBJECT BinaryViewRef m_data; std::shared_ptr m_rootNode; mutable std::recursive_mutex m_rootNodeMutex; bool m_needsUpdate; bool m_updating; std::recursive_mutex m_updateMutex; std::vector> m_updateCallbacks; std::vector m_containerIds; std::map m_containerNames; std::map m_containerTypes; std::map m_containers; std::map m_containerViews; std::map m_containerLibraries; std::map m_containerDebugInfos; std::map m_containerPlatforms; void updateContainerList(); void callUpdateCallbacks(); void commitUpdates(std::vector& updates); public: TypeBrowserModel(BinaryViewRef data); virtual ~TypeBrowserModel(); BinaryViewRef getData() { return m_data; } std::shared_ptr getRootNode() { return m_rootNode; } std::vector containerIds() const; std::string nameForContainerId(const std::string& id) const; std::optional> containerForContainerId(const std::string& id); std::optional> containerForContainerId(const std::string& id) const; std::optional viewForContainerId(const std::string& id) const; std::optional libraryForContainerId(const std::string& id) const; std::optional debugInfoForContainerId(const std::string& id) const; std::optional platformForContainerId(const std::string& id) const; void updateFonts(); void runAfterUpdate(std::function callback); int columnCount(const QModelIndex& parent = QModelIndex()) const override; int rowCount(const QModelIndex& parent = QModelIndex()) const override; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; QModelIndex parent(const QModelIndex& child) const override; QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; std::shared_ptr nodeForIndex(const QModelIndex& index) const; QModelIndex indexForNode(std::shared_ptr node, int column = 0) const; std::vector> containerNodes() const; bool filter(const QModelIndex& index, const std::string& filter, TypeBrowserFilterMode mode) const; bool lessThan(const QModelIndex& left, const QModelIndex& right) const; void OnTypeDefined(BinaryNinja::BinaryView* data, const BinaryNinja::QualifiedName& name, BinaryNinja::Type* type) override; void OnTypeUndefined(BinaryNinja::BinaryView* data, const BinaryNinja::QualifiedName& name, BinaryNinja::Type* type) override; void OnTypeReferenceChanged(BinaryNinja::BinaryView* data, const BinaryNinja::QualifiedName& name, BinaryNinja::Type* type) override; void OnTypeFieldReferenceChanged(BinaryNinja::BinaryView* data, const BinaryNinja::QualifiedName& name, uint64_t offset) override; Q_SIGNALS: void updatesAboutToHappen(); void updateComplete(); public Q_SLOTS: void markDirty(); void notifyRefresh(); }; class BINARYNINJAUIAPI TypeBrowserFilterModel : public QSortFilterProxyModel { Q_OBJECT BinaryViewRef m_data; TypeBrowserModel* m_model; std::string m_filter; TypeBrowserFilterMode m_filterMode; protected: bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override; bool lessThan(const QModelIndex& source_left, const QModelIndex& source_right) const override; public: TypeBrowserFilterModel(BinaryViewRef data, TypeBrowserModel* model); void setFilter(const std::string& filter); TypeBrowserFilterMode filterMode() const { return m_filterMode; } void setFilterMode(TypeBrowserFilterMode newMode) { m_filterMode = newMode; } Q_SIGNALS: void filterAboutToBeChanged(); void filterChanged(); }; class BINARYNINJAUIAPI TypeBrowserItemDelegate : public QItemDelegate { QFont m_font; QFont m_monospaceFont; float m_charWidth, m_charHeight, m_charOffset; float m_baseline; class TypeBrowserView* m_view; void initFont(); public: TypeBrowserItemDelegate(class TypeBrowserView* view); void updateFonts(); virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override; virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override; }; class BINARYNINJAUIAPI TypeBrowserTreeView : public QTreeView { Q_OBJECT UIActionHandler m_actionHandler; public: explicit TypeBrowserTreeView(class TypeBrowserView* parent); }; struct BINARYNINJAUIAPI TypeReference { std::string containerId; BinaryNinja::QualifiedName typeName; TypeReference() = default; TypeReference(std::string containerId, BinaryNinja::QualifiedName typeName); }; class BINARYNINJAUIAPI TypeBrowserView : public QFrame, public View, public FilterTarget { Q_OBJECT ViewFrame* m_frame; BinaryViewRef m_data; class TypeBrowserContainer* m_container; ContextMenuManager* m_contextMenuManager; QSplitter* m_splitter; TypeBrowserModel* m_model; TypeBrowserFilterModel* m_filterModel; QStandardItemModel* m_loadingModel; QTreeView* m_tree; TypeBrowserItemDelegate* m_delegate; bool m_updatedWidths; bool m_navigateToNextInsert; QModelIndex m_lastPosition; QModelIndex m_lastInsert; TypeEditor::SavedCursorPosition m_editorPosition; TypeEditor* m_typeEditor; QTextEdit* m_debugText; public: TypeBrowserView(ViewFrame* frame, BinaryViewRef data, TypeBrowserContainer* container); TypeBrowserContainer* getContainer() { return m_container; } TypeBrowserModel* getModel() { return m_model; } TypeBrowserFilterModel* getFilterModel() { return m_filterModel; } QTreeView* getTreeView() { return m_tree; } TypeEditor* getTypeEditor() { return m_typeEditor; } virtual BinaryViewRef getData() override { return m_data; } virtual uint64_t getCurrentOffset() override; virtual void setSelectionOffsets(BNAddressRange range) override; virtual bool navigate(uint64_t offset) override; virtual SelectionInfoForXref getSelectionForXref() override; virtual QFont getFont() override; virtual void updateFonts() override; virtual void showEvent(QShowEvent* event) override; virtual void hideEvent(QHideEvent* event) override; virtual void resizeEvent(QResizeEvent* event) override; virtual StatusBarWidget* getStatusBarWidget() override; virtual QWidget* getHeaderOptionsWidget() override; virtual void setFilter(const std::string& filter) override; virtual void scrollToFirstItem() override; virtual void scrollToCurrentItem() override; virtual void selectFirstItem() override; virtual void activateFirstItem() override; virtual void notifyRefresh() override; void showSelectedTypes(); void showTypes(const std::vector& types); void selectTypeByName(const std::string& name, bool newSelection); bool navigateToType(const std::string& typeName, uint64_t offset); void scrollToIndexWithContext(const QModelIndex& index, int context = 1); // Selection helpers // All nodes std::vector> selectedNodes() const; // BV selected or BV relevant to selected types, only if JUST bv stuff is selected std::optional selectedBV() const; // If selectedBV exists, names of selected types std::optional> selectedBVTypeNames() const; std::optional> selectedTypeNameAndContainer() const; // All selected type names, grouped by type container std::vector>> selectedTypeNamesByContainers() const; // Selected type reference std::optional selectedType() const; // Selected type references std::vector selectedTypes() const; // Selected type container, or container of selected type // makeSureItHasPlatform: if the type container is a BV with no platform (raw), ask for one and return nullopt if rejected // preferView: if the type container is a BV and the user/auto-only container, switch to the whole-view container for that BV instead std::optional selectedTypeContainer(bool makeSureItHasPlatform = true, bool preferView = false) const; // Names -> Ids, if any don't exist then nullopt static std::optional> typeIdsFromNames(BinaryViewRef view, const std::unordered_set& names); std::optional> containerForId(const std::string& containerId, bool makeSureItHasPlatform = false, bool preferView = false); // Menu actions static void registerActions(); void bindActions(); void showContextMenu(); bool canCreateNewTypes(); void createNewTypes(); bool canCreateNewStructure(); void createNewStructure(); bool canCreateNewEnumeration(); void createNewEnumeration(); bool canCreateNewUnion(); void createNewUnion(); bool canRenameTypes(); void renameTypes(); bool canDeleteTypes(); void deleteTypes(); bool canChangeTypes(); void changeTypes(); bool canImportType(); void importType(); bool canAddTypeLibrary(); void addTypeLibrary(); bool canExpandAll(); void expandAll(); bool canCollapseAll(); void collapseAll(); Q_SIGNALS: void typeNameNavigated(const std::string& typeName, bool newSelection); protected: void itemSelected(const QItemSelection& selected, const QItemSelection& deselected); void itemDoubleClicked(const QModelIndex& index); virtual void contextMenuEvent(QContextMenuEvent* event) override; }; class BINARYNINJAUIAPI TypeBrowserOptionsIconWidget : public QWidget { public: TypeBrowserOptionsIconWidget(TypeBrowserView* parent); private: TypeBrowserView* m_view; void showMenu(); }; class BINARYNINJAUIAPI TypeBrowserContainer : public QWidget, public ViewContainer { Q_OBJECT ViewFrame* m_frame; BinaryViewRef m_data; TypeBrowserView* m_view; FilteredView* m_filter; FilterEdit* m_separateEdit; class TypeBrowserSidebarWidget* m_sidebarWidget; UIActionHandler m_actionHandler; public: TypeBrowserContainer(ViewFrame* frame, BinaryViewRef data, class TypeBrowserSidebarWidget* parent); virtual View* getView() override { return m_view; } ViewFrame* getViewFrame() { return m_frame; } BinaryViewRef getData() { return m_data; } TypeBrowserView* getTypeBrowserView() { return m_view; } FilteredView* getFilter() { return m_filter; } FilterEdit* getSeparateFilterEdit() { return m_separateEdit; } class TypeBrowserSidebarWidget* getSidebarWidget() { return m_sidebarWidget; } void showContextMenu(); protected: virtual void focusInEvent(QFocusEvent* event) override; }; class BINARYNINJAUIAPI TypeBrowserViewType : public ViewType { static TypeBrowserViewType* g_instance; public: TypeBrowserViewType(); virtual int getPriority(BinaryViewRef data, const QString& filename) override; virtual QWidget* create(BinaryViewRef data, ViewFrame* frame) override; static void init(); }; class BINARYNINJAUIAPI TypeBrowserSidebarWidget : public SidebarWidget { Q_OBJECT QWidget* m_header; TypeBrowserContainer* m_container; public: TypeBrowserSidebarWidget(ViewFrame* frame, BinaryViewRef data); TypeBrowserContainer* container() { return m_container; } virtual QWidget* headerWidget() override { return m_header; } virtual void focus() override; protected: virtual void contextMenuEvent(QContextMenuEvent* event) override; private Q_SLOTS: void showContextMenu(); }; class BINARYNINJAUIAPI TypeBrowserSidebarWidgetType : public SidebarWidgetType { public: TypeBrowserSidebarWidgetType(); virtual SidebarWidget* createWidget(ViewFrame* frame, BinaryViewRef data) override; };