aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStig Bjørlykke <stig@bjorlykke.org>2016-02-16 22:34:12 +0100
committerStig Bjørlykke <stig@bjorlykke.org>2016-02-18 08:06:46 +0000
commit30d83e089c2f0b5d5d67892c6fc581ba9ce0a0a5 (patch)
treed746f24099cf6bdf108e9f64fc1aaf8df5bdd8fc
parentb77ffb9d36a9405943dadce3d4849c1106b2e361 (diff)
Qt: Add regex support in Find Packet
Add support for using regular expressions in the Search Frame when searching in packet list, packet details and packet bytes. This search is in many cases faster than plain string search. Change-Id: I2d8a709046f90d7b278fb39547fc4e2e420623bc Reviewed-on: https://code.wireshark.org/review/13981 Petri-Dish: Stig Bjørlykke <stig@bjorlykke.org> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Stig Bjørlykke <stig@bjorlykke.org>
-rw-r--r--cfile.h1
-rw-r--r--docbook/release-notes.asciidoc1
-rw-r--r--file.c103
-rw-r--r--ui/gtk/find_dlg.c1
-rw-r--r--ui/qt/search_frame.cpp68
-rw-r--r--ui/qt/search_frame.h4
-rw-r--r--ui/qt/search_frame.ui7
7 files changed, 146 insertions, 39 deletions
diff --git a/cfile.h b/cfile.h
index 5d40dd8ce1..7c270608f8 100644
--- a/cfile.h
+++ b/cfile.h
@@ -103,6 +103,7 @@ typedef struct _capture_file {
gboolean packet_data; /* TRUE if "String" search in "Packet data" was last selected */
guint32 search_pos; /* Byte position of last byte found in a hex search */
gboolean case_type; /* TRUE if case-insensitive text search */
+ GRegex *regex; /* Set if regular expression search */
search_charset_t scs_type; /* Character set for text search */
search_direction dir; /* Direction in which to do searches */
gboolean search_in_progress; /* TRUE if user just clicked OK in the Find dialog or hit <control>N/B */
diff --git a/docbook/release-notes.asciidoc b/docbook/release-notes.asciidoc
index 3243c621c3..179809fe3a 100644
--- a/docbook/release-notes.asciidoc
+++ b/docbook/release-notes.asciidoc
@@ -28,6 +28,7 @@ since version 2.0.0:
** You can now switch between between Capture and File Format dissection of
the current capture file via the View menu in the Qt GUI.
** You can now show selected packet bytes as ASCII, HTML, Image, ISO 8859-1, Raw or UTF-8.
+** You can now use regular expressions in Find Packet.
//=== Removed Dissectors
diff --git a/file.c b/file.c
index f576cb8d25..10290dd2c8 100644
--- a/file.c
+++ b/file.c
@@ -118,6 +118,8 @@ static match_result match_wide(capture_file *cf, frame_data *fdata,
void *criterion);
static match_result match_binary(capture_file *cf, frame_data *fdata,
void *criterion);
+static match_result match_regex(capture_file *cf, frame_data *fdata,
+ void *criterion);
static match_result match_dfilter(capture_file *cf, frame_data *fdata,
void *criterion);
static match_result match_marked(capture_file *cf, frame_data *fdata,
@@ -2896,22 +2898,30 @@ match_subtree_text(proto_node *node, gpointer data)
proto_item_fill_label(fi, label_str);
}
- /* Does that label match? */
- label_len = strlen(label_ptr);
- for (i = 0; i < label_len; i++) {
- c_char = label_ptr[i];
- if (cf->case_type)
- c_char = g_ascii_toupper(c_char);
- if (c_char == string[c_match]) {
- c_match++;
- if (c_match == string_len) {
- /* No need to look further; we have a match */
- mdata->frame_matched = TRUE;
- mdata->finfo = fi;
- return;
- }
- } else
- c_match = 0;
+ if (cf->regex) {
+ if (g_regex_match(cf->regex, label_ptr, (GRegexMatchFlags) 0, NULL)) {
+ mdata->frame_matched = TRUE;
+ mdata->finfo = fi;
+ return;
+ }
+ } else {
+ /* Does that label match? */
+ label_len = strlen(label_ptr);
+ for (i = 0; i < label_len; i++) {
+ c_char = label_ptr[i];
+ if (cf->case_type)
+ c_char = g_ascii_toupper(c_char);
+ if (c_char == string[c_match]) {
+ c_match++;
+ if (c_match == string_len) {
+ /* No need to look further; we have a match */
+ mdata->frame_matched = TRUE;
+ mdata->finfo = fi;
+ return;
+ }
+ } else
+ c_match = 0;
+ }
}
/* Recurse into the subtree, if it exists */
@@ -2963,18 +2973,25 @@ match_summary_line(capture_file *cf, frame_data *fdata, void *criterion)
/* Found it. See if we match. */
info_column = edt.pi.cinfo->columns[colx].col_data;
info_column_len = strlen(info_column);
- for (i = 0; i < info_column_len; i++) {
- c_char = info_column[i];
- if (cf->case_type)
- c_char = g_ascii_toupper(c_char);
- if (c_char == string[c_match]) {
- c_match++;
- if (c_match == string_len) {
- result = MR_MATCHED;
- break;
- }
- } else
- c_match = 0;
+ if (cf->regex) {
+ if (g_regex_match(cf->regex, info_column, (GRegexMatchFlags) 0, NULL)) {
+ result = MR_MATCHED;
+ break;
+ }
+ } else {
+ for (i = 0; i < info_column_len; i++) {
+ c_char = info_column[i];
+ if (cf->case_type)
+ c_char = g_ascii_toupper(c_char);
+ if (c_char == string[c_match]) {
+ c_match++;
+ if (c_match == string_len) {
+ result = MR_MATCHED;
+ break;
+ }
+ } else
+ c_match = 0;
+ }
}
break;
}
@@ -3008,8 +3025,11 @@ cf_find_packet_data(capture_file *cf, const guint8 *string, size_t string_size,
info.data = string;
info.data_len = string_size;
- /* String or hex search? */
- if (cf->string) {
+ /* Regex, String or hex search? */
+ if (cf->regex) {
+ /* Regular Expression search */
+ return find_packet(cf, match_regex, NULL, dir);
+ } else if (cf->string) {
/* String search - what type of string? */
switch (cf->scs_type) {
@@ -3214,6 +3234,29 @@ match_binary(capture_file *cf, frame_data *fdata, void *criterion)
return result;
}
+static match_result
+match_regex(capture_file *cf, frame_data *fdata, void *criterion _U_)
+{
+ match_result result = MR_NOTMATCHED;
+ GMatchInfo *match_info = NULL;
+
+ /* Load the frame's data. */
+ if (!cf_read_record(cf, fdata)) {
+ /* Attempt to get the packet failed. */
+ return MR_ERROR;
+ }
+
+ if (g_regex_match_full(cf->regex, ws_buffer_start_ptr(&cf->buf), fdata->cap_len,
+ 0, (GRegexMatchFlags) 0, &match_info, NULL))
+ {
+ gint start_pos = 0, end_pos = 0;
+ g_match_info_fetch_pos (match_info, 0, &start_pos, &end_pos);
+ cf->search_pos = end_pos; /* TODO: use start_pos to show correct length for regex */
+ result = MR_MATCHED;
+ }
+ return result;
+}
+
gboolean
cf_find_packet_dfilter(capture_file *cf, dfilter_t *sfcode,
search_direction dir)
diff --git a/ui/gtk/find_dlg.c b/ui/gtk/find_dlg.c
index 1d3c7b59a5..7b85f07f7e 100644
--- a/ui/gtk/find_dlg.c
+++ b/ui/gtk/find_dlg.c
@@ -653,6 +653,7 @@ find_frame_ok_cb(GtkWidget *ok_bt _U_, gpointer parent_w)
cfile.string = string_search;
cfile.scs_type = scs_type;
cfile.case_type = case_type;
+ cfile.regex = NULL;
cfile.packet_data = packet_data;
cfile.decode_data = decode_data;
cfile.summary_data = summary_data;
diff --git a/ui/qt/search_frame.cpp b/ui/qt/search_frame.cpp
index 6fe3f2de03..c0c7f13c64 100644
--- a/ui/qt/search_frame.cpp
+++ b/ui/qt/search_frame.cpp
@@ -40,7 +40,8 @@ enum {
enum {
df_search_,
hex_search_,
- string_search_
+ string_search_,
+ regex_search_
};
enum {
@@ -52,7 +53,8 @@ enum {
SearchFrame::SearchFrame(QWidget *parent) :
AccordionFrame(parent),
sf_ui_(new Ui::SearchFrame),
- cap_file_(NULL)
+ cap_file_(NULL),
+ regex_(NULL)
{
sf_ui_->setupUi(this);
@@ -67,6 +69,9 @@ SearchFrame::SearchFrame(QWidget *parent) :
SearchFrame::~SearchFrame()
{
+ if (regex_) {
+ g_regex_unref(regex_);
+ }
delete sf_ui_;
}
@@ -138,6 +143,33 @@ void SearchFrame::keyPressEvent(QKeyEvent *event)
}
}
+bool SearchFrame::regexCompile()
+{
+ int flags = (G_REGEX_OPTIMIZE);
+ if (!sf_ui_->caseCheckBox->isChecked()) {
+ flags |= G_REGEX_CASELESS;
+ }
+
+ if (regex_) {
+ g_regex_unref(regex_);
+ }
+
+ if (sf_ui_->searchLineEdit->text().isEmpty()) {
+ regex_ = NULL;
+ return false;
+ }
+
+ GError *g_error = NULL;
+ regex_ = g_regex_new(sf_ui_->searchLineEdit->text().toUtf8().constData(),
+ (GRegexCompileFlags)flags, (GRegexMatchFlags) 0, &g_error);
+ if (g_error) {
+ regex_error_ = g_error->message;
+ g_error_free(g_error);
+ }
+
+ return regex_ ? true : false;
+}
+
void SearchFrame::updateWidgets()
{
if (cap_file_) {
@@ -147,12 +179,12 @@ void SearchFrame::updateWidgets()
return;
}
- bool enable = sf_ui_->searchTypeComboBox->currentIndex() == string_search_;
- sf_ui_->searchInComboBox->setEnabled(enable);
- sf_ui_->caseCheckBox->setEnabled(enable);
- sf_ui_->charEncodingComboBox->setEnabled(enable);
+ int search_type = sf_ui_->searchTypeComboBox->currentIndex();
+ sf_ui_->searchInComboBox->setEnabled(search_type == string_search_ || search_type == regex_search_);
+ sf_ui_->caseCheckBox->setEnabled(search_type == string_search_ || search_type == regex_search_);
+ sf_ui_->charEncodingComboBox->setEnabled(search_type == string_search_);
- switch (sf_ui_->searchTypeComboBox->currentIndex()) {
+ switch (search_type) {
case df_search_:
sf_ui_->searchLineEdit->checkDisplayFilter(sf_ui_->searchLineEdit->text());
break;
@@ -178,6 +210,13 @@ void SearchFrame::updateWidgets()
sf_ui_->searchLineEdit->setSyntaxState(SyntaxLineEdit::Valid);
}
break;
+ case regex_search_:
+ if (regexCompile()) {
+ sf_ui_->searchLineEdit->setSyntaxState(SyntaxLineEdit::Valid);
+ } else {
+ sf_ui_->searchLineEdit->setSyntaxState(SyntaxLineEdit::Invalid);
+ }
+ break;
default:
// currentIndex is probably -1. Nothing is selected or list is empty.
return;
@@ -190,6 +229,11 @@ void SearchFrame::updateWidgets()
}
}
+void SearchFrame::on_caseCheckBox_toggled(bool)
+{
+ regexCompile();
+}
+
void SearchFrame::on_searchTypeComboBox_currentIndexChanged(int)
{
updateWidgets();
@@ -216,12 +260,14 @@ void SearchFrame::on_findButton_clicked()
cap_file_->hex = FALSE;
cap_file_->string = FALSE;
cap_file_->case_type = FALSE;
+ cap_file_->regex = NULL;
cap_file_->packet_data = FALSE;
cap_file_->decode_data = FALSE;
cap_file_->summary_data = FALSE;
cap_file_->scs_type = SCS_NARROW_AND_WIDE;
- switch (sf_ui_->searchTypeComboBox->currentIndex()) {
+ int search_type = sf_ui_->searchTypeComboBox->currentIndex();
+ switch (search_type) {
case df_search_:
if (!dfilter_compile(sf_ui_->searchLineEdit->text().toUtf8().constData(), &dfp, NULL)) {
err_string = tr("Invalid filter.");
@@ -245,6 +291,7 @@ void SearchFrame::on_findButton_clicked()
cap_file_->hex = TRUE;
break;
case string_search_:
+ case regex_search_:
if (sf_ui_->searchLineEdit->text().isEmpty()) {
err_string = tr("You didn't specify any text for which to search.");
emit pushFilterSyntaxStatus(err_string);
@@ -252,6 +299,7 @@ void SearchFrame::on_findButton_clicked()
}
cap_file_->string = TRUE;
cap_file_->case_type = sf_ui_->caseCheckBox->isChecked() ? FALSE : TRUE;
+ cap_file_->regex = (search_type == regex_search_ ? regex_ : NULL);
switch (sf_ui_->charEncodingComboBox->currentIndex()) {
case narrow_and_wide_chars_:
cap_file_->scs_type = SCS_NARROW_AND_WIDE;
@@ -305,6 +353,10 @@ void SearchFrame::on_findButton_clicked()
return;
}
} else if (cap_file_->string) {
+ if (search_type == regex_search_ && !cap_file_->regex) {
+ emit pushFilterSyntaxStatus(regex_error_);
+ return;
+ }
if (cap_file_->summary_data) {
/* String in the Info column of the summary line */
found_packet = cf_find_packet_summary_line(cap_file_, string, cap_file_->dir);
diff --git a/ui/qt/search_frame.h b/ui/qt/search_frame.h
index 9ba8c62c1c..ee895e0366 100644
--- a/ui/qt/search_frame.h
+++ b/ui/qt/search_frame.h
@@ -55,12 +55,16 @@ protected:
virtual void keyPressEvent(QKeyEvent *event);
private:
+ bool regexCompile();
void updateWidgets();
Ui::SearchFrame *sf_ui_;
capture_file *cap_file_;
+ GRegex *regex_;
+ QString regex_error_;
private slots:
+ void on_caseCheckBox_toggled(bool);
void on_searchTypeComboBox_currentIndexChanged(int);
void on_searchLineEdit_textChanged(const QString &);
void on_findButton_clicked();
diff --git a/ui/qt/search_frame.ui b/ui/qt/search_frame.ui
index e05a4ff06b..d2b9056118 100644
--- a/ui/qt/search_frame.ui
+++ b/ui/qt/search_frame.ui
@@ -106,7 +106,7 @@
<item>
<widget class="QComboBox" name="searchTypeComboBox">
<property name="toolTip">
- <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Search for data using display filter syntax (e.g. ip.addr==10.1.1.1), a hexadecimal string (e.g. fffffda5) or a plain string (e.g. My String).&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Search for data using display filter syntax (e.g. ip.addr==10.1.1.1), a hexadecimal string (e.g. fffffda5), a plain string (e.g. My String) or a regular expression (e.g. colou?r).&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<item>
<property name="text">
@@ -123,6 +123,11 @@
<string>String</string>
</property>
</item>
+ <item>
+ <property name="text">
+ <string>Regular Expression</string>
+ </property>
+ </item>
</widget>
</item>
<item>