diff --git a/ui/qt/byte_view_tab.cpp b/ui/qt/byte_view_tab.cpp index afc7aa834e..b8d12bbe33 100644 --- a/ui/qt/byte_view_tab.cpp +++ b/ui/qt/byte_view_tab.cpp @@ -20,7 +20,6 @@ */ #include "byte_view_tab.h" -#include "byte_view_text.h" #include #include @@ -28,14 +27,21 @@ #include #include +#include "cfile.h" +#include "epan/epan_dissect.h" + #include +#include + +#define tvb_data_property "tvb_data_property" // To do: // - We might want to add a callback to free_data_sources in so that we // don't have to blindly call clear(). ByteViewTab::ByteViewTab(QWidget *parent) : - QTabWidget(parent) + QTabWidget(parent), + cap_file_(0) { setAccessibleName(tr("Packet bytes")); setTabPosition(QTabWidget::South); @@ -43,39 +49,81 @@ ByteViewTab::ByteViewTab(QWidget *parent) : addTab(); } -void ByteViewTab::addTab(const char *name, tvbuff_t *tvb, proto_tree *tree, QTreeWidget *protoTree, packet_char_enc encoding) { +void ByteViewTab::addTab(const char *name, tvbuff_t *tvb) { + if ( ! tvb || ! cap_file_ ) + return; + if (count() == 1) { // Remove empty placeholder. ByteViewText *cur_text = qobject_cast(currentWidget()); if (cur_text && cur_text->isEmpty()) delete currentWidget(); } - ByteViewText *byte_view_text = new ByteViewText(this, tvb, tree, protoTree, encoding); + packet_char_enc encoding = (packet_char_enc)cap_file_->current_frame->flags.encoding; + + QByteArray data((const char *) tvb_memdup(wmem_file_scope(), tvb, 0, -1), tvb_captured_length(tvb)); + + ByteViewText * byte_view_text = new ByteViewText(data, encoding, this); byte_view_text->setAccessibleName(name); byte_view_text->setMonospaceFont(mono_font_); + + byte_view_text->setProperty(tvb_data_property, VariantPointer::asQVariant(tvb)); + connect(this, SIGNAL(monospaceFontChanged(QFont)), byte_view_text, SLOT(setMonospaceFont(QFont))); - connect(byte_view_text, SIGNAL(byteFieldHovered(const QString&)), this, SIGNAL(byteFieldHovered(const QString&))); + + connect(byte_view_text, SIGNAL(byteHovered(int)), this, SLOT(byteViewTextHovered(int))); + connect(byte_view_text, SIGNAL(byteSelected(int)), this, SLOT(byteViewTextMarked(int))); + int idx = QTabWidget::addTab(byte_view_text, name); + QTabWidget::setTabToolTip(idx, name); } -void ByteViewTab::clear() +void ByteViewTab::packetSelectionChanged() { - bool visible = isVisible(); - if (visible) { - hide(); + if ( ! cap_file_ || ! cap_file_->edt ) + return; + + GSList *src_le; + for (src_le = cap_file_->edt->pi.data_src; src_le != NULL; src_le = src_le->next) { + struct data_source *source; + char* source_name; + source = (struct data_source *)src_le->data; + source_name = get_data_source_name(source); + addTab(source_name, get_data_source_tvb(source)); + wmem_free(NULL, source_name); } - while (currentWidget()) { - delete currentWidget(); + setCurrentIndex(0); +} + +void ByteViewTab::byteViewTextHovered(int idx) +{ + if ( idx < 0 ) + { + emit tvbOffsetHovered((tvbuff_t *)0, idx); + return; } - addTab(); - if (visible) { - show(); + + tvbuff_t * tvb = VariantPointer::asPtr(sender()->property(tvb_data_property)); + + emit tvbOffsetHovered(tvb, idx); +} + +void ByteViewTab::byteViewTextMarked(int idx) +{ + if ( idx < 0 ) + { + emit tvbOffsetMarked((tvbuff_t *)0, idx); + return; } + + tvbuff_t * tvb = VariantPointer::asPtr(sender()->property(tvb_data_property)); + + emit tvbOffsetMarked(tvb, idx); } // XXX How many hex dump routines do we have? const int byte_line_length_ = 16; // Print out data for 16 bytes on one line -void ByteViewTab::copyHexTextDump(const guint8 *data_p, int data_len, bool append_text) +void ByteViewTab::copyHexTextDump(QByteArray data, bool append_text) { QString clipboard_text; /* Write hex data for a line, then ascii data, then concatenate and add to buffer */ @@ -85,21 +133,19 @@ void ByteViewTab::copyHexTextDump(const guint8 *data_p, int data_len, bool appen int byte_line_part_length; i = 0; - while (i < data_len) { + while (i < data.count()) { if(end_of_line) { hex_str += QString("%1 ").arg(i, 4, 16, QChar('0')); /* Offset - note that we _append_ here */ } - hex_str += QString(" %1").arg(*data_p, 2, 16, QChar('0')); + hex_str += QString(" %1").arg(data[i], 2, 16, QChar('0')); if(append_text) { - char_str += QString("%1").arg(g_ascii_isprint(*data_p) ? QChar(*data_p) : '.'); + char_str += QString("%1").arg(g_ascii_isprint(data[i]) ? QChar(data[i]) : '.'); } - ++data_p; - /* Look ahead to see if this is the end of the data */ byte_line_part_length = (++i) % byte_line_length_; - if(i >= data_len){ + if(i >= data.count()){ /* End of data - need to fill in spaces in hex string and then do "end of line". * */ @@ -133,15 +179,14 @@ void ByteViewTab::copyHexTextDump(const guint8 *data_p, int data_len, bool appen } } -void ByteViewTab::copyPrintableText(const guint8 *data_p, int data_len) +void ByteViewTab::copyPrintableText(QByteArray data) { QString clipboard_text; - for (int i = 0; i < data_len; i++) { - const guint8 c = data_p[i]; - if (g_ascii_isprint(c) || g_ascii_isspace(c)) { - clipboard_text += QChar(c); - } + for (int i = 0; i < data.count(); i++) + { + if ( QChar(data[i]).toLatin1() != 0 ) + clipboard_text += QChar(data[i]); } if (!clipboard_text.isEmpty()) { @@ -149,23 +194,15 @@ void ByteViewTab::copyPrintableText(const guint8 *data_p, int data_len) } } -void ByteViewTab::copyHexStream(const guint8 *data_p, int data_len) +void ByteViewTab::copyHexStream(QByteArray data) { - QString clipboard_text; - - for (int i = 0; i < data_len; i++) { - clipboard_text += QString("%1").arg(data_p[i], 2, 16, QChar('0')); - } - - if (!clipboard_text.isEmpty()) { - qApp->clipboard()->setText(clipboard_text); + if (!data.isEmpty()) { + qApp->clipboard()->setText(data.toHex().toUpper()); } } -void ByteViewTab::copyBinary(const guint8 *data_p, int data_len) +void ByteViewTab::copyBinary(QByteArray data) { - QByteArray clipboard_bytes = QByteArray::fromRawData((const char *) data_p, data_len); - - if (!clipboard_bytes.isEmpty()) { + if (!data.isEmpty()) { QMimeData *mime_data = new QMimeData; // gtk/gui_utils.c:copy_binary_to_clipboard says: /* XXX - this is not understood by most applications, @@ -174,27 +211,28 @@ void ByteViewTab::copyBinary(const guint8 *data_p, int data_len) */ // As of 2015-07-30, pasting into Frhed works on Windows. Pasting into // Hex Editor Neo and HxD does not. - mime_data->setData("application/octet-stream", clipboard_bytes); + mime_data->setData("application/octet-stream", data); qApp->clipboard()->setMimeData(mime_data); } } -void ByteViewTab::copyEscapedString(const guint8 *data_p, int data_len) +void ByteViewTab::copyEscapedString(QByteArray data) { QString clipboard_text; // Beginning quote clipboard_text += QString("\""); - for (int i = 0; i < data_len; i++) { + for (int i = 0; i < data.count(); i++) + { // Terminate this line if it has reached 16 bytes, // unless it is also the very last byte in the data, // as the termination after this for loop will take // care of that. - if (i % 16 == 0 && i != 0 && i != data_len - 1) { + if (i % 16 == 0 && i != 0 && i != data.count() - 1) { clipboard_text += QString("\" \\\n\""); } - clipboard_text += QString("\\x%1").arg(data_p[i], 2, 16, QChar('0')); + clipboard_text += QString("\\x%1").arg(data[i], 2, 16, QChar('0')); } // End quote clipboard_text += QString("\"\n"); @@ -204,51 +242,70 @@ void ByteViewTab::copyEscapedString(const guint8 *data_p, int data_len) } } +ByteViewText * ByteViewTab::findByteViewTextForTvb(tvbuff_t * search_tvb, int * idx) +{ + int cnt = 0; + ByteViewText * item = 0; + + if ( ! search_tvb ) + return item; + + item = qobject_cast(widget(cnt)); + + while ( item ) { + if ( ! item->property(tvb_data_property).isNull() ) + { + tvbuff_t * stored = VariantPointer::asPtr(item->property(tvb_data_property)); + if ( stored && stored == search_tvb ) + { + if ( idx ) + *idx = cnt; + break; + } + } + item = qobject_cast(widget(++cnt)); + } + + return item; +} + void ByteViewTab::copyData(ByteViewTab::copyDataType copy_type, field_info *fi) { - int i = 0; - ByteViewText *byte_view_text = qobject_cast(widget(i)); + ByteViewText *byte_view_text = 0; - if (fi) { - while (byte_view_text) { - if (byte_view_text->hasDataSource(fi->ds_tvb)) break; - byte_view_text = qobject_cast(widget(++i)); - } - } + if ( fi ) + byte_view_text = findByteViewTextForTvb(fi->ds_tvb); if (!byte_view_text) return; - guint data_len = 0; - const guint8 *data_p; + QByteArray data = byte_view_text->viewData(); - data_p = byte_view_text->dataAndLength(&data_len); - if (!data_p) return; + if ( data.isEmpty() == 0 ) + return; - if (fi && fi->start >= 0 && fi->length > 0 && fi->length <= (int) data_len) { - data_len = fi->length; - data_p += fi->start; - } + if ( fi && fi->start >= 0 && fi->length > 0 && fi->length <= data.count() ) + data = data.right(fi->length); - if (!data_len) return; + if ( data.isEmpty() ) return; switch (copy_type) { case copyDataHexTextDump: - copyHexTextDump(data_p, data_len, true); + copyHexTextDump(data, true); break; case copyDataHexDump: - copyHexTextDump(data_p, data_len, false); + copyHexTextDump(data, false); break; case copyDataPrintableText: - copyPrintableText(data_p, data_len); + copyPrintableText(data); break; case copyDataHexStream: - copyHexStream(data_p, data_len); + copyHexStream(data); break; case copyDataBinary: - copyBinary(data_p, data_len); + copyBinary(data); break; case copyDataEscapedString: - copyEscapedString(data_p, data_len); + copyEscapedString(data); break; default: break; @@ -278,76 +335,77 @@ void ByteViewTab::protoTreeItemChanged(QTreeWidgetItem *current) { fi = VariantPointer::asPtr(current->data(0, Qt::UserRole)); - int i = 0; - ByteViewText *byte_view_text = qobject_cast(widget(i)); - while (byte_view_text) { - if (byte_view_text->hasDataSource(fi->ds_tvb)) { - QTreeWidgetItem *parent = current->parent(); - field_info *parent_fi = NULL; - int f_start = -1, f_end = -1, f_len = -1; - int fa_start = -1, fa_end = -1, fa_len = -1; - int p_start = -1, p_end = -1, p_len = -1; - guint len = tvb_captured_length(fi->ds_tvb); + ByteViewText *byte_view_text = 0; + int idx = 0; - // Find and highlight the protocol bytes - while (parent && parent->parent()) { - parent = parent->parent(); - } - if (parent) { - parent_fi = VariantPointer::asPtr(parent->data(0, Qt::UserRole)); - } - if (parent_fi && parent_fi->ds_tvb == fi->ds_tvb) { - p_start = parent_fi->start; - p_len = parent_fi->length; - } + if ( fi ) + byte_view_text = findByteViewTextForTvb(fi->ds_tvb, &idx); - if (cap_file_->search_in_progress && (cap_file_->hex || (cap_file_->string && cap_file_->packet_data))) { - // In the hex view, only highlight the target bytes or string. The entire - // field can then be displayed by clicking on any of the bytes in the field. - f_start = cap_file_->search_pos - cap_file_->search_len + 1; - f_len = cap_file_->search_len; - } else { - f_start = fi->start; - f_len = fi->length; - } + if (byte_view_text) { + QTreeWidgetItem *parent = current->parent(); + field_info *parent_fi = NULL; + int f_start = -1, f_end = -1, f_len = -1; + int fa_start = -1, fa_end = -1, fa_len = -1; + int p_start = -1, p_end = -1, p_len = -1; + guint len = tvb_captured_length(fi->ds_tvb); - /* bmask = finfo->hfinfo->bitmask << hfinfo_bitshift(finfo->hfinfo); */ /* (value & mask) >> shift */ - fa_start = fi->appendix_start; - fa_len = fi->appendix_length; - - if (p_start >= 0 && p_len > 0 && (guint)p_start < len) { - p_end = p_start + p_len; - } - if (f_start >= 0 && f_len > 0 && (guint)f_start < len) { - f_end = f_start + f_len; - } - if (fa_start >= 0 && fa_len > 0 && (guint)fa_start < len) { - fa_end = fa_start + fa_len; - } - - if (f_end == -1 && fa_end != -1) { - f_start = fa_start; - f_end = fa_end; - fa_start = fa_end = -1; - } - - /* don't exceed the end of available data */ - if (p_end != -1 && (guint)p_end > len) p_end = len; - if (f_end != -1 && (guint)f_end > len) f_end = len; - if (fa_end != -1 && (guint)fa_end > len) fa_end = len; - - // Protocol - byte_view_text->setProtocolHighlight(p_start, p_end); - - // Field bytes - byte_view_text->setFieldHighlight(f_start, f_end); - - // Appendix (trailer) bytes - byte_view_text->setFieldAppendixHighlight(fa_start, fa_end); - - setCurrentIndex(i); + // Find and highlight the protocol bytes + while (parent && parent->parent()) { + parent = parent->parent(); } - byte_view_text = qobject_cast(widget(++i)); + if (parent) { + parent_fi = VariantPointer::asPtr(parent->data(0, Qt::UserRole)); + } + if (parent_fi && parent_fi->ds_tvb == fi->ds_tvb) { + p_start = parent_fi->start; + p_len = parent_fi->length; + } + + if (cap_file_->search_in_progress && (cap_file_->hex || (cap_file_->string && cap_file_->packet_data))) { + // In the hex view, only highlight the target bytes or string. The entire + // field can then be displayed by clicking on any of the bytes in the field. + f_start = cap_file_->search_pos - cap_file_->search_len + 1; + f_len = cap_file_->search_len; + } else { + f_start = fi->start; + f_len = fi->length; + } + + /* bmask = finfo->hfinfo->bitmask << hfinfo_bitshift(finfo->hfinfo); */ /* (value & mask) >> shift */ + fa_start = fi->appendix_start; + fa_len = fi->appendix_length; + + if (p_start >= 0 && p_len > 0 && (guint)p_start < len) { + p_end = p_start + p_len; + } + if (f_start >= 0 && f_len > 0 && (guint)f_start < len) { + f_end = f_start + f_len; + } + if (fa_start >= 0 && fa_len > 0 && (guint)fa_start < len) { + fa_end = fa_start + fa_len; + } + + if (f_end == -1 && fa_end != -1) { + f_start = fa_start; + f_end = fa_end; + fa_start = fa_end = -1; + } + + /* don't exceed the end of available data */ + if (p_end != -1 && (guint)p_end > len) p_end = len; + if (f_end != -1 && (guint)f_end > len) f_end = len; + if (fa_end != -1 && (guint)fa_end > len) fa_end = len; + + // Protocol + byte_view_text->markProtocol(p_start, p_end); + + // Field bytes + byte_view_text->markField(f_start, f_end); + + // Appendix (trailer) bytes + byte_view_text->markAppendix(fa_start, fa_end); + + setCurrentIndex(idx); } } } diff --git a/ui/qt/byte_view_tab.h b/ui/qt/byte_view_tab.h index 041832809c..202409ef2a 100644 --- a/ui/qt/byte_view_tab.h +++ b/ui/qt/byte_view_tab.h @@ -31,9 +31,10 @@ #include "cfile.h" #include +#include +#include -class QTreeWidget; -class QTreeWidgetItem; +#include class ByteViewTab : public QTabWidget { @@ -49,33 +50,47 @@ public: }; explicit ByteViewTab(QWidget *parent = 0); - void addTab(const char *name = "", tvbuff_t *tvb = NULL, proto_tree *tree = NULL, QTreeWidget *protoTree = NULL, packet_char_enc encoding = PACKET_CHAR_ENC_CHAR_ASCII); - void clear(); + void copyData(copyDataType copy_type, field_info *fi = NULL); +public slots: + /* Set the capture file */ + void setCaptureFile(capture_file *cf); + /* Creates the tabs and data, depends on an dissection which has already run */ + void packetSelectionChanged(); + + void protoTreeItemChanged(QTreeWidgetItem *current); + void setMonospaceFont(const QFont &mono_font); + +signals: + void monospaceFontChanged(const QFont &mono_font); + void byteFieldHovered(const QString &); + + void tvbOffsetHovered(tvbuff_t *, int); + void tvbOffsetMarked(tvbuff_t *, int); + private: capture_file *cap_file_; QFont mono_font_; void setTabsVisible(); - void copyHexTextDump(const guint8 *data_p, int data_len, bool append_text); - void copyPrintableText(const guint8 *data_p, int data_len); - void copyHexStream(const guint8 *data_p, int data_len); - void copyBinary(const guint8 *data_p, int data_len); - void copyEscapedString(const guint8 *data_p, int data_len); + void copyHexTextDump(QByteArray data, bool append_text); + void copyPrintableText(QByteArray data); + void copyHexStream(QByteArray data); + void copyBinary(QByteArray data); + void copyEscapedString(QByteArray data); + + ByteViewText * findByteViewTextForTvb(tvbuff_t * search, int * idx = 0); + + void addTab(const char *name = "", tvbuff_t *tvb = NULL); protected: void tabInserted(int index); void tabRemoved(int index); -signals: - void monospaceFontChanged(const QFont &mono_font); - void byteFieldHovered(const QString &); - -public slots: - void protoTreeItemChanged(QTreeWidgetItem *current); - void setCaptureFile(capture_file *cf); - void setMonospaceFont(const QFont &mono_font); +private slots: + void byteViewTextHovered(int); + void byteViewTextMarked(int); }; #endif // BYTE_VIEW_TAB_H diff --git a/ui/qt/byte_view_text.cpp b/ui/qt/byte_view_text.cpp index 47595c763e..95575140ed 100644 --- a/ui/qt/byte_view_text.cpp +++ b/ui/qt/byte_view_text.cpp @@ -38,6 +38,8 @@ #include #include #include +#include +#include // To do: // - Add recent settings and context menu items to show/hide the offset, @@ -52,14 +54,9 @@ Q_DECLARE_METATYPE(bytes_view_type) Q_DECLARE_METATYPE(packet_char_enc) -ByteViewText::ByteViewText(QWidget *parent, tvbuff_t *tvb, proto_tree *tree, QTreeWidget *tree_widget, packet_char_enc encoding) : +ByteViewText::ByteViewText(QByteArray data, packet_char_enc encoding, QWidget *parent) : QAbstractScrollArea(parent), - tvb_(tvb), - proto_tree_(tree), - tree_widget_(tree_widget), bold_highlight_(false), - format_actions_(new QActionGroup(this)), - encoding_actions_(new QActionGroup(this)), encoding_(encoding), hovered_byte_offset_(-1), hovered_byte_lock_(false), @@ -75,6 +72,25 @@ ByteViewText::ByteViewText(QWidget *parent, tvbuff_t *tvb, proto_tree *tree, QTr line_spacing_(0), margin_(0) { + data_ = data; + + createContextMenu(); + + setMouseTracking(true); + +#ifdef Q_OS_MAC + setAttribute(Qt::WA_MacShowFocusRect, true); +#endif +} + +ByteViewText::~ByteViewText() +{ + ctx_menu_.clear(); +} + +void ByteViewText::createContextMenu() +{ + QActionGroup * format_actions_ = new QActionGroup(this); QAction *action; action = format_actions_->addAction(tr("Show bytes as hexadecimal")); @@ -95,6 +111,7 @@ ByteViewText::ByteViewText(QWidget *parent, tvbuff_t *tvb, proto_tree *tree, QTr ctx_menu_.addSeparator(); + QActionGroup * encoding_actions_ = new QActionGroup(this); action = encoding_actions_->addAction(tr(UTF8_HORIZONTAL_ELLIPSIS "as ASCII")); action->setData(qVariantFromValue(PACKET_CHAR_ENC_CHAR_ASCII)); action->setCheckable(true); @@ -110,17 +127,26 @@ ByteViewText::ByteViewText(QWidget *parent, tvbuff_t *tvb, proto_tree *tree, QTr ctx_menu_.addActions(encoding_actions_->actions()); connect(encoding_actions_, SIGNAL(triggered(QAction*)), this, SLOT(setCharacterEncoding(QAction*))); - - setMouseTracking(true); - -#ifdef Q_OS_MAC - setAttribute(Qt::WA_MacShowFocusRect, true); -#endif } -ByteViewText::~ByteViewText() +void ByteViewText::reset() { - ctx_menu_.clear(); + data_.clear(); +} + +QByteArray ByteViewText::viewData() +{ + return data_; +} + +void ByteViewText::setHighlightStyle(bool bold) +{ + bold_highlight_ = bold; +} + +bool ByteViewText::isEmpty() const +{ + return data_.isEmpty(); } QSize ByteViewText::minimumSizeHint() const @@ -129,46 +155,34 @@ QSize ByteViewText::minimumSizeHint() const return QSize(); } -bool ByteViewText::hasDataSource(const tvbuff_t *ds_tvb) { - if (ds_tvb != NULL && ds_tvb == tvb_) - return true; - return false; -} - -void ByteViewText::setProtocolHighlight(int start, int end) +void ByteViewText::markProtocol(int start, int end) { p_bound_ = QPair(qMax(0, start), qMax(0, end)); p_bound_save_ = p_bound_; viewport()->update(); } -void ByteViewText::setFieldHighlight(int start, int end, guint32, int) +void ByteViewText::markField(int start, int end) { f_bound_ = QPair(qMax(0, start), qMax(0, end)); f_bound_save_ = f_bound_; - scrollToByte(start); viewport()->update(); } -void ByteViewText::setFieldAppendixHighlight(int start, int end) +void ByteViewText::moveToOffset(int pos) +{ + scrollToByte(pos); + viewport()->update(); +} + + +void ByteViewText::markAppendix(int start, int end) { fa_bound_ = QPair(qMax(0, start), qMax(0, end)); fa_bound_save_ = f_bound_; viewport()->update(); } -const guint8 *ByteViewText::dataAndLength(guint *data_len_ptr) -{ - if (!tvb_) return NULL; - - guint data_len = tvb_captured_length(tvb_); - if (data_len) { - *data_len_ptr = data_len; - return tvb_get_ptr(tvb_, 0, -1); - } - return NULL; -} - void ByteViewText::setMonospaceFont(const QFont &mono_font) { mono_font_ = mono_font; @@ -209,7 +223,7 @@ void ByteViewText::paintEvent(QPaintEvent *) painter.fillRect(offset_rect, palette().window()); } - if (!tvb_) { + if ( data_.isEmpty() ) { return; } @@ -236,7 +250,7 @@ void ByteViewText::paintEvent(QPaintEvent *) // Data rows int widget_height = height(); painter.save(); - while(row_y + line_spacing_ < widget_height && offset < tvb_captured_length(tvb_)) { + while( (int) (row_y + line_spacing_) < widget_height && (int) offset < (int) data_.count()) { drawOffsetLine(painter, offset, row_y); offset += row_width_; row_y += line_spacing_; @@ -254,26 +268,12 @@ void ByteViewText::resizeEvent(QResizeEvent *) } void ByteViewText::mousePressEvent (QMouseEvent *event) { - if (!tvb_ || !event || event->button() != Qt::LeftButton) { + if (isEmpty() || !event || event->button() != Qt::LeftButton) { return; } hovered_byte_lock_ = !hovered_byte_lock_; - QPoint pos = event->pos(); - field_info *fi = fieldAtPixel(pos); - - if (fi && tree_widget_) { - // XXX - This should probably be a ProtoTree method. - QTreeWidgetItemIterator iter(tree_widget_); - while (*iter) { - if (fi == VariantPointer::asPtr((*iter)->data(0, Qt::UserRole))) { - tree_widget_->setCurrentItem((*iter)); - tree_widget_->scrollToItem((*iter)); - } - - ++iter; - } - } + emit byteSelected(byteOffsetAtPixel(event->pos())); } void ByteViewText::mouseMoveEvent(QMouseEvent *event) @@ -282,53 +282,16 @@ void ByteViewText::mouseMoveEvent(QMouseEvent *event) return; } - QString field_str; - // XXX can the event really be NULL? - if (!event) { - emit byteFieldHovered(field_str); - p_bound_ = p_bound_save_; - f_bound_ = f_bound_save_; - fa_bound_ = fa_bound_save_; - viewport()->update(); - return; - } - QPoint pos = event->pos(); - hovered_byte_offset_ = byteOffsetAtPixel(pos); - field_info *fi = fieldAtPixel(pos); - if (fi) { - if (fi->length < 2) { - field_str = QString(tr("Byte %1")) - .arg(fi->start); - } else { - field_str = QString(tr("Bytes %1-%2")) - .arg(fi->start) - .arg(fi->start + fi->length - 1); - } - field_str += QString(": %1 (%2)") - .arg(fi->hfinfo->name) - .arg(fi->hfinfo->abbrev); - f_bound_ = QPair(fi->start, fi->start + fi->length); - p_bound_ = QPair(0, 0); - fa_bound_ = QPair(0, 0); - } else { - p_bound_ = p_bound_save_; - f_bound_ = f_bound_save_; - fa_bound_ = fa_bound_save_; - } - emit byteFieldHovered(field_str); + emit byteHovered(byteOffsetAtPixel(event->pos())); + viewport()->update(); } void ByteViewText::leaveEvent(QEvent *event) { QString empty; - emit byteFieldHovered(empty); - if (!hovered_byte_lock_) { - hovered_byte_offset_ = -1; - } - p_bound_ = p_bound_save_; - f_bound_ = f_bound_save_; - fa_bound_ = fa_bound_save_; + emit byteHovered(-1); + viewport()->update(); QAbstractScrollArea::leaveEvent(event); } @@ -348,12 +311,11 @@ const int ByteViewText::separator_interval_ = 8; // Insert a space after this ma // numbers so we track our X coordinate position using using floats. void ByteViewText::drawOffsetLine(QPainter &painter, const guint offset, const int row_y) { - if (!tvb_) { + if (isEmpty()) { return; } - guint tvb_len = tvb_captured_length(tvb_); + guint tvb_len = data_.count(); guint max_pos = qMin(offset + row_width_, tvb_len); - const guint8 *pd = tvb_get_ptr(tvb_, 0, -1); static const guchar hexchars[16] = { '0', '1', '2', '3', '4', '5', '6', '7', @@ -399,13 +361,13 @@ void ByteViewText::drawOffsetLine(QPainter &painter, const guint offset, const i switch (recent.gui_bytes_view) { case BYTES_HEX: - text += hexchars[(pd[tvb_pos] & 0xf0) >> 4]; - text += hexchars[pd[tvb_pos] & 0x0f]; + text += hexchars[(data_[tvb_pos] & 0xf0) >> 4]; + text += hexchars[data_[tvb_pos] & 0x0f]; break; case BYTES_BITS: /* XXX, bitmask */ for (int j = 7; j >= 0; j--) - text += (pd[tvb_pos] & (1 << j)) ? '1' : '0'; + text += (data_[tvb_pos] & (1 << j)) ? '1' : '0'; break; } if (draw_hover) { @@ -450,8 +412,8 @@ void ByteViewText::drawOffsetLine(QPainter &painter, const guint offset, const i } guchar c = (encoding_ == PACKET_CHAR_ENC_CHAR_EBCDIC) ? - EBCDIC_to_ASCII1(pd[tvb_pos]) : - pd[tvb_pos]; + EBCDIC_to_ASCII1(data_[tvb_pos]) : + data_[tvb_pos]; text += g_ascii_isprint(c) ? c : '.'; if (highlight_text) { @@ -532,7 +494,7 @@ void ByteViewText::scrollToByte(int byte) // Offset character width int ByteViewText::offsetChars() { - if (tvb_ && tvb_captured_length(tvb_) > 0xffff) { + if (! isEmpty() && data_.count() > 0xffff) { return 8; } return 4; @@ -572,17 +534,16 @@ int ByteViewText::totalPixels() void ByteViewText::updateScrollbars() { - const gint length = tvb_ ? tvb_captured_length(tvb_) : 0; - if (tvb_) { + const int length = data_.count(); + if (length > 0) { + qint64 maxval = length / row_width_ + ((length % row_width_) ? 1 : 0) - viewport()->height() / line_spacing_; + + verticalScrollBar()->setRange(0, int(qMax((qint64)0, maxval))); + horizontalScrollBar()->setRange(0, qMax(0, static_cast((totalPixels() - viewport()->width()) / font_width_))); } - - qint64 maxval = length / row_width_ + ((length % row_width_) ? 1 : 0) - viewport()->height() / line_spacing_; - - verticalScrollBar()->setRange(0, int(qMax((qint64)0, maxval))); - horizontalScrollBar()->setRange(0, qMax(0, static_cast((totalPixels() - viewport()->width()) / font_width_))); } -int ByteViewText::byteOffsetAtPixel(QPoint &pos) +int ByteViewText::byteOffsetAtPixel(QPoint pos) { int byte = (verticalScrollBar()->value() + (pos.y() / line_spacing_)) * row_width_; int x = (horizontalScrollBar()->value() * font_width_) + pos.x(); @@ -593,21 +554,12 @@ int ByteViewText::byteOffsetAtPixel(QPoint &pos) } byte += col; - if ((guint) byte > tvb_captured_length(tvb_)) { + if (byte > data_.count()) { return -1; } return byte; } -field_info *ByteViewText::fieldAtPixel(QPoint &pos) -{ - int byte = byteOffsetAtPixel(pos); - if (byte < 0) { - return NULL; - } - return proto_find_field_from_offset(proto_tree_, byte, tvb_); -} - void ByteViewText::setHexDisplayFormat(QAction *action) { if (!action) { diff --git a/ui/qt/byte_view_text.h b/ui/qt/byte_view_text.h index f2af3c01d1..f5a7430f94 100644 --- a/ui/qt/byte_view_text.h +++ b/ui/qt/byte_view_text.h @@ -24,17 +24,14 @@ #include -#include -#include -#include - -#include "proto_tree.h" #include "ui/recent.h" #include +#include +#include +#include #include - -class QActionGroup; +#include // XXX - Is there any reason we shouldn't add ByteViewImage, etc? @@ -42,25 +39,34 @@ class ByteViewText : public QAbstractScrollArea { Q_OBJECT public: - explicit ByteViewText(QWidget *parent = 0, tvbuff_t *tvb = NULL, proto_tree *tree = NULL, QTreeWidget *protoTree = NULL, packet_char_enc encoding = PACKET_CHAR_ENC_CHAR_ASCII); + + explicit ByteViewText(QByteArray data, packet_char_enc encoding = PACKET_CHAR_ENC_CHAR_ASCII, QWidget *parent = 0); ~ByteViewText(); + virtual QSize minimumSizeHint() const; - bool hasDataSource(const tvbuff_t *ds_tvb = NULL); void setFormat(bytes_view_type format); - void setHighlightStyle(bool bold) { bold_highlight_ = bold; } - void setProtocolHighlight(int start, int end); - void setFieldHighlight(int start, int end, guint32 mask = 0, int mask_le = 0); - void setFieldAppendixHighlight(int start, int end); - bool isEmpty() { return tvb_ == NULL || proto_tree_ == NULL; } - const guint8 *dataAndLength(guint *data_len_ptr); + void setHighlightStyle(bool bold); + bool isEmpty() const; + + QByteArray viewData(); signals: - void byteFieldHovered(const QString &); + + void byteHovered(int pos); + void byteSelected(int pos); public slots: + void reset(); + void setMonospaceFont(const QFont &mono_font); + void markProtocol(int start, int end); + void markField(int start, int end); + void markAppendix(int start, int end); + + void moveToOffset(int pos); + protected: virtual void paintEvent(QPaintEvent *); virtual void resizeEvent(QResizeEvent *); @@ -80,22 +86,23 @@ private: ModeHover } HighlightMode; + QByteArray data_; + void drawOffsetLine(QPainter &painter, const guint offset, const int row_y); qreal flushOffsetFragment(QPainter &painter, qreal x, int y, HighlightMode mode, QString &text); void scrollToByte(int byte); + void updateScrollbars(); + int byteOffsetAtPixel(QPoint pos); + + void createContextMenu(); + int offsetChars(); int offsetPixels(); int hexPixels(); int asciiPixels(); int totalPixels(); - void updateScrollbars(); - int byteOffsetAtPixel(QPoint &pos); - field_info *fieldAtPixel(QPoint &pos); static const int separator_interval_; - tvbuff_t *tvb_; - proto_tree *proto_tree_; - QTreeWidget *tree_widget_; // Fonts and colors QFont mono_font_; @@ -103,11 +110,9 @@ private: QBrush offset_normal_fg_; QBrush offset_field_fg_; - gboolean bold_highlight_; + bool bold_highlight_; // Data - QActionGroup *format_actions_; - QActionGroup *encoding_actions_; packet_char_enc encoding_; // ASCII or EBCDIC QMenu ctx_menu_; diff --git a/ui/qt/main_window.cpp b/ui/qt/main_window.cpp index 0336b27d52..c2f0718515 100644 --- a/ui/qt/main_window.cpp +++ b/ui/qt/main_window.cpp @@ -476,6 +476,9 @@ MainWindow::MainWindow(QWidget *parent) : packet_list_->setByteViewTab(byte_view_tab_); packet_list_->installEventFilter(this); + connect(packet_list_, SIGNAL(packetSelectionChanged()), + byte_view_tab_, SLOT(packetSelectionChanged())); + main_welcome_ = main_ui_->welcomePage; // Packet list and proto tree must exist before these are called. @@ -685,10 +688,8 @@ MainWindow::MainWindow(QWidget *parent) : connect(proto_tree_, SIGNAL(editProtocolPreference(preference*,pref_module*)), main_ui_->preferenceEditorFrame, SLOT(editPreference(preference*,pref_module*))); - connect(byte_view_tab_, SIGNAL(byteFieldHovered(const QString&)), - main_ui_->statusBar, SLOT(pushByteStatus(const QString&))); - connect(byte_view_tab_, SIGNAL(currentChanged(int)), - this, SLOT(byteViewTabChanged(int))); + connect(byte_view_tab_, SIGNAL(tvbOffsetHovered(tvbuff_t *, int)), + this, SLOT(setTvbOffsetHovered(tvbuff_t *, int))); connect(main_ui_->statusBar, SIGNAL(showExpertInfo()), this, SLOT(on_actionAnalyzeExpertInfo_triggered())); diff --git a/ui/qt/main_window.h b/ui/qt/main_window.h index 0ab3614e4d..77c8c35b03 100644 --- a/ui/qt/main_window.h +++ b/ui/qt/main_window.h @@ -388,7 +388,7 @@ private slots: void openTapParameterDialog(const QString cfg_str, const QString arg, void *userdata); void openTapParameterDialog(); - void byteViewTabChanged(int tab_index); + void setTvbOffsetHovered(tvbuff_t * tvb, int idx); #ifdef HAVE_SOFTWARE_UPDATE void softwareUpdateRequested(); diff --git a/ui/qt/main_window_slots.cpp b/ui/qt/main_window_slots.cpp index c61b03abd6..c4068eab80 100644 --- a/ui/qt/main_window_slots.cpp +++ b/ui/qt/main_window_slots.cpp @@ -1779,13 +1779,33 @@ void MainWindow::openTapParameterDialog() openTapParameterDialog(cfg_str, NULL, NULL); } -void MainWindow::byteViewTabChanged(int tab_index) +void MainWindow::setTvbOffsetHovered(tvbuff_t * tvb, int idx) { - QWidget *new_tab = byte_view_tab_->widget(tab_index); - if (new_tab) { - setTabOrder(proto_tree_, new_tab); - setTabOrder(new_tab, df_combo_box_->lineEdit()); // XXX Toolbar instead? + QString field_str(""); + + if ( tvb && capture_file_.capFile() && capture_file_.capFile()->edt ) + { + proto_tree * tree = capture_file_.capFile()->edt->tree; + if ( tree ) + { + field_info * fi = proto_find_field_from_offset(tree, idx, tvb); + + if (fi) { + if (fi->length < 2) { + field_str = QString(tr("Byte %1")) + .arg(fi->start); + } else { + field_str = QString(tr("Bytes %1-%2")) + .arg(fi->start) + .arg(fi->start + fi->length - 1); + } + field_str += QString(": %1 (%2)") + .arg(fi->hfinfo->name) + .arg(fi->hfinfo->abbrev); + } + } } + main_ui_->statusBar->pushByteStatus(field_str); } #ifdef HAVE_SOFTWARE_UPDATE diff --git a/ui/qt/packet_dialog.cpp b/ui/qt/packet_dialog.cpp index 5daec09601..7849a3d5f9 100644 --- a/ui/qt/packet_dialog.cpp +++ b/ui/qt/packet_dialog.cpp @@ -71,19 +71,7 @@ PacketDialog::PacketDialog(QWidget &parent, CaptureFile &cf, frame_data *fdata) byte_view_tab_ = new ByteViewTab(ui->packetSplitter); byte_view_tab_->setCaptureFile(cap_file_.capFile()); - byte_view_tab_->clear(); - - GSList *src_le; - for (src_le = edt_.pi.data_src; src_le != NULL; src_le = src_le->next) { - struct data_source *source; - char* source_name; - source = (struct data_source *)src_le->data; - source_name = get_data_source_name(source); - byte_view_tab_->addTab(source_name, get_data_source_tvb(source), edt_.tree, proto_tree_, - (packet_char_enc)cap_file_.capFile()->current_frame->flags.encoding); - wmem_free(NULL, source_name); - } - byte_view_tab_->setCurrentIndex(0); + byte_view_tab_->packetSelectionChanged(); ui->packetSplitter->setStretchFactor(1, 0); @@ -95,7 +83,8 @@ PacketDialog::PacketDialog(QWidget &parent, CaptureFile &cf, frame_data *fdata) .arg(cap_file_.capFile()->cinfo.columns[i].col_data); } col_info_ = col_parts.join(" " UTF8_MIDDLE_DOT " "); - setHintText(); + + ui->hintLabel->setText(col_info_); connect(this, SIGNAL(monospaceFontChanged(QFont)), proto_tree_, SLOT(setMonospaceFont(QFont))); @@ -106,6 +95,8 @@ PacketDialog::PacketDialog(QWidget &parent, CaptureFile &cf, frame_data *fdata) byte_view_tab_, SLOT(protoTreeItemChanged(QTreeWidgetItem*))); connect(byte_view_tab_, SIGNAL(byteFieldHovered(const QString&)), this, SLOT(setHintText(const QString&))); + connect(byte_view_tab_, SIGNAL(tvbOffsetHovered(tvbuff_t *, int)), + this, SLOT(setTvbOffsetHovered(tvbuff_t *, int))); } PacketDialog::~PacketDialog() @@ -120,13 +111,38 @@ void PacketDialog::captureFileClosing() QString closed_title = tr("[%1 closed] " UTF8_MIDDLE_DOT " %2") .arg(cap_file_.fileName()) .arg(col_info_); - setHintText(closed_title); + ui->hintLabel->setText(closed_title); WiresharkDialog::captureFileClosing(); } -void PacketDialog::setHintText(const QString &hint) +void PacketDialog::setTvbOffsetHovered(tvbuff_t * tvb, int idx) { - ui->hintLabel->setText(hint.isEmpty() ? col_info_ : hint); + QString field_str(""); + + if ( tvb && cap_file_.capFile() && cap_file_.capFile()->edt ) + { + proto_tree * tree = cap_file_.capFile()->edt->tree; + if ( tree ) + { + field_info * fi = proto_find_field_from_offset(tree, idx, tvb); + + if (fi) { + if (fi->length < 2) { + field_str = QString(tr("Byte %1")) + .arg(fi->start); + } else { + field_str = QString(tr("Bytes %1-%2")) + .arg(fi->start) + .arg(fi->start + fi->length - 1); + } + field_str += QString(": %1 (%2)") + .arg(fi->hfinfo->name) + .arg(fi->hfinfo->abbrev); + } + } + } + + ui->hintLabel->setText(field_str); } void PacketDialog::on_buttonBox_helpRequested() diff --git a/ui/qt/packet_dialog.h b/ui/qt/packet_dialog.h index 4f4cde7885..429519c85b 100644 --- a/ui/qt/packet_dialog.h +++ b/ui/qt/packet_dialog.h @@ -47,8 +47,7 @@ signals: private slots: void captureFileClosing(); - void setHintText() { QString empty; setHintText(empty); } - void setHintText(const QString &hint); + void setTvbOffsetHovered(tvbuff_t * tvb, int idx); void on_buttonBox_helpRequested(); private: diff --git a/ui/qt/packet_list.cpp b/ui/qt/packet_list.cpp index 46985c0bb8..2e904a0fdb 100644 --- a/ui/qt/packet_list.cpp +++ b/ui/qt/packet_list.cpp @@ -505,7 +505,6 @@ void PacketList::selectionChanged (const QItemSelection & selected, const QItemS related_packet_delegate_.clear(); if (proto_tree_) proto_tree_->clear(); - if (byte_view_tab_) byte_view_tab_->clear(); emit packetSelectionChanged(); @@ -525,20 +524,6 @@ void PacketList::selectionChanged (const QItemSelection & selected, const QItemS viewport()->update(); } - if (byte_view_tab_) { - GSList *src_le; - struct data_source *source; - char* source_name; - - for (src_le = cap_file_->edt->pi.data_src; src_le != NULL; src_le = src_le->next) { - source = (struct data_source *)src_le->data; - source_name = get_data_source_name(source); - byte_view_tab_->addTab(source_name, get_data_source_tvb(source), cap_file_->edt->tree, proto_tree_, (packet_char_enc)cap_file_->current_frame->flags.encoding); - wmem_free(NULL, source_name); - } - byte_view_tab_->setCurrentIndex(0); - } - if (cap_file_->search_in_progress && (cap_file_->search_pos != 0 || (cap_file_->string && cap_file_->decode_data))) { @@ -944,7 +929,6 @@ void PacketList::freeze() // call selectionChanged. related_packet_delegate_.clear(); proto_tree_->clear(); - byte_view_tab_->clear(); } void PacketList::thaw(bool restore_selection) @@ -970,7 +954,6 @@ void PacketList::clear() { selectionModel()->clear(); packet_list_model_->clear(); proto_tree_->clear(); - byte_view_tab_->clear(); selection_history_.clear(); cur_history_ = -1; in_history_ = false;