wireshark/ui/qt/utils/data_printer.cpp

248 lines
7.8 KiB
C++

/* data_printer.cpp
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <ui/qt/utils/data_printer.h>
#include <ui/qt/utils/variant_pointer.h>
#include <ui/recent.h>
#include <wsutil/utf8_entities.h>
#include <stdint.h>
#include <QApplication>
#include <QClipboard>
#include <QString>
#include <QMimeData>
DataPrinter::DataPrinter(QObject * parent)
: QObject(parent),
byteLineLength_(16)
{}
void DataPrinter::toClipboard(DataPrinter::DumpType type, IDataPrintable * printable)
{
const QByteArray printData = printable->printableData();
QString clipboard_text;
switch(type)
{
case DP_PrintableText:
for (int i = 0; i < printData.length(); i++) {
QChar ch(printData[i]);
if (ch.isSpace() || ch.isPrint()) {
clipboard_text += ch;
}
}
break;
case DP_HexStream:
for (int i = 0; i < printData.length(); i++)
clipboard_text += QString("%1").arg((uint8_t) printData[i], 2, 16, QChar('0'));
break;
case DP_EscapedString:
// Beginning quote
clipboard_text += QString("\"");
for (int i = 0; i < printData.length(); 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 != printData.length() - 1) {
clipboard_text += QString("\" \\\n\"");
}
clipboard_text += QString("\\x%1").arg((uint8_t) printData[i], 2, 16, QChar('0'));
}
// End quote
clipboard_text += QString("\"\n");
break;
case DP_Binary:
binaryDump(printData);
break;
case DP_HexDump:
clipboard_text = hexTextDump(printData, true);
break;
case DP_HexOnly:
clipboard_text = hexTextDump(printData, false);
break;
default:
break;
}
if (!clipboard_text.isEmpty()) {
qApp->clipboard()->setText(clipboard_text);
}
}
void DataPrinter::binaryDump(const QByteArray printData)
{
if (!printData.isEmpty()) {
QMimeData *mime_data = new QMimeData;
// gtk/gui_utils.c:copy_binary_to_clipboard says:
/* XXX - this is not understood by most applications,
* but can be pasted into the better hex editors - is
* there something better that we can do?
*/
// 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", printData);
qApp->clipboard()->setMimeData(mime_data);
}
}
void DataPrinter::setByteLineLength(int bll)
{
byteLineLength_ = bll;
}
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(const QByteArray printData, bool showASCII)
{
QString clipboard_text;
QString byteStr;
QString dataStr;
int cnt = 0;
while (cnt < printData.length())
{
byteStr += QString(" %1").arg((uint8_t) printData[cnt], 2, 16, QChar('0'));
if (showASCII)
{
QChar ch(printData[cnt]);
if (g_ascii_isprint(printData[cnt]))
dataStr += printData[cnt];
else
dataStr += '.';
}
cnt++;
}
int lines = printData.length() / byteLineLength_;
if (printData.length() % byteLineLength_ > 0)
lines++;
for (cnt = 0; cnt < lines; cnt++)
{
int offset = cnt * 0x10;
clipboard_text += QString("%1 ").arg(offset, 4, 16, QChar('0'));
clipboard_text += byteStr.mid(offset * 3, byteLineLength_ * 3);
if (showASCII)
{
/* separation bytes for byte and text */
clipboard_text += QString(3, ' ');
/* separation bytes last line */
if (cnt == (lines - 1) )
{
int remSpace = byteLineLength_ - dataStr.mid(offset, byteLineLength_).length();
clipboard_text += QString(remSpace * 3, ' ');
}
/* text representation */
clipboard_text += dataStr.mid(offset, byteLineLength_);
}
clipboard_text += "\n";
}
return clipboard_text;
}
DataPrinter * DataPrinter::instance()
{
static DataPrinter * inst = Q_NULLPTR;
if (inst == Q_NULLPTR)
inst = new DataPrinter();
return inst;
}
QActionGroup * DataPrinter::copyActions(QObject * copyClass, QObject * data)
{
QActionGroup * actions = new QActionGroup(copyClass);
if (! data && ! dynamic_cast<IDataPrintable *>(copyClass))
return actions;
DataPrinter * dpi = DataPrinter::instance();
if (data)
actions->setProperty("idataprintable", VariantPointer<QObject>::asQVariant(data));
else
actions->setProperty("idataprintable", VariantPointer<QObject>::asQVariant(copyClass));
// Mostly duplicated from main_window.ui
QAction * action = new QAction(tr("Copy Bytes as Hex + ASCII Dump"), actions);
action->setToolTip(tr("Copy packet bytes as a hex and ASCII dump."));
action->setProperty("printertype", DataPrinter::DP_HexDump);
connect(action, &QAction::triggered, dpi, &DataPrinter::copyIDataBytes);
action = new QAction(tr("…as Hex Dump"), actions);
action->setToolTip(tr("Copy packet bytes as a hex dump."));
action->setProperty("printertype", DataPrinter::DP_HexOnly);
connect(action, &QAction::triggered, dpi, &DataPrinter::copyIDataBytes);
action = new QAction(tr("…as Printable Text"), actions);
action->setToolTip(tr("Copy only the printable text in the packet."));
action->setProperty("printertype", DataPrinter::DP_PrintableText);
connect(action, &QAction::triggered, dpi, &DataPrinter::copyIDataBytes);
action = new QAction(tr("…as a Hex Stream"), actions);
action->setToolTip(tr("Copy packet bytes as a stream of hex."));
action->setProperty("printertype", DataPrinter::DP_HexStream);
connect(action, &QAction::triggered, dpi, &DataPrinter::copyIDataBytes);
action = new QAction(tr("…as Raw Binary"), actions);
action->setToolTip(tr("Copy packet bytes as application/octet-stream MIME data."));
action->setProperty("printertype", DataPrinter::DP_Binary);
connect(action, &QAction::triggered, dpi, &DataPrinter::copyIDataBytes);
action = new QAction(tr("…as Escaped String"), actions);
action->setToolTip(tr("Copy packet bytes as an escaped string."));
action->setProperty("printertype", DataPrinter::DP_EscapedString);
connect(action, &QAction::triggered, dpi, &DataPrinter::copyIDataBytes);
return actions;
}
void DataPrinter::copyIDataBytes(bool /* state */)
{
if (! dynamic_cast<QAction*>(sender()))
return;
QAction * sendingAction = dynamic_cast<QAction *>(sender());
if (! sendingAction->actionGroup() || ! sendingAction->actionGroup()->property("idataprintable").isValid())
return;
QObject * dataObject = VariantPointer<QObject>::asPtr(sendingAction->actionGroup()->property("idataprintable"));
if (! dataObject || ! dynamic_cast<IDataPrintable *>(dataObject))
return;
int dump_type = sendingAction->property("printertype").toInt();
if (dump_type >= 0 && dump_type <= DataPrinter::DP_Binary) {
DataPrinter printer;
printer.toClipboard((DataPrinter::DumpType) dump_type, dynamic_cast<IDataPrintable *>(dataObject));
}
}