From 1832f2bc3948248bf21acab5dd16fca8d5477a1a Mon Sep 17 00:00:00 2001 From: John Thacker Date: Sun, 11 Aug 2024 15:23:17 -0400 Subject: [PATCH] Qt: Add GUI support for saving in LZ4 format Add GUI support for saving in LZ4 format as well as gzip and uncompressed. Replace the current checkbox with a group box. The group box looks better alongside the packet range group box for Export Packet Dissections and would be appropriate to substitute into the Capture Options dialog in a later commit; a combobox might look more natural for the ordinary Save As window. Change the work to fix up the file extension a bit, so that it can switch between .gz and .lz4 --- README.md | 8 +++- doc/release-notes.adoc | 9 ++++ ui/logray/CMakeLists.txt | 2 + ui/qt/CMakeLists.txt | 2 + ui/qt/capture_file_dialog.cpp | 45 ++++++++--------- ui/qt/capture_file_dialog.h | 3 +- ui/qt/widgets/compression_group_box.cpp | 64 +++++++++++++++++++++++++ ui/qt/widgets/compression_group_box.h | 41 ++++++++++++++++ wiretap/file_access.c | 2 +- 9 files changed, 147 insertions(+), 29 deletions(-) create mode 100644 ui/qt/widgets/compression_group_box.cpp create mode 100644 ui/qt/widgets/compression_group_box.h diff --git a/README.md b/README.md index 3e67c211a6..f99d693a1c 100644 --- a/README.md +++ b/README.md @@ -89,10 +89,14 @@ the required compression library was available when Wireshark was compiled. Currently supported compression formats are: - GZIP -- ZSTD - LZ4 +- ZSTD -You can disable zlib support by running `cmake -DENABLE_ZLIB=OFF`. +GZIP and LZ4 (when using independent blocks, which is the default) support +fast random seeking, which offers much better GUI performance on large files. +Any of these compression formats can be disabled at compile time by passing +the corresponding option to cmake, i.e., `cmake -DENABLE_ZLIB=OFF`, +`cmake -DENABLE_LZ4=OFF`, or `cmake -DENABLE_ZSTD=OFF`. Although Wireshark can read AIX iptrace files, the documentation on AIX's iptrace packet-trace command is sparse. The `iptrace` command diff --git a/doc/release-notes.adoc b/doc/release-notes.adoc index 00f22e4d06..1c78556c26 100644 --- a/doc/release-notes.adoc +++ b/doc/release-notes.adoc @@ -379,6 +379,15 @@ The following features are either new or have been significantly updated since v * Global profiles can be used in tshark by using `--global-profile` option. +* Fast random access is supported with LZ4 compressed files (when compressed + with independent blocks, which is the default). This provides much more + responsive GUI performance when jumping to different packets. gzip compressed + files also support fast random seeking (since 1.8.0), but Zstd compressed + do not. + +* Existing capture files can be saved with LZ4 compression. LZ4 has an emphasis + on speed and may be particularly useful for large files. + === Removed Features and Support * The tshark `-G` option with no argument is deprecated and will be removed in diff --git a/ui/logray/CMakeLists.txt b/ui/logray/CMakeLists.txt index 2f44bb6794..9e11340673 100644 --- a/ui/logray/CMakeLists.txt +++ b/ui/logray/CMakeLists.txt @@ -22,6 +22,7 @@ set(WIRESHARK_WIDGET_HEADERS ${CMAKE_SOURCE_DIR}/ui/qt/widgets/capture_filter_combo.h ${CMAKE_SOURCE_DIR}/ui/qt/widgets/capture_filter_edit.h ${CMAKE_SOURCE_DIR}/ui/qt/widgets/clickable_label.h + ${CMAKE_SOURCE_DIR}/ui/qt/widgets/compression_group_box.h ${CMAKE_SOURCE_DIR}/ui/qt/widgets/copy_from_profile_button.h ${CMAKE_SOURCE_DIR}/ui/qt/widgets/detachable_tabwidget.h ${CMAKE_SOURCE_DIR}/ui/qt/widgets/display_filter_combo.h @@ -261,6 +262,7 @@ set(WIRESHARK_WIDGET_SRCS ${CMAKE_SOURCE_DIR}/ui/qt/widgets/capture_filter_combo.cpp ${CMAKE_SOURCE_DIR}/ui/qt/widgets/capture_filter_edit.cpp ${CMAKE_SOURCE_DIR}/ui/qt/widgets/clickable_label.cpp + ${CMAKE_SOURCE_DIR}/ui/qt/widgets/compression_group_box.cpp ${CMAKE_SOURCE_DIR}/ui/qt/widgets/copy_from_profile_button.cpp ${CMAKE_SOURCE_DIR}/ui/qt/widgets/detachable_tabwidget.cpp ${CMAKE_SOURCE_DIR}/ui/qt/widgets/display_filter_combo.cpp diff --git a/ui/qt/CMakeLists.txt b/ui/qt/CMakeLists.txt index ff20f0d378..3308d6f229 100644 --- a/ui/qt/CMakeLists.txt +++ b/ui/qt/CMakeLists.txt @@ -22,6 +22,7 @@ set(WIRESHARK_WIDGET_HEADERS widgets/capture_filter_combo.h widgets/capture_filter_edit.h widgets/clickable_label.h + widgets/compression_group_box.h widgets/copy_from_profile_button.h widgets/detachable_tabwidget.h widgets/display_filter_combo.h @@ -290,6 +291,7 @@ set(WIRESHARK_WIDGET_SRCS widgets/capture_filter_combo.cpp widgets/capture_filter_edit.cpp widgets/clickable_label.cpp + widgets/compression_group_box.cpp widgets/copy_from_profile_button.cpp widgets/detachable_tabwidget.cpp widgets/display_filter_combo.cpp diff --git a/ui/qt/capture_file_dialog.cpp b/ui/qt/capture_file_dialog.cpp index 2ea16ecebf..884cb3f936 100644 --- a/ui/qt/capture_file_dialog.cpp +++ b/ui/qt/capture_file_dialog.cpp @@ -418,23 +418,22 @@ void CaptureFileDialog::fixFilenameExtension() } // Fixup the new suffix based on whether we're compressing or not. - if (compressionType() == WTAP_UNCOMPRESSED) { - // Not compressing; strip off any compression suffix - GSList *compression_type_extensions = wtap_get_all_compression_type_extensions_list(); - for (GSList *compression_type_extension = compression_type_extensions; - compression_type_extension != NULL; - compression_type_extension = g_slist_next(compression_type_extension)) { - QString suffix = QString(".") + (char *)compression_type_extension->data; - if (new_suffix.endsWith(suffix)) { - // - // It ends with this compression suffix; chop it off. - // - new_suffix.chop(suffix.size()); - break; - } + // Strip off any compression suffix + GSList *compression_type_extensions = wtap_get_all_compression_type_extensions_list(); + for (GSList *compression_type_extension = compression_type_extensions; + compression_type_extension != NULL; + compression_type_extension = g_slist_next(compression_type_extension)) { + QString suffix = QString(".") + (char *)compression_type_extension->data; + if (new_suffix.endsWith(suffix)) { + // + // It ends with this compression suffix; chop it off. + // + new_suffix.chop(suffix.size()); + break; } - g_slist_free(compression_type_extensions); - } else { + } + g_slist_free(compression_type_extensions); + if (compressionType() != WTAP_UNCOMPRESSED) { // Compressing; append the appropriate compression suffix. QString compressed_file_extension = QString(".") + wtap_compression_type_extension(compressionType()); if (valid_extensions.contains(new_suffix + compressed_file_extension)) { @@ -503,7 +502,7 @@ int CaptureFileDialog::selectedFileType() { } wtap_compression_type CaptureFileDialog::compressionType() { - return compress_.isChecked() ? WTAP_GZIP_COMPRESSED : WTAP_UNCOMPRESSED; + return compress_group_box_.compressionType(); } void CaptureFileDialog::addDisplayFilterEdit(QString &display_filter) { @@ -539,15 +538,11 @@ void CaptureFileDialog::addFormatTypeSelector(QVBoxLayout &v_box) { } void CaptureFileDialog::addGzipControls(QVBoxLayout &v_box) { - compress_.setText(tr("Compress with g&zip")); - if (cap_file_->compression_type == WTAP_GZIP_COMPRESSED && - wtap_dump_can_compress(default_ft_)) { - compress_.setChecked(true); - } else { - compress_.setChecked(false); + if (wtap_dump_can_compress(default_ft_)) { + compress_group_box_.setCompressionType(cap_file_->compression_type); } - v_box.addWidget(&compress_, 0, Qt::AlignTop); - connect(&compress_, &QCheckBox::stateChanged, this, &CaptureFileDialog::fixFilenameExtension); + v_box.addWidget(&compress_group_box_, 0, Qt::AlignTop); + connect(&compress_group_box_, &CompressionGroupBox::stateChanged, this, &CaptureFileDialog::fixFilenameExtension); } diff --git a/ui/qt/capture_file_dialog.h b/ui/qt/capture_file_dialog.h index ad41efd624..2c48100abb 100644 --- a/ui/qt/capture_file_dialog.h +++ b/ui/qt/capture_file_dialog.h @@ -13,6 +13,7 @@ #include #include +#include #include "packet_range_group_box.h" #include "ui/help_url.h" @@ -117,7 +118,7 @@ private: int default_ft_; - QCheckBox compress_; + CompressionGroupBox compress_group_box_; PacketRangeGroupBox packet_range_group_box_; QPushButton *save_bt_; diff --git a/ui/qt/widgets/compression_group_box.cpp b/ui/qt/widgets/compression_group_box.cpp new file mode 100644 index 0000000000..b86c04ed80 --- /dev/null +++ b/ui/qt/widgets/compression_group_box.cpp @@ -0,0 +1,64 @@ +/* @file + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "compression_group_box.h" + +#include +#include +#include + +CompressionGroupBox::CompressionGroupBox(QWidget *parent) : + QGroupBox(parent) +{ + setTitle(tr("Compression options")); + setFlat(true); + + + bg_ = new QButtonGroup(this); + QVBoxLayout *vbox = new QVBoxLayout(); + + QRadioButton *radio1 = new QRadioButton(tr("&Uncompressed")); + bg_->addButton(radio1, WTAP_UNCOMPRESSED); + vbox->addWidget(radio1); + +#if defined (HAVE_ZLIB) || defined (HAVE_ZLIBNG) + QRadioButton *radio2 = new QRadioButton(tr("Compress with g&zip")); + bg_->addButton(radio2, WTAP_GZIP_COMPRESSED); + vbox->addWidget(radio2); +#endif +#ifdef HAVE_LZ4FRAME_H + QRadioButton *radio3 = new QRadioButton(tr("Compress with &LZ4")); + bg_->addButton(radio3, WTAP_LZ4_COMPRESSED); + vbox->addWidget(radio3); +#endif + + radio1->setChecked(true); + + setLayout(vbox); + + connect(bg_, &QButtonGroup::idToggled, [=] { emit stateChanged(); }); +} + +CompressionGroupBox::~CompressionGroupBox() +{ +} + +wtap_compression_type CompressionGroupBox::compressionType() const +{ + return static_cast(bg_->checkedId()); +} + +void CompressionGroupBox::setCompressionType(wtap_compression_type type) +{ + QAbstractButton *button = bg_->button(type); + if (button != nullptr) { + button->setChecked(true); + } +} + diff --git a/ui/qt/widgets/compression_group_box.h b/ui/qt/widgets/compression_group_box.h new file mode 100644 index 0000000000..4e70ca2d09 --- /dev/null +++ b/ui/qt/widgets/compression_group_box.h @@ -0,0 +1,41 @@ +/** @file + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef COMPRESSION_GROUP_BOX_H +#define COMPRESSION_GROUP_BOX_H + +#include + +#include + +#include + +class QButtonGroup; + +/** + * UI element for selecting compression type from among those supported. + */ +class CompressionGroupBox : public QGroupBox +{ + Q_OBJECT + +public: + explicit CompressionGroupBox(QWidget *parent = 0); + ~CompressionGroupBox(); + wtap_compression_type compressionType() const; + void setCompressionType(wtap_compression_type type); + +signals: + void stateChanged(); + +private: + QButtonGroup *bg_; +}; + +#endif // COMPRESSION_GROUP_BOX_H diff --git a/wiretap/file_access.c b/wiretap/file_access.c index e386df5ce8..7e858d1848 100644 --- a/wiretap/file_access.c +++ b/wiretap/file_access.c @@ -2124,7 +2124,7 @@ wtap_dump_can_open(int file_type_subtype) * Return whether we know how to write a compressed file of the specified * file type. */ -#if defined (HAVE_ZLIB) || defined (HAVE_ZLIBNG) +#if defined (HAVE_ZLIB) || defined (HAVE_ZLIBNG) || defined (HAVE_LZ4FRAME_H) bool wtap_dump_can_compress(int file_type_subtype) {