diff options
-rw-r--r-- | cfile.h | 1 | ||||
-rw-r--r-- | docbook/release-notes.asciidoc | 1 | ||||
-rw-r--r-- | file.c | 103 | ||||
-rw-r--r-- | ui/gtk/find_dlg.c | 1 | ||||
-rw-r--r-- | ui/qt/search_frame.cpp | 68 | ||||
-rw-r--r-- | ui/qt/search_frame.h | 4 | ||||
-rw-r--r-- | ui/qt/search_frame.ui | 7 |
7 files changed, 146 insertions, 39 deletions
@@ -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 @@ -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><html><head/><body><p>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).</p></body></html></string> + <string><html><head/><body><p>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).</p></body></html></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> |