forked from Vector35/binaryninja-api
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearchresult.h
347 lines (285 loc) · 9.4 KB
/
searchresult.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
#pragma once
#include <QtCore/QAbstractItemModel>
#include <QtCore/QItemSelectionModel>
#include <QtCore/QSortFilterProxyModel>
#include <QtCore/QModelIndex>
#include <QtCore/QThread>
#include <QtWidgets/QTableView>
#include <QtWidgets/QTabWidget>
#include <QtWidgets/QStyledItemDelegate>
#include <QtWidgets/QDialog>
#include <QtWidgets/QProgressBar>
#include <QtWidgets/QToolButton>
#include "binaryninjaapi.h"
#include "filter.h"
#include "expandablegroup.h"
#include "sidebar.h"
#include "tabwidget.h"
#define FIND_RESULT_LIST_UPDATE_INTERVAL 250
#define COLUMN_MIN_WIDTH_IN_CHAR 10
#define COLUMN_MAX_WIDTH_IN_CHAR 30
/*!
\defgroup searchreult SearchResult
\ingroup uiapi
*/
/*!
\ingroup searchresult
*/
class CachedTokens
{
public:
QVariant tokens;
QVariant flattenedTokens;
bool valid;
CachedTokens() : valid(false) {}
CachedTokens(const CachedTokens& other) :
tokens(other.tokens), flattenedTokens(other.flattenedTokens), valid(other.valid)
{}
};
/*!
\ingroup searchresult
*/
class SearchResultItem
{
private:
uint64_t m_addr;
BinaryNinja::DataBuffer m_buffer;
FunctionRef m_func;
CachedTokens m_tokensCache[4];
public:
SearchResultItem();
SearchResultItem(uint64_t addr, const BinaryNinja::DataBuffer& buffer, FunctionRef func);
SearchResultItem(uint64_t addr, const BinaryNinja::DataBuffer& buffer, FunctionRef func,
const BinaryNinja::DisassemblyTextLine& line, QWidget* owner);
SearchResultItem(const SearchResultItem& other);
uint64_t addr() const { return m_addr; }
BinaryNinja::DataBuffer buffer() const { return m_buffer; }
FunctionRef func() const { return m_func; }
bool operator==(const SearchResultItem& other) const { return m_addr == other.addr(); }
bool operator!=(const SearchResultItem& other) const { return m_addr != other.addr(); }
bool operator<(const SearchResultItem& other) const { return m_addr < other.addr(); }
CachedTokens getCachedTokens(size_t i) const;
CachedTokens& getCachedTokens(size_t i);
void setCachedTokens(size_t i, QVariant tokens, QVariant flattenedTokens);
};
Q_DECLARE_METATYPE(SearchResultItem);
/*!
\ingroup searchresult
*/
class BINARYNINJAUIAPI SearchResultModel : public QAbstractTableModel
{
Q_OBJECT
protected:
QWidget* m_owner;
BinaryViewRef m_data;
BinaryNinja::FindParameters m_params;
std::vector<SearchResultItem> m_refs;
mutable size_t m_columnWidths[4];
// if this value is true, it means the user has overriden the automatically calculated width
// of the coumn, and we should not resize it anymore
bool m_userColumnWidth[4];
std::mutex m_updateMutex;
std::set<SearchResultItem> m_pendingSearchResults;
public:
enum ColumnHeaders
{
AddressColumn = 0,
DataColumn = 1,
FunctionColumn = 2,
PreviewColumn = 3,
EndOfColumn = 4
};
SearchResultModel(QWidget* parent, BinaryViewRef data);
virtual ~SearchResultModel();
virtual QModelIndex index(int row, int col, const QModelIndex& parent = QModelIndex()) const override;
void reset();
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override
{
(void)parent;
return (int)m_refs.size();
}
virtual int columnCount(const QModelIndex& parent = QModelIndex()) const override
{
(void)parent;
return 4;
}
SearchResultItem getRow(int row) const;
virtual QVariant data(const QModelIndex& i, int role) const override;
virtual QVariant headerData(int column, Qt::Orientation orientation, int role) const override;
void addItem(const SearchResultItem& addr);
void clear();
void updateFindParameters(const BinaryNinja::FindParameters params);
void updateSearchResults();
size_t getColumnWidth(size_t column) const;
// This function is marked as const, but it actually modifies the mutable member m_columnWidths.
// It is called in SearchResultModel::data(), which is const. So it has to be const as well.
void updateColumnWidth(size_t column, size_t size) const;
void resetColumnWidth();
bool isUserColumnWidth(size_t column) const;
void setUserColumnWidth(size_t column);
};
/*!
\ingroup searchresult
*/
class BINARYNINJAUIAPI SearchResultFilterProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
SearchResultFilterProxyModel(QObject* parent);
virtual bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override;
virtual bool lessThan(const QModelIndex& left, const QModelIndex& right) const override;
virtual QVariant data(const QModelIndex& idx, int role) const override;
};
/*!
\ingroup searchresult
*/
class BINARYNINJAUIAPI SearchResultItemDelegate : public QStyledItemDelegate
{
Q_OBJECT
QFont m_font;
int m_baseline, m_charWidth, m_charHeight, m_charOffset;
public:
SearchResultItemDelegate(QWidget* parent);
void updateFonts();
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& idx) const;
};
class SearchResultWidget;
/*!
\ingroup searchresult
*/
class BINARYNINJAUIAPI SearchResultTable : public QTableView
{
Q_OBJECT
SearchResultModel* m_table;
SearchResultFilterProxyModel* m_model;
SearchResultItemDelegate* m_itemDelegate;
BinaryViewRef m_data;
BinaryNinja::FindParameters m_params;
UIActionHandler m_actionHandler;
QTimer* m_updateTimer;
bool m_ignoreColumnResize = true;
int m_charWidth, m_charHeight;
bool m_cacheThreadShouldExit;
public:
SearchResultTable(SearchResultWidget* parent, BinaryViewRef data);
virtual ~SearchResultTable();
void addSearchResult(const SearchResultItem& addr);
void updateFindParameters(const BinaryNinja::FindParameters& params);
void clearSearchResult();
void updateFonts();
void updateHeaderFontAndSize();
virtual QSize sizeHint() const override;
virtual void keyPressEvent(QKeyEvent* e) override;
virtual bool hasSelection() const { return selectionModel()->selectedRows().size() != 0; }
virtual QModelIndexList selectedRows() const { return selectionModel()->selectedRows(); }
void goToResult(const QModelIndex& idx);
int rowCount() const;
int filteredCount() const;
void updateColumnWidth();
void resetColumnWidth();
void cacheTokens();
void terminateCacheThread() { m_cacheThreadShouldExit = true; }
SearchResultModel* model() const { return m_table; }
void StopTimer();
void copy();
public Q_SLOTS:
void resultActivated(const QModelIndex& idx);
void updateFilter(const QString& filterText);
void updateTimerEvent();
void columnResized(int logicalIndex, int oldSize, int newSize);
Q_SIGNALS:
void newSelection();
};
class SearchProgressBar;
/*!
\ingroup searchresult
*/
class BINARYNINJAUIAPI SearchResultWidget : public SidebarWidget
{
Q_OBJECT
UIActionHandler m_actionHandler;
ContextMenuManager* m_contextMenuManager = nullptr;
Menu* m_menu = nullptr;
BinaryViewRef m_data;
SearchResultTable* m_table;
QLabel* m_label;
QLineEdit* m_lineEdit;
ExpandableGroup* m_group;
SearchProgressBar* m_progress;
BinaryNinja::FindParameters m_params;
QThread* m_tokenCacheThread = nullptr;
virtual void contextMenuEvent(QContextMenuEvent* event) override;
public:
SearchResultWidget(BinaryViewRef data, const QString& title);
~SearchResultWidget();
void notifyFontChanged() override;
void startNewFind(const BinaryNinja::FindParameters& params);
virtual QString getHeaderText();
void addSearchResult(uint64_t addr, const BinaryNinja::DataBuffer& match);
void addSearchResult(
uint64_t addr, const BinaryNinja::DataBuffer& match, const BinaryNinja::LinearDisassemblyLine& line);
void clearSearchResult();
bool updateProgress(uint64_t cur, uint64_t total);
void notifySearchCompleted();
void cacheTokens();
void terminateCacheThread();
bool isSearchActive() const;
public Q_SLOTS:
void updateTotal();
};
/*!
\ingroup searchresult
*/
class BINARYNINJAUIAPI SearchProgressBar : public QWidget
{
Q_OBJECT
private:
QProgressBar* m_progress;
QToolButton* m_cancel;
bool m_maxSet;
bool m_running;
// The minimal duration (in milliseconds) the progress bar must last, before it is displayed
int m_minimalDuration;
std::chrono::steady_clock::time_point m_lastUpdate;
public:
explicit SearchProgressBar(QWidget* parent = nullptr);
bool updateProgress(uint64_t cur, uint64_t total);
void init();
void reset();
void show();
bool isRunning() const { return m_running; }
};
/*!
\ingroup searchresult
*/
class BINARYNINJAUIAPI SearchResultHeaderWidget : public QWidget, public FilterTarget
{
Q_OBJECT
QLineEdit* m_search;
QComboBox* m_mode;
ClickableIcon* m_caseSensitive;
public:
SearchResultHeaderWidget();
virtual void setFilter(const std::string&) override {}
virtual void scrollToFirstItem() override {}
virtual void scrollToCurrentItem() override {}
virtual void selectFirstItem() override {}
virtual void activateFirstItem() override;
protected:
virtual void keyPressEvent(QKeyEvent* e) override;
};
/*!
\ingroup searchresult
*/
class BINARYNINJAUIAPI SearchResultSidebarWidgetType : public SidebarWidgetType
{
public:
SearchResultSidebarWidgetType();
SidebarWidgetLocation defaultLocation() const override { return SidebarWidgetLocation::RightBottom; }
SidebarContextSensitivity contextSensitivity() const override { return PerViewTypeSidebarContext; }
bool alwaysShowTabs() const override { return true; }
virtual QString noWidgetMessage() const override { return "No search active"; }
virtual QWidget* headerWidget(SplitPaneWidget* panes, ViewFrame* frame, BinaryViewRef data) override;
virtual bool focusHeaderWidget() const override { return true; }
virtual DockableTabStyle* tabStyle() const override { return new DefaultDockableTabStyle(); }
};