2016-02-07 21:15:12 +00:00
|
|
|
/* show_packet_bytes_dialog.cpp
|
|
|
|
*
|
|
|
|
* Wireshark - Network traffic analyzer
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "show_packet_bytes_dialog.h"
|
|
|
|
#include <ui_show_packet_bytes_dialog.h>
|
|
|
|
|
|
|
|
#include "main_window.h"
|
|
|
|
#include "wireshark_application.h"
|
|
|
|
|
|
|
|
#include "epan/charsets.h"
|
2017-12-03 18:53:58 +00:00
|
|
|
|
2016-02-14 22:01:09 +00:00
|
|
|
#include "wsutil/base64.h"
|
|
|
|
#include "wsutil/utf8_entities.h"
|
2016-02-07 21:15:12 +00:00
|
|
|
|
2016-02-14 22:01:09 +00:00
|
|
|
#include <QAction>
|
2016-02-07 21:15:12 +00:00
|
|
|
#include <QImage>
|
|
|
|
#include <QKeyEvent>
|
2016-02-14 22:01:09 +00:00
|
|
|
#include <QMenu>
|
2016-02-07 21:15:12 +00:00
|
|
|
#include <QPrintDialog>
|
|
|
|
#include <QPrinter>
|
|
|
|
#include <QTextStream>
|
|
|
|
|
|
|
|
// To do:
|
|
|
|
// - Add show as custom protocol in a Packet Details view
|
2016-02-10 08:07:13 +00:00
|
|
|
// - Use ByteViewText to ShowAsHexDump and supplementary view for custom protocol
|
2016-02-07 21:15:12 +00:00
|
|
|
// - Handle large data blocks
|
|
|
|
|
|
|
|
ShowPacketBytesDialog::ShowPacketBytesDialog(QWidget &parent, CaptureFile &cf) :
|
|
|
|
WiresharkDialog(parent, cf),
|
|
|
|
ui(new Ui::ShowPacketBytesDialog),
|
2016-02-14 22:01:09 +00:00
|
|
|
finfo_(cf.capFile()->finfo_selected),
|
|
|
|
decode_as_(DecodeAsNone),
|
2016-02-14 18:34:11 +00:00
|
|
|
show_as_(ShowAsASCII),
|
|
|
|
use_regex_find_(false)
|
2016-02-07 21:15:12 +00:00
|
|
|
{
|
|
|
|
ui->setupUi(this);
|
2016-02-28 18:23:20 +00:00
|
|
|
loadGeometry(parent.width() * 2 / 3, parent.height() * 3 / 4);
|
2016-02-07 21:15:12 +00:00
|
|
|
|
2016-02-14 22:01:09 +00:00
|
|
|
QString field_name = QString("%1 (%2)").arg(finfo_->hfinfo->name, finfo_->hfinfo->abbrev);
|
2016-02-10 19:39:55 +00:00
|
|
|
setWindowSubtitle (field_name);
|
2016-02-07 21:15:12 +00:00
|
|
|
|
2016-02-14 22:01:09 +00:00
|
|
|
hint_label_ = tr("Frame %1, %2, %Ln byte(s).", "", finfo_->length)
|
|
|
|
.arg(cf.capFile()->current_frame->num)
|
|
|
|
.arg(field_name);
|
2016-02-07 21:15:12 +00:00
|
|
|
|
|
|
|
ui->tePacketBytes->installEventFilter(this);
|
|
|
|
|
2016-02-14 22:01:09 +00:00
|
|
|
connect(ui->tePacketBytes, SIGNAL(showSelected(int,int)), this, SLOT(showSelected(int,int)));
|
2016-02-14 18:34:11 +00:00
|
|
|
connect(ui->leFind, SIGNAL(useRegexFind(bool)), this, SLOT(useRegexFind(bool)));
|
|
|
|
|
2016-02-14 22:01:09 +00:00
|
|
|
ui->cbDecodeAs->blockSignals(true);
|
|
|
|
ui->cbDecodeAs->addItem(tr("None"), DecodeAsNone);
|
|
|
|
ui->cbDecodeAs->addItem(tr("Base64"), DecodeAsBASE64);
|
|
|
|
ui->cbDecodeAs->addItem(tr("Compressed"), DecodeAsCompressed);
|
2016-05-19 10:09:33 +00:00
|
|
|
ui->cbDecodeAs->addItem(tr("Quoted-Printable"), DecodeAsQuotedPrintable);
|
2016-02-14 22:01:09 +00:00
|
|
|
ui->cbDecodeAs->addItem(tr("ROT13"), DecodeAsROT13);
|
|
|
|
ui->cbDecodeAs->blockSignals(false);
|
|
|
|
|
2016-02-07 21:15:12 +00:00
|
|
|
ui->cbShowAs->blockSignals(true);
|
|
|
|
ui->cbShowAs->addItem(tr("ASCII"), ShowAsASCII);
|
2016-02-28 12:38:08 +00:00
|
|
|
ui->cbShowAs->addItem(tr("ASCII & Control"), ShowAsASCIIandControl);
|
2016-02-11 20:08:51 +00:00
|
|
|
ui->cbShowAs->addItem(tr("C Array"), ShowAsCArray);
|
2016-02-07 21:15:12 +00:00
|
|
|
ui->cbShowAs->addItem(tr("EBCDIC"), ShowAsEBCDIC);
|
2016-02-10 08:07:13 +00:00
|
|
|
ui->cbShowAs->addItem(tr("Hex Dump"), ShowAsHexDump);
|
2016-02-07 21:15:12 +00:00
|
|
|
ui->cbShowAs->addItem(tr("HTML"), ShowAsHTML);
|
|
|
|
ui->cbShowAs->addItem(tr("Image"), ShowAsImage);
|
|
|
|
ui->cbShowAs->addItem(tr("ISO 8859-1"), ShowAsISO8859_1);
|
|
|
|
ui->cbShowAs->addItem(tr("Raw"), ShowAsRAW);
|
|
|
|
ui->cbShowAs->addItem(tr("UTF-8"), ShowAsUTF8);
|
2016-02-11 20:08:51 +00:00
|
|
|
ui->cbShowAs->addItem(tr("YAML"), ShowAsYAML);
|
2016-02-07 21:15:12 +00:00
|
|
|
ui->cbShowAs->setCurrentIndex(show_as_);
|
|
|
|
ui->cbShowAs->blockSignals(false);
|
|
|
|
|
2016-02-14 22:01:09 +00:00
|
|
|
ui->sbStart->setMinimum(0);
|
|
|
|
ui->sbEnd->setMaximum(finfo_->length);
|
|
|
|
|
2016-02-07 21:15:12 +00:00
|
|
|
print_button_ = ui->buttonBox->addButton(tr("Print"), QDialogButtonBox::ActionRole);
|
|
|
|
connect(print_button_, SIGNAL(clicked()), this, SLOT(printBytes()));
|
|
|
|
|
|
|
|
copy_button_ = ui->buttonBox->addButton(tr("Copy"), QDialogButtonBox::ActionRole);
|
|
|
|
connect(copy_button_, SIGNAL(clicked()), this, SLOT(copyBytes()));
|
|
|
|
|
|
|
|
save_as_button_ = ui->buttonBox->addButton(tr("Save as" UTF8_HORIZONTAL_ELLIPSIS), QDialogButtonBox::ActionRole);
|
|
|
|
connect(save_as_button_, SIGNAL(clicked()), this, SLOT(saveAs()));
|
|
|
|
|
|
|
|
connect(ui->buttonBox, SIGNAL(helpRequested()), this, SLOT(helpButton()));
|
|
|
|
connect(&cap_file_, SIGNAL(captureFileClosing()), this, SLOT(captureFileClosing()));
|
|
|
|
|
2016-02-14 22:01:09 +00:00
|
|
|
setStartAndEnd(0, finfo_->length);
|
|
|
|
updateFieldBytes(true);
|
2016-02-07 21:15:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ShowPacketBytesDialog::~ShowPacketBytesDialog()
|
|
|
|
{
|
|
|
|
delete ui;
|
|
|
|
}
|
|
|
|
|
2016-02-14 22:01:09 +00:00
|
|
|
void ShowPacketBytesDialog::showSelected(int start, int end)
|
|
|
|
{
|
|
|
|
if (end == -1) {
|
|
|
|
// end set to -1 means show all packet bytes
|
|
|
|
setStartAndEnd(0, finfo_->length);
|
|
|
|
} else {
|
2016-02-28 12:38:08 +00:00
|
|
|
if (show_as_ == ShowAsRAW) {
|
|
|
|
start /= 2;
|
|
|
|
end = (end + 1) / 2;
|
|
|
|
}
|
2016-02-14 22:01:09 +00:00
|
|
|
setStartAndEnd(start_ + start, start_ + end);
|
|
|
|
}
|
|
|
|
updateFieldBytes();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShowPacketBytesDialog::setStartAndEnd(int start, int end)
|
|
|
|
{
|
|
|
|
start_ = start;
|
|
|
|
end_ = end;
|
|
|
|
|
|
|
|
ui->sbStart->blockSignals(true);
|
|
|
|
ui->sbStart->setMaximum(end_);
|
|
|
|
ui->sbStart->setValue(start_);
|
|
|
|
ui->sbStart->blockSignals(false);
|
|
|
|
|
|
|
|
ui->sbEnd->blockSignals(true);
|
|
|
|
ui->sbEnd->setMinimum(start_);
|
|
|
|
ui->sbEnd->setValue(end_);
|
|
|
|
ui->sbEnd->blockSignals(false);
|
|
|
|
|
|
|
|
updateHintLabel();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ShowPacketBytesDialog::enableShowSelected()
|
|
|
|
{
|
|
|
|
// "Show Selected" only works when showing all bytes:
|
|
|
|
// - DecodeAs must not alter the number of bytes in the buffer
|
|
|
|
// - ShowAs must show all bytes in the buffer
|
|
|
|
|
|
|
|
return (((decode_as_ == DecodeAsNone) ||
|
|
|
|
(decode_as_ == DecodeAsROT13)) &&
|
|
|
|
((show_as_ == ShowAsASCII) ||
|
2016-02-28 12:38:08 +00:00
|
|
|
(show_as_ == ShowAsASCIIandControl) ||
|
|
|
|
(show_as_ == ShowAsEBCDIC) ||
|
|
|
|
(show_as_ == ShowAsRAW)));
|
2016-02-14 22:01:09 +00:00
|
|
|
}
|
|
|
|
|
2016-02-07 21:15:12 +00:00
|
|
|
void ShowPacketBytesDialog::updateWidgets()
|
|
|
|
{
|
|
|
|
WiresharkDialog::updateWidgets();
|
|
|
|
}
|
|
|
|
|
2016-02-14 22:01:09 +00:00
|
|
|
void ShowPacketBytesDialog::updateHintLabel()
|
|
|
|
{
|
|
|
|
QString hint = hint_label_;
|
|
|
|
|
|
|
|
if (start_ > 0 || end_ < finfo_->length) {
|
|
|
|
hint.append(" <span style=\"color: red\">" +
|
|
|
|
tr("Displaying %Ln byte(s).", "", end_ - start_) +
|
|
|
|
"</span>");
|
|
|
|
}
|
|
|
|
|
|
|
|
ui->hintLabel->setText("<small><i>" + hint + "</i></small>");
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShowPacketBytesDialog::on_sbStart_valueChanged(int value)
|
|
|
|
{
|
|
|
|
start_ = value;
|
|
|
|
ui->sbEnd->setMinimum(value);
|
|
|
|
|
|
|
|
updateHintLabel();
|
|
|
|
updateFieldBytes();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShowPacketBytesDialog::on_sbEnd_valueChanged(int value)
|
|
|
|
{
|
|
|
|
end_ = value;
|
|
|
|
ui->sbStart->setMaximum(value);
|
|
|
|
|
|
|
|
updateHintLabel();
|
|
|
|
updateFieldBytes();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShowPacketBytesDialog::on_cbDecodeAs_currentIndexChanged(int idx)
|
|
|
|
{
|
|
|
|
if (idx < 0) return;
|
|
|
|
decode_as_ = static_cast<DecodeAsType>(ui->cbDecodeAs->itemData(idx).toInt());
|
|
|
|
|
|
|
|
ui->tePacketBytes->setShowSelectedEnabled(enableShowSelected());
|
|
|
|
|
|
|
|
updateFieldBytes();
|
|
|
|
}
|
|
|
|
|
2016-02-07 21:15:12 +00:00
|
|
|
void ShowPacketBytesDialog::on_cbShowAs_currentIndexChanged(int idx)
|
|
|
|
{
|
|
|
|
if (idx < 0) return;
|
|
|
|
show_as_ = static_cast<ShowAsType>(ui->cbShowAs->itemData(idx).toInt());
|
|
|
|
|
2016-02-14 22:01:09 +00:00
|
|
|
ui->tePacketBytes->setShowSelectedEnabled(enableShowSelected());
|
2016-02-07 21:15:12 +00:00
|
|
|
ui->lFind->setEnabled(true);
|
|
|
|
ui->leFind->setEnabled(true);
|
|
|
|
ui->bFind->setEnabled(true);
|
|
|
|
print_button_->setEnabled(true);
|
|
|
|
copy_button_->setEnabled(true);
|
|
|
|
save_as_button_->setEnabled(true);
|
|
|
|
|
|
|
|
updatePacketBytes();
|
|
|
|
}
|
|
|
|
|
2016-02-14 18:34:11 +00:00
|
|
|
void ShowPacketBytesDialog::useRegexFind(bool use_regex)
|
|
|
|
{
|
|
|
|
use_regex_find_ = use_regex;
|
|
|
|
if (use_regex_find_)
|
2017-12-15 13:35:44 +00:00
|
|
|
ui->lFind->setText(tr("Regex Find:"));
|
2016-02-14 18:34:11 +00:00
|
|
|
else
|
2017-12-15 13:35:44 +00:00
|
|
|
ui->lFind->setText(tr("Find:"));
|
2016-02-14 18:34:11 +00:00
|
|
|
}
|
|
|
|
|
2016-02-07 21:15:12 +00:00
|
|
|
void ShowPacketBytesDialog::findText(bool go_back)
|
|
|
|
{
|
|
|
|
if (ui->leFind->text().isEmpty()) return;
|
|
|
|
|
2016-02-14 18:34:11 +00:00
|
|
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0))
|
|
|
|
bool found;
|
|
|
|
if (use_regex_find_) {
|
|
|
|
QRegExp regex(ui->leFind->text());
|
|
|
|
found = ui->tePacketBytes->find(regex);
|
|
|
|
} else {
|
|
|
|
found = ui->tePacketBytes->find(ui->leFind->text());
|
|
|
|
}
|
|
|
|
#else
|
2016-02-07 21:15:12 +00:00
|
|
|
bool found = ui->tePacketBytes->find(ui->leFind->text());
|
2016-02-14 18:34:11 +00:00
|
|
|
#endif
|
2016-02-07 21:15:12 +00:00
|
|
|
|
|
|
|
if (found) {
|
|
|
|
ui->tePacketBytes->setFocus();
|
|
|
|
} else if (go_back) {
|
|
|
|
ui->tePacketBytes->moveCursor(QTextCursor::Start);
|
|
|
|
findText(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShowPacketBytesDialog::printBytes()
|
|
|
|
{
|
|
|
|
#ifndef QT_NO_PRINTER
|
|
|
|
QPrinter printer(QPrinter::HighResolution);
|
|
|
|
QPrintDialog dialog(&printer, this);
|
|
|
|
if (dialog.exec() == QDialog::Accepted)
|
|
|
|
ui->tePacketBytes->print(&printer);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShowPacketBytesDialog::copyBytes()
|
|
|
|
{
|
|
|
|
switch (show_as_) {
|
|
|
|
|
|
|
|
case ShowAsASCII:
|
2016-02-28 12:38:08 +00:00
|
|
|
{
|
|
|
|
QByteArray ba(field_bytes_);
|
|
|
|
sanitizeBuffer(ba, true);
|
|
|
|
wsApp->clipboard()->setText(ba);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ShowAsASCIIandControl:
|
2016-02-11 20:08:51 +00:00
|
|
|
case ShowAsCArray:
|
2016-02-07 21:15:12 +00:00
|
|
|
case ShowAsEBCDIC:
|
2016-02-10 08:07:13 +00:00
|
|
|
case ShowAsHexDump:
|
2016-02-07 21:15:12 +00:00
|
|
|
case ShowAsISO8859_1:
|
|
|
|
case ShowAsRAW:
|
2016-02-11 20:08:51 +00:00
|
|
|
case ShowAsYAML:
|
2016-02-07 21:15:12 +00:00
|
|
|
wsApp->clipboard()->setText(ui->tePacketBytes->toPlainText());
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ShowAsHTML:
|
|
|
|
wsApp->clipboard()->setText(ui->tePacketBytes->toHtml());
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ShowAsImage:
|
|
|
|
wsApp->clipboard()->setImage(image_);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ShowAsUTF8:
|
|
|
|
wsApp->clipboard()->setText(ui->tePacketBytes->toPlainText().toUtf8());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShowPacketBytesDialog::saveAs()
|
|
|
|
{
|
|
|
|
QString file_name = QFileDialog::getSaveFileName(this, wsApp->windowTitleString(tr("Save Selected Packet Bytes As" UTF8_HORIZONTAL_ELLIPSIS)));
|
|
|
|
|
|
|
|
if (file_name.isEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
QFile file(file_name);
|
|
|
|
file.open(QIODevice::WriteOnly);
|
|
|
|
|
|
|
|
switch (show_as_) {
|
|
|
|
|
|
|
|
case ShowAsASCII:
|
2016-02-28 12:38:08 +00:00
|
|
|
{
|
|
|
|
QByteArray ba(field_bytes_);
|
|
|
|
sanitizeBuffer(ba, true);
|
|
|
|
file.write(ba);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ShowAsASCIIandControl:
|
2016-02-11 20:08:51 +00:00
|
|
|
case ShowAsCArray:
|
2016-02-07 21:15:12 +00:00
|
|
|
case ShowAsEBCDIC:
|
2016-02-10 08:07:13 +00:00
|
|
|
case ShowAsHexDump:
|
2016-02-07 21:15:12 +00:00
|
|
|
case ShowAsISO8859_1:
|
2016-02-11 20:08:51 +00:00
|
|
|
case ShowAsYAML:
|
2016-02-07 21:15:12 +00:00
|
|
|
{
|
|
|
|
QTextStream out(&file);
|
|
|
|
out << ui->tePacketBytes->toPlainText();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ShowAsHTML:
|
|
|
|
{
|
|
|
|
QTextStream out(&file);
|
|
|
|
out << ui->tePacketBytes->toHtml();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ShowAsUTF8:
|
|
|
|
{
|
|
|
|
QTextStream out(&file);
|
|
|
|
out << ui->tePacketBytes->toPlainText().toUtf8();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ShowAsImage:
|
|
|
|
case ShowAsRAW:
|
|
|
|
file.write(field_bytes_);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
file.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShowPacketBytesDialog::helpButton()
|
|
|
|
{
|
|
|
|
wsApp->helpTopicAction(HELP_SHOW_PACKET_BYTES_DIALOG);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShowPacketBytesDialog::on_bFind_clicked()
|
|
|
|
{
|
|
|
|
findText();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShowPacketBytesDialog::on_leFind_returnPressed()
|
|
|
|
{
|
|
|
|
findText();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Not sure why we have to do this manually.
|
|
|
|
void ShowPacketBytesDialog::on_buttonBox_rejected()
|
|
|
|
{
|
|
|
|
WiresharkDialog::reject();
|
|
|
|
}
|
|
|
|
|
|
|
|
// The following keyboard shortcuts should work (although
|
|
|
|
// they may not work consistently depending on focus):
|
|
|
|
// / (slash), Ctrl-F - Focus and highlight the search box
|
|
|
|
// Ctrl-G, Ctrl-N, F3 - Find next
|
|
|
|
// Should we make it so that typing any text starts searching?
|
|
|
|
bool ShowPacketBytesDialog::eventFilter(QObject *, QEvent *event)
|
|
|
|
{
|
|
|
|
if (ui->tePacketBytes->hasFocus() && event->type() == QEvent::KeyPress) {
|
|
|
|
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
|
|
|
|
if (keyEvent->matches(QKeySequence::SelectAll) || keyEvent->matches(QKeySequence::Copy)
|
|
|
|
|| keyEvent->text().isEmpty()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
ui->leFind->setFocus();
|
|
|
|
if (keyEvent->matches(QKeySequence::Find)) {
|
|
|
|
return true;
|
|
|
|
} else if (keyEvent->matches(QKeySequence::FindNext)) {
|
|
|
|
findText();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShowPacketBytesDialog::keyPressEvent(QKeyEvent *event)
|
|
|
|
{
|
|
|
|
if (ui->leFind->hasFocus()) {
|
|
|
|
if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
|
|
|
|
findText();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (event->key() == Qt::Key_Slash || event->matches(QKeySequence::Find)) {
|
|
|
|
ui->leFind->setFocus();
|
|
|
|
ui->leFind->selectAll();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (event->key() == Qt::Key_F3 || (event->key() == Qt::Key_N && event->modifiers() & Qt::ControlModifier)) {
|
|
|
|
findText();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QDialog::keyPressEvent(event);
|
|
|
|
}
|
|
|
|
|
2016-02-28 12:38:08 +00:00
|
|
|
void ShowPacketBytesDialog::sanitizeBuffer(QByteArray &ba, bool keep_CR)
|
2016-02-07 21:15:12 +00:00
|
|
|
{
|
|
|
|
for (int i = 0; i < ba.length(); i++) {
|
2016-02-28 12:38:08 +00:00
|
|
|
if (ba[i] == '\n' || (keep_CR && ba[i] == '\r'))
|
|
|
|
// Keep LF and optionally CR
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (ba[i] == '\0' || g_ascii_isspace(ba[i])) {
|
|
|
|
ba[i] = ' ';
|
|
|
|
} else if (!g_ascii_isprint(ba[i])) {
|
|
|
|
ba[i] = '.';
|
2016-02-07 21:15:12 +00:00
|
|
|
}
|
|
|
|
}
|
2016-02-28 12:38:08 +00:00
|
|
|
}
|
2016-02-14 22:01:09 +00:00
|
|
|
|
2016-02-28 12:38:08 +00:00
|
|
|
void ShowPacketBytesDialog::symbolizeBuffer(QByteArray &ba)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < ba.length(); i++) {
|
|
|
|
if ((ba[i] < '\0' || ba[i] >= ' ') && ba[i] != (char)0x7f && !g_ascii_isprint(ba[i])) {
|
|
|
|
ba[i] = '.';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QByteArray symbol(UTF8_SYMBOL_FOR_NULL);
|
|
|
|
for (char i = 0; i < ' '; i++) {
|
|
|
|
ba.replace(i, symbol);
|
|
|
|
symbol[2] = symbol[2] + 1;
|
|
|
|
}
|
|
|
|
symbol[2] = symbol[2] + 1; // Skip SP
|
|
|
|
ba.replace((char)0x7f, symbol); // DEL
|
2016-02-14 22:01:09 +00:00
|
|
|
}
|
|
|
|
|
2016-05-19 10:09:33 +00:00
|
|
|
QByteArray ShowPacketBytesDialog::decodeQuotedPrintable(const guint8 *bytes, int length)
|
|
|
|
{
|
|
|
|
QByteArray ba;
|
|
|
|
|
|
|
|
for (int i = 0; i < length; i++) {
|
|
|
|
if (bytes[i] == '=' && i + 1 < length) {
|
|
|
|
if (bytes[i+1] == '\n') {
|
|
|
|
i++; // Soft line break LF
|
|
|
|
} else if (bytes[i+1] == '\r' && i + 2 < length && bytes[i+2] == '\n') {
|
|
|
|
i += 2; // Soft line break CRLF
|
|
|
|
} else if (g_ascii_isxdigit(bytes[i+1]) && i + 2 < length && g_ascii_isxdigit(bytes[i+2])) {
|
|
|
|
ba.append(QByteArray::fromHex(QByteArray((const char *)&bytes[i+1], 2)));
|
|
|
|
i += 2; // Valid Quoted-Printable sequence
|
|
|
|
} else {
|
|
|
|
// Illegal Quoted-Printable, just add byte
|
|
|
|
ba.append(bytes[i]);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ba.append(bytes[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ba;
|
|
|
|
}
|
|
|
|
|
2016-02-14 22:01:09 +00:00
|
|
|
void ShowPacketBytesDialog::rot13(QByteArray &ba)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < ba.length(); i++) {
|
|
|
|
gchar upper = g_ascii_toupper(ba[i]);
|
|
|
|
if (upper >= 'A' && upper <= 'M') ba[i] = ba[i] + 13;
|
|
|
|
else if (upper >= 'N' && upper <= 'Z') ba[i] = ba[i] - 13;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShowPacketBytesDialog::updateFieldBytes(bool initialization)
|
|
|
|
{
|
|
|
|
int start = finfo_->start + start_;
|
|
|
|
int length = end_ - start_;
|
|
|
|
const guint8 *bytes;
|
|
|
|
|
2017-05-19 12:44:14 +00:00
|
|
|
if (!finfo_->ds_tvb)
|
|
|
|
return;
|
|
|
|
|
2016-02-14 22:01:09 +00:00
|
|
|
switch (decode_as_) {
|
|
|
|
|
|
|
|
case DecodeAsNone:
|
|
|
|
bytes = tvb_get_ptr(finfo_->ds_tvb, start, -1);
|
|
|
|
field_bytes_ = QByteArray((const char *)bytes, length);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DecodeAsBASE64:
|
|
|
|
{
|
|
|
|
bytes = tvb_get_ptr(finfo_->ds_tvb, start, -1);
|
|
|
|
field_bytes_ = QByteArray((const char *)bytes, length);
|
|
|
|
size_t len = ws_base64_decode_inplace(field_bytes_.data());
|
2016-02-16 22:25:58 +00:00
|
|
|
field_bytes_.resize((int)len);
|
2016-02-14 22:01:09 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case DecodeAsCompressed:
|
|
|
|
{
|
|
|
|
tvbuff *uncompr_tvb = tvb_uncompress(finfo_->ds_tvb, start, length);
|
|
|
|
if (uncompr_tvb) {
|
|
|
|
bytes = tvb_get_ptr(uncompr_tvb, 0, -1);
|
|
|
|
field_bytes_ = QByteArray((const char *)bytes, tvb_reported_length(uncompr_tvb));
|
|
|
|
tvb_free(uncompr_tvb);
|
|
|
|
} else {
|
|
|
|
field_bytes_.clear();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-05-19 10:09:33 +00:00
|
|
|
case DecodeAsQuotedPrintable:
|
|
|
|
bytes = tvb_get_ptr(finfo_->ds_tvb, start, -1);
|
|
|
|
field_bytes_ = decodeQuotedPrintable(bytes, length);
|
|
|
|
break;
|
|
|
|
|
2016-02-14 22:01:09 +00:00
|
|
|
case DecodeAsROT13:
|
|
|
|
bytes = tvb_get_ptr(finfo_->ds_tvb, start, -1);
|
|
|
|
field_bytes_ = QByteArray((const char *)bytes, length);
|
|
|
|
rot13(field_bytes_);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-05-11 12:19:30 +00:00
|
|
|
// Try loading as image at startup
|
|
|
|
if (initialization && image_.loadFromData(field_bytes_)) {
|
|
|
|
show_as_ = ShowAsImage;
|
|
|
|
ui->cbShowAs->blockSignals(true);
|
|
|
|
ui->cbShowAs->setCurrentIndex(ShowAsImage);
|
|
|
|
ui->cbShowAs->blockSignals(false);
|
2016-02-14 22:01:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
updatePacketBytes();
|
2016-02-07 21:15:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ShowPacketBytesDialog::updatePacketBytes(void)
|
|
|
|
{
|
2016-02-11 20:08:51 +00:00
|
|
|
static const gchar hexchars[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
|
|
|
|
|
2016-02-23 08:37:20 +00:00
|
|
|
ui->tePacketBytes->clear();
|
2016-02-07 21:15:12 +00:00
|
|
|
ui->tePacketBytes->setCurrentFont(wsApp->monospaceFont());
|
|
|
|
|
|
|
|
switch (show_as_) {
|
|
|
|
|
|
|
|
case ShowAsASCII:
|
|
|
|
{
|
|
|
|
QByteArray ba(field_bytes_);
|
2016-02-28 12:38:08 +00:00
|
|
|
sanitizeBuffer(ba, false);
|
|
|
|
ui->tePacketBytes->setLineWrapMode(QTextEdit::WidgetWidth);
|
|
|
|
ui->tePacketBytes->setPlainText(ba);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ShowAsASCIIandControl:
|
|
|
|
{
|
|
|
|
QByteArray ba(field_bytes_);
|
|
|
|
symbolizeBuffer(ba);
|
2016-02-23 08:37:20 +00:00
|
|
|
ui->tePacketBytes->setLineWrapMode(QTextEdit::WidgetWidth);
|
2016-02-07 21:15:12 +00:00
|
|
|
ui->tePacketBytes->setPlainText(ba);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-02-11 20:08:51 +00:00
|
|
|
case ShowAsCArray:
|
|
|
|
{
|
|
|
|
int pos = 0, len = field_bytes_.length();
|
|
|
|
QString text("char packet_bytes[] = {\n");
|
|
|
|
|
|
|
|
while (pos < len) {
|
|
|
|
gchar hexbuf[256];
|
|
|
|
char *cur = hexbuf;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
*cur++ = ' ';
|
|
|
|
for (i = 0; i < 8 && pos + i < len; i++) {
|
|
|
|
// Prepend entries with " 0x"
|
|
|
|
*cur++ = ' ';
|
|
|
|
*cur++ = '0';
|
|
|
|
*cur++ = 'x';
|
|
|
|
*cur++ = hexchars[(field_bytes_[pos + i] & 0xf0) >> 4];
|
|
|
|
*cur++ = hexchars[field_bytes_[pos + i] & 0x0f];
|
|
|
|
|
|
|
|
// Delimit array entries with a comma
|
|
|
|
if (pos + i + 1 < len)
|
|
|
|
*cur++ = ',';
|
|
|
|
}
|
|
|
|
|
|
|
|
pos += i;
|
|
|
|
*cur++ = '\n';
|
|
|
|
*cur = 0;
|
|
|
|
|
|
|
|
text.append(hexbuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
text.append("};\n");
|
|
|
|
ui->tePacketBytes->setLineWrapMode(QTextEdit::NoWrap);
|
2016-02-23 08:37:20 +00:00
|
|
|
ui->tePacketBytes->setPlainText(text);
|
2016-02-11 20:08:51 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-02-07 21:15:12 +00:00
|
|
|
case ShowAsEBCDIC:
|
|
|
|
{
|
|
|
|
QByteArray ba(field_bytes_);
|
|
|
|
EBCDIC_to_ASCII((guint8*)ba.data(), ba.length());
|
2016-02-28 12:38:08 +00:00
|
|
|
sanitizeBuffer(ba, false);
|
2016-02-23 08:37:20 +00:00
|
|
|
ui->tePacketBytes->setLineWrapMode(QTextEdit::WidgetWidth);
|
2016-02-07 21:15:12 +00:00
|
|
|
ui->tePacketBytes->setPlainText(ba);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-02-10 08:07:13 +00:00
|
|
|
case ShowAsHexDump:
|
|
|
|
{
|
2016-02-11 20:08:51 +00:00
|
|
|
int pos = 0, len = field_bytes_.length();
|
2016-02-23 08:37:20 +00:00
|
|
|
// Use 16-bit offset if there are <= 65536 bytes, 32-bit offset if there are more
|
|
|
|
unsigned int offset_chars = (len - 1 <= 0xFFFF) ? 4 : 8;
|
2016-02-11 20:08:51 +00:00
|
|
|
QString text;
|
2016-02-14 22:01:09 +00:00
|
|
|
text.reserve((len / 16) * 80);
|
2016-02-10 08:07:13 +00:00
|
|
|
|
2016-02-11 20:08:51 +00:00
|
|
|
while (pos < len) {
|
2016-02-10 08:07:13 +00:00
|
|
|
char hexbuf[256];
|
|
|
|
char *cur = hexbuf;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
// Dump offset
|
2016-02-23 08:37:20 +00:00
|
|
|
cur += g_snprintf(cur, 20, "%0*X ", offset_chars, pos);
|
2016-02-10 08:07:13 +00:00
|
|
|
|
|
|
|
// Dump bytes as hex
|
2016-02-11 20:08:51 +00:00
|
|
|
for (i = 0; i < 16 && pos + i < len; i++) {
|
2016-02-10 08:07:13 +00:00
|
|
|
*cur++ = hexchars[(field_bytes_[pos + i] & 0xf0) >> 4];
|
|
|
|
*cur++ = hexchars[field_bytes_[pos + i] & 0x0f];
|
|
|
|
*cur++ = ' ';
|
|
|
|
if (i == 7)
|
|
|
|
*cur++ = ' ';
|
|
|
|
}
|
|
|
|
|
2016-02-23 08:37:20 +00:00
|
|
|
while (cur < hexbuf + offset_chars + 53)
|
|
|
|
*cur++ = ' '; // Fill it up with space to ascii column
|
2016-02-10 08:07:13 +00:00
|
|
|
|
|
|
|
// Dump bytes as text
|
2016-02-11 20:08:51 +00:00
|
|
|
for (i = 0; i < 16 && pos + i < len; i++) {
|
2016-02-10 08:07:13 +00:00
|
|
|
if (g_ascii_isprint(field_bytes_[pos + i]))
|
|
|
|
*cur++ = field_bytes_[pos + i];
|
|
|
|
else
|
|
|
|
*cur++ = '.';
|
|
|
|
if (i == 7)
|
|
|
|
*cur++ = ' ';
|
|
|
|
}
|
2016-02-11 20:08:51 +00:00
|
|
|
|
2016-02-10 08:07:13 +00:00
|
|
|
pos += i;
|
|
|
|
*cur++ = '\n';
|
|
|
|
*cur = 0;
|
|
|
|
|
2016-02-11 20:08:51 +00:00
|
|
|
text.append(hexbuf);
|
2016-02-10 08:07:13 +00:00
|
|
|
}
|
2016-02-11 20:08:51 +00:00
|
|
|
|
2016-02-10 08:07:13 +00:00
|
|
|
ui->tePacketBytes->setLineWrapMode(QTextEdit::NoWrap);
|
2016-02-23 08:37:20 +00:00
|
|
|
ui->tePacketBytes->setPlainText(text);
|
2016-02-10 08:07:13 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-02-07 21:15:12 +00:00
|
|
|
case ShowAsHTML:
|
2016-02-23 08:37:20 +00:00
|
|
|
ui->tePacketBytes->setLineWrapMode(QTextEdit::WidgetWidth);
|
2016-02-07 21:15:12 +00:00
|
|
|
ui->tePacketBytes->setHtml(field_bytes_);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ShowAsImage:
|
|
|
|
{
|
|
|
|
ui->lFind->setEnabled(false);
|
|
|
|
ui->leFind->setEnabled(false);
|
|
|
|
ui->bFind->setEnabled(false);
|
|
|
|
|
2016-05-11 12:19:30 +00:00
|
|
|
ui->tePacketBytes->setLineWrapMode(QTextEdit::WidgetWidth);
|
|
|
|
if (image_.loadFromData(field_bytes_)) {
|
2016-02-07 21:15:12 +00:00
|
|
|
ui->tePacketBytes->textCursor().insertImage(image_);
|
|
|
|
}
|
2016-05-11 12:19:30 +00:00
|
|
|
|
|
|
|
print_button_->setEnabled(!image_.isNull());
|
|
|
|
copy_button_->setEnabled(!image_.isNull());
|
|
|
|
save_as_button_->setEnabled(!image_.isNull());
|
2016-02-07 21:15:12 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ShowAsISO8859_1:
|
|
|
|
{
|
2016-02-28 12:38:08 +00:00
|
|
|
QString latin1 = QString::fromLatin1(field_bytes_.constData(), (int)field_bytes_.length());
|
2016-02-23 08:37:20 +00:00
|
|
|
ui->tePacketBytes->setLineWrapMode(QTextEdit::WidgetWidth);
|
2016-02-28 12:38:08 +00:00
|
|
|
ui->tePacketBytes->setPlainText(latin1);
|
2016-02-07 21:15:12 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ShowAsUTF8:
|
|
|
|
{
|
|
|
|
// The QString docs say that invalid characters will be replaced with
|
|
|
|
// replacement characters or removed. It would be nice if we could
|
|
|
|
// explicitly choose one or the other.
|
2016-02-28 12:38:08 +00:00
|
|
|
QString utf8 = QString::fromUtf8(field_bytes_.constData(), (int)field_bytes_.length());
|
2016-02-23 08:37:20 +00:00
|
|
|
ui->tePacketBytes->setLineWrapMode(QTextEdit::WidgetWidth);
|
2016-02-07 21:15:12 +00:00
|
|
|
ui->tePacketBytes->setPlainText(utf8);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-02-11 20:08:51 +00:00
|
|
|
case ShowAsYAML:
|
|
|
|
{
|
|
|
|
const int base64_raw_len = 57; // Encodes to 76 bytes, common in RFCs
|
|
|
|
int pos = 0, len = field_bytes_.length();
|
|
|
|
QString text("# Packet Bytes: !!binary |\n");
|
|
|
|
|
|
|
|
while (pos < len) {
|
|
|
|
QByteArray base64_data = field_bytes_.mid(pos, base64_raw_len);
|
|
|
|
pos += base64_data.length();
|
|
|
|
text.append(" " + base64_data.toBase64() + "\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
ui->tePacketBytes->setLineWrapMode(QTextEdit::NoWrap);
|
2016-02-23 08:37:20 +00:00
|
|
|
ui->tePacketBytes->setPlainText(text);
|
2016-02-11 20:08:51 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-02-07 21:15:12 +00:00
|
|
|
case ShowAsRAW:
|
2016-02-23 08:37:20 +00:00
|
|
|
ui->tePacketBytes->setLineWrapMode(QTextEdit::WidgetWidth);
|
2016-02-07 21:15:12 +00:00
|
|
|
ui->tePacketBytes->setPlainText(field_bytes_.toHex());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShowPacketBytesDialog::captureFileClosing()
|
|
|
|
{
|
2016-02-14 22:01:09 +00:00
|
|
|
// We have lost the source backend and must disable all functions
|
|
|
|
// for manipulating decoding and displayed range.
|
|
|
|
|
|
|
|
ui->tePacketBytes->setMenusEnabled(false);
|
|
|
|
ui->lDecodeAs->setEnabled(false);
|
|
|
|
ui->cbDecodeAs->setEnabled(false);
|
|
|
|
ui->lStart->setEnabled(false);
|
|
|
|
ui->sbStart->setEnabled(false);
|
|
|
|
ui->lEnd->setEnabled(false);
|
|
|
|
ui->sbEnd->setEnabled(false);
|
|
|
|
|
|
|
|
finfo_ = NULL; // This will invalidate the source backend
|
|
|
|
|
2016-02-07 21:15:12 +00:00
|
|
|
WiresharkDialog::captureFileClosing();
|
|
|
|
}
|
|
|
|
|
2016-02-14 22:01:09 +00:00
|
|
|
void ShowPacketBytesTextEdit::contextMenuEvent(QContextMenuEvent *event)
|
|
|
|
{
|
|
|
|
QMenu *menu = createStandardContextMenu();
|
|
|
|
QAction *action;
|
|
|
|
|
|
|
|
menu->addSeparator();
|
|
|
|
|
|
|
|
action = menu->addAction(tr("Show Selected"));
|
|
|
|
action->setEnabled(menus_enabled_ && show_selected_enabled_ && textCursor().hasSelection());
|
|
|
|
connect(action, SIGNAL(triggered()), this, SLOT(showSelected()));
|
|
|
|
|
|
|
|
action = menu->addAction(tr("Show All"));
|
|
|
|
action->setEnabled(menus_enabled_);
|
|
|
|
connect(action, SIGNAL(triggered()), this, SLOT(showAll()));
|
|
|
|
|
|
|
|
menu->exec(event->globalPos());
|
|
|
|
delete menu;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShowPacketBytesTextEdit::showSelected()
|
|
|
|
{
|
|
|
|
QTextCursor cursor = textCursor();
|
|
|
|
int start = cursor.selectionStart();
|
|
|
|
int end = cursor.selectionEnd();
|
|
|
|
|
|
|
|
emit showSelected(start, end);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShowPacketBytesTextEdit::showAll()
|
|
|
|
{
|
|
|
|
emit showSelected(0, -1);
|
|
|
|
}
|
|
|
|
|
2016-02-07 21:15:12 +00:00
|
|
|
/*
|
|
|
|
* Editor modelines
|
|
|
|
*
|
|
|
|
* Local Variables:
|
|
|
|
* c-basic-offset: 4
|
|
|
|
* tab-width: 8
|
|
|
|
* indent-tabs-mode: nil
|
|
|
|
* End:
|
|
|
|
*
|
|
|
|
* ex: set shiftwidth=4 tabstop=8 expandtab:
|
|
|
|
* :indentSize=4:tabSize=8:noTabs=true:
|
|
|
|
*/
|