aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--epan/prefs.c17
-rw-r--r--ui/qt/byte_view_tab.cpp13
-rw-r--r--ui/qt/utils/data_printer.cpp23
-rw-r--r--ui/qt/utils/data_printer.h18
-rw-r--r--ui/qt/utils/field_information.cpp51
-rw-r--r--ui/qt/utils/field_information.h15
-rw-r--r--ui/qt/widgets/byte_view_text.cpp404
-rw-r--r--ui/qt/widgets/byte_view_text.h70
8 files changed, 261 insertions, 350 deletions
diff --git a/epan/prefs.c b/epan/prefs.c
index 89a4e54f50..9ae9cfd21b 100644
--- a/epan/prefs.c
+++ b/epan/prefs.c
@@ -5,19 +5,7 @@
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * SPDX-License-Identifier: GPL-2.0+
*/
#include "config.h"
@@ -109,6 +97,7 @@ static const enum_val_t gui_ptree_expander_style[] = {
{NULL, NULL, -1}
};
+/* GTK+ only. */
static const enum_val_t gui_hex_dump_highlight_style[] = {
{"BOLD", "BOLD", 0},
{"INVERSE", "INVERSE", 1},
@@ -3959,7 +3948,7 @@ pre_init_prefs(void)
prefs.gui_expert_composite_eyecandy = FALSE;
prefs.gui_ptree_line_style = 0;
prefs.gui_ptree_expander_style = 1;
- prefs.gui_hex_dump_highlight_style = 1;
+ prefs.gui_hex_dump_highlight_style = 1; /* GTK+ only */
prefs.filter_toolbar_show_in_statusbar = FALSE;
prefs.restore_filter_after_following_stream = FALSE;
prefs.gui_toolbar_main_style = TB_STYLE_ICONS;
diff --git a/ui/qt/byte_view_tab.cpp b/ui/qt/byte_view_tab.cpp
index a038f637df..7bf47921c1 100644
--- a/ui/qt/byte_view_tab.cpp
+++ b/ui/qt/byte_view_tab.cpp
@@ -25,7 +25,6 @@
#include <QClipboard>
#include <QMimeData>
#include <QTabBar>
-#include <QTreeWidgetItem>
#include "cfile.h"
#include "epan/epan_dissect.h"
@@ -266,23 +265,23 @@ void ByteViewTab::selectedFieldChanged(FieldInformation *selected)
if (byte_view_text)
{
- int f_start = -1, f_end = -1;
+ int f_start = -1, f_length = -1;
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_end = f_start + cap_file_->search_len;
+ f_length = (int) cap_file_->search_len;
} else {
f_start = selected->position().start;
- f_end = selected->position().end;
+ f_length = selected->position().length;
}
setCurrentIndex(idx);
- byte_view_text->markField(f_start, f_end);
- byte_view_text->markProtocol(selected->parentField()->position().start, selected->parentField()->position().end);
- byte_view_text->markAppendix(selected->appendix().start, selected->appendix().end);
+ byte_view_text->markField(f_start, f_length);
+ byte_view_text->markProtocol(selected->parentField()->position().start, selected->parentField()->position().length);
+ byte_view_text->markAppendix(selected->appendix().start, selected->appendix().length);
}
}
diff --git a/ui/qt/utils/data_printer.cpp b/ui/qt/utils/data_printer.cpp
index fbb8a3c797..9d2d7740fb 100644
--- a/ui/qt/utils/data_printer.cpp
+++ b/ui/qt/utils/data_printer.cpp
@@ -4,21 +4,11 @@
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * SPDX-License-Identifier: GPL-2.0+
*/
+#include "ui/recent.h"
+
#include <ui/qt/utils/data_printer.h>
#include <stdint.h>
@@ -113,6 +103,13 @@ int DataPrinter::byteLineLength() const
return byteLineLength_;
}
+int DataPrinter::hexChars()
+{
+ int row_width = recent.gui_bytes_view == BYTES_HEX ? 16 : 8;
+ int chars_per_byte = recent.gui_bytes_view == BYTES_HEX ? 3 : 9;
+ return (row_width * chars_per_byte) + ((row_width - 1) / separatorInterval());
+}
+
QString DataPrinter::hexTextDump(QByteArray printData, bool showText)
{
QString clipboard_text;
diff --git a/ui/qt/utils/data_printer.h b/ui/qt/utils/data_printer.h
index 923c15169b..42a5f0c04d 100644
--- a/ui/qt/utils/data_printer.h
+++ b/ui/qt/utils/data_printer.h
@@ -7,19 +7,7 @@
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * SPDX-License-Identifier: GPL-2.0+
*/
#ifndef DATA_PRINTER_H
@@ -57,6 +45,10 @@ public:
void setByteLineLength(int);
int byteLineLength() const;
+ // Insert a space after this many bytes
+ static int separatorInterval() { return 8; }
+ // The number of hexadecimal characters per line
+ static int hexChars();
private:
QString hexTextDump(QByteArray printData, bool append_text);
diff --git a/ui/qt/utils/field_information.cpp b/ui/qt/utils/field_information.cpp
index fc58222101..aac03277c5 100644
--- a/ui/qt/utils/field_information.cpp
+++ b/ui/qt/utils/field_information.cpp
@@ -4,19 +4,7 @@
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * SPDX-License-Identifier: GPL-2.0+
*/
#include <stdint.h>
@@ -87,29 +75,22 @@ bool FieldInformation::tvbContains(FieldInformation *child)
FieldInformation::Position FieldInformation::position() const
{
- Position pos = {-1, -1, -1};
+ Position pos = {-1, -1};
if ( fi_ && fi_->ds_tvb )
{
- guint len = tvb_captured_length(fi_->ds_tvb);
+ int len = (int) tvb_captured_length(fi_->ds_tvb);
pos.start = fi_->start;
pos.length = fi_->length;
- if (pos.start >= 0 && pos.length > 0 && (guint)pos.start < len)
- {
- pos.end = pos.start + pos.length;
- }
- else
+ if (pos.start < 0 || pos.length < 0 || pos.start >= len)
{
- if ( fi_->appendix_start >= 0 && fi_->appendix_length > 0 && (guint)fi_->appendix_start < len )
+ if ( fi_->appendix_start >= 0 && fi_->appendix_length > 0 && fi_->appendix_start < len )
{
pos.start = fi_->appendix_start;
- pos.end = fi_->appendix_start + fi_->appendix_length;
+ pos.length = fi_->appendix_length;
}
}
-
- if (pos.end != -1 && (guint)pos.end > len)
- pos.end = len;
}
return pos;
@@ -117,31 +98,16 @@ FieldInformation::Position FieldInformation::position() const
FieldInformation::Position FieldInformation::appendix() const
{
- Position pos = {-1, -1, -1};
+ Position pos = {-1, -1};
if ( fi_ && fi_->ds_tvb )
{
- guint len = tvb_captured_length(fi_->ds_tvb);
-
pos.start = fi_->appendix_start;
pos.length = fi_->appendix_length;
-
- if (pos.start >= 0 && pos.length > 0 && (guint)pos.start < len)
- pos.end = pos.start + pos.length;
-
- /* sanity check with total field length */
- if ( position().end == -1 )
- {
- pos.start = -1;
- pos.end = -1;
- }
-
- if (pos.end != -1 && (guint)pos.end > len)
- pos.end = len;
}
return pos;
}
-#include <QDebug>
+
QByteArray FieldInformation::printableData()
{
QByteArray data;
@@ -154,7 +120,6 @@ QByteArray FieldInformation::printableData()
int length = pos.length;
if ( length > rem_length )
length = rem_length;
-qDebug() << "Bin hier";
uint8_t * dataSet = (uint8_t *)tvb_memdup(wmem_file_scope(), fi_->ds_tvb, pos.start, length );
data = QByteArray::fromRawData((char *)dataSet, length);
}
diff --git a/ui/qt/utils/field_information.h b/ui/qt/utils/field_information.h
index 9f24f18f56..19eacd3ca5 100644
--- a/ui/qt/utils/field_information.h
+++ b/ui/qt/utils/field_information.h
@@ -4,19 +4,7 @@
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * SPDX-License-Identifier: GPL-2.0+
*/
#ifndef FIELD_INFORMATION_H_
@@ -48,7 +36,6 @@ public:
struct Position
{
int start;
- int end;
int length;
};
diff --git a/ui/qt/widgets/byte_view_text.cpp b/ui/qt/widgets/byte_view_text.cpp
index 93612e514b..c66af61761 100644
--- a/ui/qt/widgets/byte_view_text.cpp
+++ b/ui/qt/widgets/byte_view_text.cpp
@@ -4,24 +4,9 @@
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * SPDX-License-Identifier: GPL-2.0+
*/
-// Some code based on QHexView by Even Teran
-// https://code.google.com/p/qhexview/
-
#include "byte_view_text.h"
#include <epan/charsets.h>
@@ -32,6 +17,7 @@
#include "wireshark_application.h"
#include "ui/recent.h"
+#include <ui/qt/utils/data_printer.h>
#include <ui/qt/utils/variant_pointer.h>
#include <QActionGroup>
@@ -40,39 +26,43 @@
#include <QScrollBar>
#include <QStyle>
#include <QStyleOption>
+#include <QTextLayout>
// To do:
// - Add recent settings and context menu items to show/hide the offset,
// and ASCII/EBCDIC.
// - Add a UTF-8 and possibly UTF-xx option to the ASCII display.
// - Add "copy bytes as" context menu items.
-
-// We don't obey the gui.hex_dump_highlight_style preference. If you
-// would like to add support for this you'll probably have to call
-// QPainter::drawText for each individual character.
+// - Add back hover.
+// - Move more common metrics to DataPrinter.
Q_DECLARE_METATYPE(bytes_view_type)
Q_DECLARE_METATYPE(packet_char_enc)
ByteViewText::ByteViewText(QByteArray data, packet_char_enc encoding, QWidget *parent) :
QAbstractScrollArea(parent),
- bold_highlight_(false),
+ layout_(new QTextLayout()),
encoding_(encoding),
hovered_byte_offset_(-1),
hovered_byte_lock_(false),
- p_bound_(0, 0),
- f_bound_(0, 0),
- fa_bound_(0, 0),
+ proto_start_(0),
+ proto_len_(0),
+ field_start_(0),
+ field_len_(0),
+ field_a_start_(0),
+ field_a_len_(0),
show_offset_(true),
show_hex_(true),
show_ascii_(true),
row_width_(recent.gui_bytes_view == BYTES_HEX ? 16 : 8),
- one_em_(0),
font_width_(0),
- line_spacing_(0),
- margin_(0)
+ line_height_(0)
{
data_ = data;
+ layout_->setCacheEnabled(true);
+
+ offset_normal_fg_ = ColorUtils::alphaBlend(palette().windowText(), palette().window(), 0.35);
+ offset_field_fg_ = ColorUtils::alphaBlend(palette().windowText(), palette().window(), 0.65);
createContextMenu();
@@ -86,6 +76,7 @@ ByteViewText::ByteViewText(QByteArray data, packet_char_enc encoding, QWidget *p
ByteViewText::~ByteViewText()
{
ctx_menu_.clear();
+ delete(layout_);
}
void ByteViewText::createContextMenu()
@@ -139,11 +130,6 @@ QByteArray ByteViewText::viewData()
return data_;
}
-void ByteViewText::setHighlightStyle(bool bold)
-{
- bold_highlight_ = bold;
-}
-
bool ByteViewText::isEmpty() const
{
return data_.isEmpty();
@@ -151,22 +137,22 @@ bool ByteViewText::isEmpty() const
QSize ByteViewText::minimumSizeHint() const
{
- // Allow panel to be shrinked to any size
+ // Allow panel to shrink to any size
return QSize();
}
-void ByteViewText::markProtocol(int start, int end)
+void ByteViewText::markProtocol(int start, int length)
{
- p_bound_ = QPair<guint, guint>(qMax(0, start), qMax(0, end));
- p_bound_save_ = p_bound_;
+ proto_start_ = start;
+ proto_len_ = length;
viewport()->update();
}
-void ByteViewText::markField(int start, int end)
+void ByteViewText::markField(int start, int length)
{
- f_bound_ = QPair<guint, guint>(qMax(0, start), qMax(0, end));
+ field_start_ = start;
+ field_len_ = length;
scrollToByte(start);
- f_bound_save_ = f_bound_;
viewport()->update();
}
@@ -177,10 +163,10 @@ void ByteViewText::moveToOffset(int pos)
}
-void ByteViewText::markAppendix(int start, int end)
+void ByteViewText::markAppendix(int start, int length)
{
- fa_bound_ = QPair<guint, guint>(qMax(0, start), qMax(0, end));
- fa_bound_save_ = f_bound_;
+ field_a_start_ = start;
+ field_a_len_ = length;
viewport()->update();
}
@@ -190,11 +176,12 @@ void ByteViewText::setMonospaceFont(const QFont &mono_font)
const QFontMetricsF fm(mono_font);
font_width_ = fm.width('M');
- line_spacing_ = fm.lineSpacing() + 0.5;
- one_em_ = fm.height();
- margin_ = fm.height() / 2;
setFont(mono_font);
+ layout_->setFont(mono_font);
+
+ // We should probably use ProtoTree::rowHeight.
+ line_height_ = fontMetrics().height();
updateScrollbars();
viewport()->update();
@@ -210,14 +197,12 @@ void ByteViewText::paintEvent(QPaintEvent *)
int row_y = 0;
// Starting byte offset
- guint offset = (guint) verticalScrollBar()->value() * row_width_;
+ int offset = verticalScrollBar()->value() * row_width_;
// Clear the area
painter.fillRect(viewport()->rect(), palette().base());
- // Offset background
- offset_normal_fg_.setColor(ColorUtils::alphaBlend(palette().windowText(), palette().window(), 0.35));
- offset_field_fg_.setColor(ColorUtils::alphaBlend(palette().windowText(), palette().window(), 0.65));
+ // Offset background. We want the entire height to be filled.
if (show_offset_) {
QRect offset_rect = QRect(viewport()->rect());
offset_rect.setWidth(offsetPixels());
@@ -228,34 +213,17 @@ void ByteViewText::paintEvent(QPaintEvent *)
return;
}
- // Map window coordinates to byte offsets
- x_pos_to_column_.clear();
- for (guint i = 0; i < row_width_; i++) {
- int sep_width = (i / separator_interval_) * font_width_;
- if (show_hex_) {
- // Hittable pixels extend 1/2 space on either side of the hex digits
- int pixels_per_byte = (recent.gui_bytes_view == BYTES_HEX ? 3 : 9) * font_width_;
- int hex_x = offsetPixels() + margin_ + sep_width + (i * pixels_per_byte) - (font_width_ / 2);
- for (int j = 0; j <= pixels_per_byte; j++) {
- x_pos_to_column_[hex_x + j] = i;
- }
- }
- if (show_ascii_) {
- int ascii_x = offsetPixels() + hexPixels() + margin_ + sep_width + (i * font_width_);
- for (int j = 0; j <= font_width_; j++) {
- x_pos_to_column_[ascii_x + j] = i;
- }
- }
- }
-
// Data rows
int widget_height = height();
painter.save();
- while( (int) (row_y + line_spacing_) < widget_height && (int) offset < (int) data_.count()) {
- drawOffsetLine(painter, offset, row_y);
+
+ x_pos_to_column_.clear();
+ while( (int) (row_y + line_height_) < widget_height && offset < (int) data_.count()) {
+ drawLine(&painter, offset, row_y);
offset += row_width_;
- row_y += line_spacing_;
+ row_y += line_height_;
}
+
painter.restore();
QStyleOptionFocusRect option;
@@ -304,187 +272,206 @@ void ByteViewText::contextMenuEvent(QContextMenuEvent *event)
// Private
-const int ByteViewText::separator_interval_ = 8; // Insert a space after this many bytes
+const int ByteViewText::separator_interval_ = DataPrinter::separatorInterval();
// Draw a line of byte view text for a given offset.
-// Text with different styles are split into fragments and passed to
-// flushOffsetFragment. Font character widths aren't necessarily whole
-// numbers so we track our X coordinate position using using floats.
-void ByteViewText::drawOffsetLine(QPainter &painter, const guint offset, const int row_y)
+// Text highlighting is handled using QTextLayout::FormatRange.
+void ByteViewText::drawLine(QPainter *painter, const int offset, const int row_y)
{
if (isEmpty()) {
return;
}
- guint tvb_len = data_.count();
- guint max_pos = qMin(offset + row_width_, tvb_len);
+
+ // Build our pixel to byte offset vector the first time through.
+ bool build_x_pos = x_pos_to_column_.empty() ? true : false;
+ int tvb_len = data_.count();
+ int max_tvb_pos = qMin(offset + row_width_, tvb_len) - 1;
+ QList<QTextLayout::FormatRange> fmt_list;
static const guchar hexchars[16] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
- QString text;
- HighlightMode hl_mode = ModeNormal, offset_mode = ModeOffsetNormal;
- qreal hex_x = offsetPixels() + margin_;
- qreal ascii_x = offsetPixels() + hexPixels() + margin_;
+ QString line;
+ HighlightMode offset_mode = ModeOffsetNormal;
+
+ // Offset.
+ if (show_offset_) {
+ line = QString(" %1 ").arg(offset, offsetChars(false), 16, QChar('0'));
+ if (build_x_pos) {
+ x_pos_to_column_.fill(-1, fontMetrics().width(line));
+ }
+ }
// Hex
if (show_hex_) {
- for (guint tvb_pos = offset; tvb_pos < max_pos; tvb_pos++) {
- HighlightMode hex_state = ModeNormal;
- bool add_space = tvb_pos != offset;
- bool draw_hover = tvb_pos == hovered_byte_offset_;
-
- if ((tvb_pos >= f_bound_.first && tvb_pos < f_bound_.second) || (tvb_pos >= fa_bound_.first && tvb_pos < fa_bound_.second)) {
- hex_state = ModeField;
- offset_mode = ModeOffsetField;
- } else if (tvb_pos >= p_bound_.first && tvb_pos < p_bound_.second) {
- hex_state = ModeProtocol;
- }
+ int ascii_start = line.length() + DataPrinter::hexChars() + 3;
+ // Extra hover space before and after each byte.
+ int slop = font_width_ / 2;
- if (hex_state != hl_mode || draw_hover) {
- if ((hl_mode == ModeNormal || (hl_mode == ModeProtocol && hex_state == ModeField) || draw_hover) && add_space) {
- add_space = false;
- text += ' ';
- /* insert a space every separator_interval_ bytes */
- if ((tvb_pos % separator_interval_) == 0)
- text += ' ';
- }
- hex_x += flushOffsetFragment(painter, hex_x, row_y, hl_mode, text);
- hl_mode = hex_state;
- }
+ if (build_x_pos) {
+ x_pos_to_column_.append(QVector<int>().fill(-1, slop));
+ }
- if (add_space) {
- text += ' ';
- /* insert a space every separator_interval_ bytes */
- if ((tvb_pos % separator_interval_) == 0)
- text += ' ';
+ for (int tvb_pos = offset; tvb_pos <= max_tvb_pos; tvb_pos++) {
+ line += ' ';
+ /* insert a space every separator_interval_ bytes */
+ if ((tvb_pos != offset) && ((tvb_pos % separator_interval_) == 0)) {
+ line += ' ';
+ x_pos_to_column_.append(QVector<int>().fill(tvb_pos - offset - 1, font_width_));
}
switch (recent.gui_bytes_view) {
case BYTES_HEX:
- text += hexchars[(data_[tvb_pos] & 0xf0) >> 4];
- text += hexchars[data_[tvb_pos] & 0x0f];
+ line += hexchars[(data_[tvb_pos] & 0xf0) >> 4];
+ line += hexchars[data_[tvb_pos] & 0x0f];
break;
case BYTES_BITS:
/* XXX, bitmask */
- for (int j = 7; j >= 0; j--)
- text += (data_[tvb_pos] & (1 << j)) ? '1' : '0';
+ for (int j = 7; j >= 0; j--) {
+ line += (data_[tvb_pos] & (1 << j)) ? '1' : '0';
+ }
break;
}
- if (draw_hover) {
- hex_x += flushOffsetFragment(painter, hex_x, row_y, ModeHover, text);
+ if (build_x_pos) {
+ x_pos_to_column_.append(QVector<int>().fill(tvb_pos - offset, fontMetrics().width(line) - x_pos_to_column_.size() + slop));
}
}
+ line += QString(ascii_start - line.length(), ' ');
+ if (build_x_pos) {
+ x_pos_to_column_.append(QVector<int>().fill(-1, fontMetrics().width(line) - x_pos_to_column_.size()));
+ }
+
+ addHexFormatRange(fmt_list, proto_start_, proto_len_, offset, max_tvb_pos, ModeProtocol);
+ if (addHexFormatRange(fmt_list, field_start_, field_len_, offset, max_tvb_pos, ModeField)) {
+ offset_mode = ModeOffsetField;
+ }
+ addHexFormatRange(fmt_list, field_a_start_, field_a_len_, offset, max_tvb_pos, ModeField);
+ if (hovered_byte_offset_ >= offset && hovered_byte_offset_ <= max_tvb_pos) {
+ addHexFormatRange(fmt_list, hovered_byte_offset_, hovered_byte_offset_ + 1, offset, max_tvb_pos, ModeField);
+ }
}
- if (text.length() > 0) {
- flushOffsetFragment(painter, hex_x, row_y, hl_mode, text);
- }
- hl_mode = ModeNormal;
// ASCII
if (show_ascii_) {
- for (guint tvb_pos = offset; tvb_pos < max_pos; tvb_pos++) {
- HighlightMode ascii_state = ModeNormal;
- bool add_space = tvb_pos != offset;
- bool highlight_text = tvb_pos == hovered_byte_offset_;
-
- if ((tvb_pos >= f_bound_.first && tvb_pos < f_bound_.second) || (tvb_pos >= fa_bound_.first && tvb_pos < fa_bound_.second)) {
- ascii_state = ModeField;
- offset_mode = ModeOffsetField;
- } else if (tvb_pos >= p_bound_.first && tvb_pos < p_bound_.second) {
- ascii_state = ModeProtocol;
- }
-
- if (ascii_state != hl_mode || highlight_text) {
- if ((hl_mode == ModeNormal || (hl_mode == ModeProtocol && ascii_state == ModeField) || highlight_text) && add_space) {
- add_space = false;
- /* insert a space every separator_interval_ bytes */
- if ((tvb_pos % separator_interval_) == 0)
- text += ' ';
+ for (int tvb_pos = offset; tvb_pos <= max_tvb_pos; tvb_pos++) {
+ /* insert a space every separator_interval_ bytes */
+ if ((tvb_pos != offset) && ((tvb_pos % separator_interval_) == 0)) {
+ line += ' ';
+ if (build_x_pos) {
+ x_pos_to_column_.append(QVector<int>().fill(tvb_pos - offset - 1, font_width_ / 2));
}
- ascii_x += flushOffsetFragment(painter, ascii_x, row_y, hl_mode, text);
- hl_mode = ascii_state;
- }
-
- if (add_space) {
- /* insert a space every separator_interval_ bytes */
- if ((tvb_pos % separator_interval_) == 0)
- text += ' ';
}
guchar c = (encoding_ == PACKET_CHAR_ENC_CHAR_EBCDIC) ?
EBCDIC_to_ASCII1(data_[tvb_pos]) :
data_[tvb_pos];
- text += g_ascii_isprint(c) ? c : '.';
- if (highlight_text) {
- ascii_x += flushOffsetFragment(painter, ascii_x, row_y, ModeHover, text);
+ if (g_ascii_isprint(c)) {
+ line += c;
+ } else {
+ line += UTF8_MIDDLE_DOT;
+ }
+ if (build_x_pos) {
+ x_pos_to_column_.append(QVector<int>().fill(tvb_pos - offset, fontMetrics().width(line) - x_pos_to_column_.size()));
}
}
- }
- if (text.length() > 0) {
- flushOffsetFragment(painter, ascii_x, row_y, hl_mode, text);
+ addAsciiFormatRange(fmt_list, proto_start_, proto_len_, offset, max_tvb_pos, ModeProtocol);
+ if (addAsciiFormatRange(fmt_list, field_start_, field_len_, offset, max_tvb_pos, ModeField)) {
+ offset_mode = ModeOffsetField;
+ }
+ addAsciiFormatRange(fmt_list, field_a_start_, field_a_len_, offset, max_tvb_pos, ModeField);
+ if (hovered_byte_offset_ >= offset && hovered_byte_offset_ <= max_tvb_pos) {
+ addAsciiFormatRange(fmt_list, hovered_byte_offset_, hovered_byte_offset_ + 1, offset, max_tvb_pos, ModeField);
+ }
}
- // Offset. Must be drawn last in order for offset_state to be set.
- if (show_offset_) {
- text = QString("%1").arg(offset, offsetChars(), 16, QChar('0'));
- flushOffsetFragment(painter, margin_, row_y, offset_mode, text);
- }
+ // XXX Fields won't be highlighted if neither hex nor ascii are enabled.
+ addFormatRange(fmt_list, 0, offsetChars(), offset_mode);
+
+ layout_->clearLayout();
+ layout_->clearAdditionalFormats();
+ layout_->setText(line);
+ layout_->setAdditionalFormats(fmt_list);
+ layout_->beginLayout();
+ QTextLine tl = layout_->createLine();
+ tl.setLineWidth(totalPixels());
+ tl.setPosition(QPointF(0.0, 0.0));
+ layout_->endLayout();
+ layout_->draw(painter, QPointF(0.0, row_y));
}
-// Draws a fragment of byte view text at the specifiec location using colors
-// for the specified state. Clears the text and returns the pixel width of the
-// drawn text.
-qreal ByteViewText::flushOffsetFragment(QPainter &painter, qreal x, int y, HighlightMode mode, QString &text)
+bool ByteViewText::addFormatRange(QList<QTextLayout::FormatRange> &fmt_list, int start, int length, HighlightMode mode)
{
- if (text.length() < 1) {
- return 0;
- }
- QFontMetricsF fm(mono_font_);
- qreal width = fm.width(text);
- QRectF area(x, y, width, line_spacing_);
- // Background
- switch (mode) {
- case ModeField:
- painter.fillRect(area, palette().highlight());
- break;
- case ModeProtocol:
- painter.fillRect(area, palette().window());
- break;
- case ModeHover:
- painter.fillRect(area, ColorUtils::byteViewHoverColor(true));
- break;
- default:
- break;
+ if (length < 1 || mode == ModeNormal) {
+ return false;
}
- // Text
- QBrush text_brush;
+ QTextLayout::FormatRange format_range;
+ format_range.start = start;
+ format_range.length = length;
+ format_range.format.setProperty(QTextFormat::LineHeight, line_height_);
switch (mode) {
case ModeNormal:
- case ModeProtocol:
- default:
- text_brush = palette().windowText();
break;
case ModeField:
- text_brush = palette().highlightedText();
+ format_range.format.setBackground(palette().highlight());
+ break;
+ case ModeProtocol:
+ format_range.format.setBackground(palette().window());
break;
case ModeOffsetNormal:
- text_brush = offset_normal_fg_;
+ format_range.format.setForeground(offset_normal_fg_);
break;
case ModeOffsetField:
- text_brush = offset_field_fg_;
+ format_range.format.setForeground(offset_field_fg_);
break;
case ModeHover:
- text_brush = ColorUtils::byteViewHoverColor(false);
+ format_range.format.setForeground(ColorUtils::byteViewHoverColor(false));
+ format_range.format.setBackground(ColorUtils::byteViewHoverColor(true));
break;
}
+ fmt_list << format_range;
+ return true;
+}
- painter.setPen(QPen(text_brush.color()));
- painter.drawText(area, Qt::AlignTop, text);
- text.clear();
- return width;
+bool ByteViewText::addHexFormatRange(QList<QTextLayout::FormatRange> &fmt_list, int mark_start, int mark_length, int tvb_offset, int max_tvb_pos, ByteViewText::HighlightMode mode)
+{
+ int mark_end = mark_start + mark_length - 1;
+ if (mark_start < 0 || mark_length < 1) return false;
+ if (mark_start > max_tvb_pos && mark_end < tvb_offset) return false;
+
+ int chars_per_byte = recent.gui_bytes_view == BYTES_HEX ? 3 : 9;
+ int byte_start = qMax(tvb_offset, mark_start) - tvb_offset;
+ int byte_end = qMin(max_tvb_pos, mark_end) - tvb_offset;
+ int fmt_start = offsetChars() + 1 // offset + spacing
+ + (byte_start / separator_interval_)
+ + (byte_start * chars_per_byte);
+ int fmt_length = offsetChars() + 1 // offset + spacing
+ + (byte_end / separator_interval_)
+ + (byte_end * chars_per_byte)
+ + 2 // Both the high and low nibbles.
+ - fmt_start;
+ return addFormatRange(fmt_list, fmt_start, fmt_length, mode);
+}
+
+bool ByteViewText::addAsciiFormatRange(QList<QTextLayout::FormatRange> &fmt_list, int mark_start, int mark_length, int tvb_offset, int max_tvb_pos, ByteViewText::HighlightMode mode)
+{
+ int mark_end = mark_start + mark_length - 1;
+ if (mark_start < 0 || mark_length < 1) return false;
+ if (mark_start > max_tvb_pos && mark_end < tvb_offset) return false;
+
+ int byte_start = qMax(tvb_offset, mark_start) - tvb_offset;
+ int byte_end = qMin(max_tvb_pos, mark_end) - tvb_offset;
+ int fmt_start = offsetChars() + DataPrinter::hexChars() + 3 // offset + hex + spacing
+ + (byte_start / separator_interval_)
+ + byte_start;
+ int fmt_length = offsetChars() + DataPrinter::hexChars() + 3 // offset + hex + spacing
+ + (byte_end / separator_interval_)
+ + byte_end
+ + 1 // Just one character.
+ - fmt_start;
+ return addFormatRange(fmt_list, fmt_start, fmt_length, mode);
}
void ByteViewText::scrollToByte(int byte)
@@ -493,19 +480,22 @@ void ByteViewText::scrollToByte(int byte)
}
// Offset character width
-int ByteViewText::offsetChars()
+int ByteViewText::offsetChars(bool include_pad)
{
+ int padding = include_pad ? 2 : 0;
if (! isEmpty() && data_.count() > 0xffff) {
- return 8;
+ return 8 + padding;
}
- return 4;
+ return 4 + padding;
}
// Offset pixel width
int ByteViewText::offsetPixels()
{
if (show_offset_) {
- return offsetChars() * font_width_ + one_em_;
+ // One pad space before and after
+ QString zeroes = QString(offsetChars(), '0');
+ return fontMetrics().width(zeroes);
}
return 0;
}
@@ -514,8 +504,9 @@ int ByteViewText::offsetPixels()
int ByteViewText::hexPixels()
{
if (show_hex_) {
- int digits_per_byte = recent.gui_bytes_view == BYTES_HEX ? 3 : 9;
- return (((row_width_ * digits_per_byte) + ((row_width_ - 1) / separator_interval_)) * font_width_) + one_em_;
+ // One pad space before and after
+ QString zeroes = QString(DataPrinter::hexChars() + 2, '0');
+ return fontMetrics().width(zeroes);
}
return 0;
}
@@ -523,7 +514,10 @@ int ByteViewText::hexPixels()
int ByteViewText::asciiPixels()
{
if (show_ascii_) {
- return ((row_width_ + ((row_width_ - 1) / separator_interval_)) * font_width_) + one_em_;
+ // Two pad spaces before, one after
+ int ascii_chars = (row_width_ + ((row_width_ - 1) / separator_interval_));
+ QString zeroes = QString(ascii_chars + 3, '0');
+ return fontMetrics().width(zeroes);
}
return 0;
}
@@ -533,20 +527,22 @@ int ByteViewText::totalPixels()
return offsetPixels() + hexPixels() + asciiPixels();
}
+// We do chunky (per-character) scrolling because it makes some of the
+// math easier. Should we do smooth scrolling?
void ByteViewText::updateScrollbars()
{
const int length = data_.count();
if (length > 0) {
- qint64 maxval = length / row_width_ + ((length % row_width_) ? 1 : 0) - viewport()->height() / line_spacing_;
+ int all_lines_height = length / row_width_ + ((length % row_width_) ? 1 : 0) - viewport()->height() / line_height_;
- verticalScrollBar()->setRange(0, int(qMax((qint64)0, maxval)));
- horizontalScrollBar()->setRange(0, qMax(0, static_cast<int>((totalPixels() - viewport()->width()) / font_width_)));
+ verticalScrollBar()->setRange(0, qMax(0, all_lines_height));
+ horizontalScrollBar()->setRange(0, qMax(0, int((totalPixels() - viewport()->width()) / font_width_)));
}
}
int ByteViewText::byteOffsetAtPixel(QPoint pos)
{
- int byte = (verticalScrollBar()->value() + (pos.y() / line_spacing_)) * row_width_;
+ int byte = (verticalScrollBar()->value() + (pos.y() / line_height_)) * row_width_;
int x = (horizontalScrollBar()->value() * font_width_) + pos.x();
int col = x_pos_to_column_.value(x, -1);
diff --git a/ui/qt/widgets/byte_view_text.h b/ui/qt/widgets/byte_view_text.h
index f5a7430f94..657f4e950a 100644
--- a/ui/qt/widgets/byte_view_text.h
+++ b/ui/qt/widgets/byte_view_text.h
@@ -4,19 +4,7 @@
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * SPDX-License-Identifier: GPL-2.0+
*/
#ifndef BYTE_VIEW_TEXT_H
@@ -27,11 +15,13 @@
#include "ui/recent.h"
#include <QAbstractScrollArea>
-#include <QString>
#include <QFont>
-#include <QSize>
+#include <QVector>
#include <QMenu>
-#include <QMap>
+#include <QSize>
+#include <QString>
+#include <QTextLayout>
+#include <QVector>
// XXX - Is there any reason we shouldn't add ByteViewImage, etc?
@@ -46,13 +36,11 @@ public:
virtual QSize minimumSizeHint() const;
void setFormat(bytes_view_type format);
- void setHighlightStyle(bool bold);
bool isEmpty() const;
QByteArray viewData();
signals:
-
void byteHovered(int pos);
void byteSelected(int pos);
@@ -61,9 +49,9 @@ public slots:
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 markProtocol(int start, int length);
+ void markField(int start, int length);
+ void markAppendix(int start, int length);
void moveToOffset(int pos);
@@ -86,17 +74,20 @@ private:
ModeHover
} HighlightMode;
+ QTextLayout *layout_;
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 drawLine(QPainter *painter, const int offset, const int row_y);
+ bool addFormatRange(QList<QTextLayout::FormatRange> &fmt_list, int start, int length, HighlightMode mode);
+ bool addHexFormatRange(QList<QTextLayout::FormatRange> &fmt_list, int mark_start, int mark_length, int tvb_offset, int max_tvb_pos, HighlightMode mode);
+ bool addAsciiFormatRange(QList<QTextLayout::FormatRange> &fmt_list, int mark_start, int mark_length, int tvb_offset, int max_tvb_pos, HighlightMode mode);
void scrollToByte(int byte);
void updateScrollbars();
int byteOffsetAtPixel(QPoint pos);
void createContextMenu();
- int offsetChars();
+ int offsetChars(bool include_pad = true);
int offsetPixels();
int hexPixels();
int asciiPixels();
@@ -106,37 +97,32 @@ private:
// Fonts and colors
QFont mono_font_;
-// QFont mono_bold_font_;
- QBrush offset_normal_fg_;
- QBrush offset_field_fg_;
-
- bool bold_highlight_;
+ QColor offset_normal_fg_;
+ QColor offset_field_fg_;
// Data
packet_char_enc encoding_; // ASCII or EBCDIC
QMenu ctx_menu_;
// Data highlight
- guint hovered_byte_offset_;
+ int hovered_byte_offset_;
bool hovered_byte_lock_;
- QPair<guint,guint> p_bound_;
- QPair<guint,guint> f_bound_;
- QPair<guint,guint> fa_bound_;
- QPair<guint,guint> p_bound_save_;
- QPair<guint,guint> f_bound_save_;
- QPair<guint,guint> fa_bound_save_;
+ int proto_start_;
+ int proto_len_;
+ int field_start_;
+ int field_len_;
+ int field_a_start_;
+ int field_a_len_;
bool show_offset_; // Should we show the byte offset?
bool show_hex_; // Should we show the hex display?
bool show_ascii_; // Should we show the ASCII display?
- guint row_width_; // Number of bytes per line
- int one_em_; // Font character height
- qreal font_width_; // Font character width
- int line_spacing_; // Font line spacing
- int margin_; // Text margin
+ int row_width_; // Number of bytes per line
+ qreal font_width_; // Single character width and text margin. NOTE: Use fontMetrics::width for multiple characters.
+ int line_height_; // Font line spacing
// Data selection
- QMap<int,int> x_pos_to_column_;
+ QVector<int> x_pos_to_column_;
private slots:
void setHexDisplayFormat(QAction *action);