summaryrefslogtreecommitdiff
path: root/ui
diff options
context:
space:
mode:
authorBrian Potchik <brian@vector35.com>2025-09-30 15:09:48 -0400
committerBrian Potchik <brian@vector35.com>2025-09-30 15:09:48 -0400
commit796932b62e7d007a46d8ad31cdb618e8125073ab (patch)
tree35937ae27a646cc6a1d7e79cafd4b46b0991a0b1 /ui
parent36a06931b3eac492eb1e609949e2cc5a3a03bf57 (diff)
Initial support for opening container formats.
Diffstat (limited to 'ui')
-rw-r--r--ui/containerbrowser.h106
-rw-r--r--ui/options.h2
-rw-r--r--ui/uitypes.h2
3 files changed, 109 insertions, 1 deletions
diff --git a/ui/containerbrowser.h b/ui/containerbrowser.h
new file mode 100644
index 00000000..8dddad0a
--- /dev/null
+++ b/ui/containerbrowser.h
@@ -0,0 +1,106 @@
+#pragma once
+
+#include <QDialog>
+#include <QStringList>
+#include <QLineEdit>
+#include <QTreeView>
+#include <QPlainTextEdit>
+#include <QLabel>
+#include <QDialogButtonBox>
+#include <QModelIndex>
+
+#include "binaryninjaapi.h"
+#include "uitypes.h"
+
+#include <vector>
+
+
+class ContainerTreeModel : public QAbstractItemModel
+{
+ Q_OBJECT
+
+public:
+ enum Columns { ColName, ColType, ColSize, ColPath, ColCount };
+
+ explicit ContainerTreeModel(TransformSessionRef session, QObject* parent = nullptr);
+
+ // QAbstractItemModel interface
+ int columnCount(const QModelIndex& parent = {}) const override;
+ QModelIndex index(int row, int column, const QModelIndex& parent = {}) const override;
+ QModelIndex parent(const QModelIndex& child) const override;
+ int rowCount(const QModelIndex& parent = {}) const override;
+ QVariant data(const QModelIndex& index, int role) const override;
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
+ Qt::ItemFlags flags(const QModelIndex& index) const override;
+
+ // Public helpers for the dialog
+ bool isLeaf(const QModelIndex& index) const;
+ QStringList pathFor(const QModelIndex& index) const;
+ void selectNode(const QModelIndex& index);
+ void rebuild();
+
+private:
+ struct Node
+ {
+ QString displayName; // GetFileName() (or synthesized for root)
+ QString type; // GetTransformName() or "Leaf"/"Root"
+ QString breadcrumb; // human-readable path "a ▸ b ▸ c"
+ QStringList pathSegments; // list of filenames from root to this node
+ quint64 size = 0; // not exposed (kept for future metadata)
+ bool isLeaf = false;
+ bool selectable = true; // we allow selection only on leaves
+ TransformContextRef ctx;
+ Node* parent = nullptr;
+ std::vector<std::unique_ptr<Node>> children;
+ };
+
+ const Node* nodeFromIndex(const QModelIndex& index) const;
+ static QString joinBreadcrumb(const QStringList& segments);
+ void buildChildren(Node* parentNode, const TransformContextRef& ctx, const QStringList& parentSegments);
+
+ TransformSessionRef m_session;
+ std::unique_ptr<Node> m_root;
+};
+
+
+class AllColumnsFilterProxyModel : public QSortFilterProxyModel
+{
+ Q_OBJECT
+
+public:
+ explicit AllColumnsFilterProxyModel(QObject* parent = nullptr);
+
+protected:
+ bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override;
+};
+
+
+class BINARYNINJAUIAPI ContainerBrowser : public QDialog
+{
+ Q_OBJECT
+
+ TransformSessionRef m_session;
+
+ ContainerTreeModel* m_model;
+
+ QLineEdit* m_filter = nullptr;
+ QTreeView* m_tree = nullptr;
+ QPlainTextEdit* m_preview = nullptr;
+ QLabel* m_status = nullptr;
+ QDialogButtonBox* m_buttons = nullptr;
+ AllColumnsFilterProxyModel* m_proxy = nullptr;
+
+ QStringList m_selectedPaths;
+
+ void connectSignals();
+ void loadRoot();
+ void updatePreviewForIndex(const QModelIndex& proxyIndex);
+ static QString toHexDump(const QByteArray& data, int bytesPerLine = 16);
+
+public:
+ ContainerBrowser(TransformSessionRef session, QWidget* parent = nullptr);
+
+ QStringList selectedPaths() const { return m_selectedPaths; }
+
+ static BinaryViewRef openContainerFile(const QString& path);
+};
diff --git a/ui/options.h b/ui/options.h
index 3206fc7e..764cb85c 100644
--- a/ui/options.h
+++ b/ui/options.h
@@ -53,7 +53,7 @@ class BINARYNINJAUIAPI OptionsDialog : public QDialog
public:
OptionsDialog(QWidget* parent, const QString& name);
virtual ~OptionsDialog();
- bool loadViews();
+ bool loadViews(BinaryViewRef existingView = nullptr);
Q_SIGNALS:
void openFile(FileContext* file);
diff --git a/ui/uitypes.h b/ui/uitypes.h
index 476c0d79..89fa43e6 100644
--- a/ui/uitypes.h
+++ b/ui/uitypes.h
@@ -108,6 +108,8 @@ typedef BinaryNinja::Ref<BinaryNinja::Tag> TagRef;
typedef BinaryNinja::Ref<BinaryNinja::TagType> TagTypeRef;
typedef BinaryNinja::Ref<BinaryNinja::TemporaryFile> TemporaryFileRef;
typedef BinaryNinja::Ref<BinaryNinja::Transform> TransformRef;
+typedef BinaryNinja::Ref<BinaryNinja::TransformContext> TransformContextRef;
+typedef BinaryNinja::Ref<BinaryNinja::TransformSession> TransformSessionRef;
typedef BinaryNinja::Ref<BinaryNinja::Type> TypeRef;
typedef BinaryNinja::Ref<BinaryNinja::TypeArchive> TypeArchiveRef;
typedef BinaryNinja::Ref<BinaryNinja::TypeLibrary> TypeLibraryRef;