266 lines
8.2 KiB
C++
266 lines
8.2 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+
|
|
*/
|
|
|
|
#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.isLetter()) {
|
|
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 showText)
|
|
{
|
|
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 ( showText )
|
|
{
|
|
QChar ch(printData[cnt]);
|
|
if (!ch.isPrint())
|
|
ch = '.';
|
|
dataStr += ch;
|
|
}
|
|
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 ( showText )
|
|
{
|
|
/* 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"), dpi);
|
|
action->setToolTip(tr("Copy packet bytes as a hex and ASCII dump."));
|
|
action->setProperty("printertype", DataPrinter::DP_HexDump);
|
|
connect(action, SIGNAL(triggered(bool)), dpi, SLOT(copyIDataBytes(bool)));
|
|
actions->addAction(action);
|
|
|
|
action = new QAction(tr(UTF8_HORIZONTAL_ELLIPSIS "as Hex Dump"), dpi);
|
|
action->setToolTip(tr("Copy packet bytes as a hex dump."));
|
|
action->setProperty("printertype", DataPrinter::DP_HexOnly);
|
|
connect(action, SIGNAL(triggered(bool)), dpi, SLOT(copyIDataBytes(bool)));
|
|
actions->addAction(action);
|
|
|
|
action = new QAction(tr(UTF8_HORIZONTAL_ELLIPSIS "as Printable Text"), dpi);
|
|
action->setToolTip(tr("Copy only the printable text in the packet."));
|
|
action->setProperty("printertype", DataPrinter::DP_PrintableText);
|
|
connect(action, SIGNAL(triggered(bool)), dpi, SLOT(copyIDataBytes(bool)));
|
|
actions->addAction(action);
|
|
|
|
action = new QAction(tr(UTF8_HORIZONTAL_ELLIPSIS "as a Hex Stream"), dpi);
|
|
action->setToolTip(tr("Copy packet bytes as a stream of hex."));
|
|
action->setProperty("printertype", DataPrinter::DP_HexStream);
|
|
connect(action, SIGNAL(triggered(bool)), dpi, SLOT(copyIDataBytes(bool)));
|
|
actions->addAction(action);
|
|
|
|
action = new QAction(tr(UTF8_HORIZONTAL_ELLIPSIS "as Raw Binary"), dpi);
|
|
action->setToolTip(tr("Copy packet bytes as application/octet-stream MIME data."));
|
|
action->setProperty("printertype", DataPrinter::DP_Binary);
|
|
connect(action, SIGNAL(triggered(bool)), dpi, SLOT(copyIDataBytes(bool)));
|
|
actions->addAction(action);
|
|
|
|
action = new QAction(tr(UTF8_HORIZONTAL_ELLIPSIS "as Escaped String"), dpi);
|
|
action->setToolTip(tr("Copy packet bytes as an escaped string."));
|
|
action->setProperty("printertype", DataPrinter::DP_EscapedString);
|
|
connect(action, SIGNAL(triggered(bool)), dpi, SLOT(copyIDataBytes(bool)));
|
|
actions->addAction(action);
|
|
|
|
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));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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:
|
|
*/
|