/* byte_view_tab.cpp * * Wireshark - Network traffic analyzer * By Gerald Combs * 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 "byte_view_tab.h" #include "byte_view_text.h" #include #include #include #include #include #include // To do: // - We might want to add a callback to free_data_sources in so that we // don't have to blindly call clear(). ByteViewTab::ByteViewTab(QWidget *parent) : QTabWidget(parent) { setAccessibleName(tr("Packet bytes")); setTabPosition(QTabWidget::South); setDocumentMode(true); addTab(); } void ByteViewTab::addTab(const char *name, tvbuff_t *tvb, proto_tree *tree, QTreeWidget *protoTree, packet_char_enc encoding) { if (count() == 1) { // Remove empty placeholder. ByteViewText *cur_text = qobject_cast(currentWidget()); if (cur_text && cur_text->isEmpty()) delete currentWidget(); } ByteViewText *byte_view_text = new ByteViewText(this, tvb, tree, protoTree, encoding); byte_view_text->setAccessibleName(name); byte_view_text->setMonospaceFont(mono_font_); connect(this, SIGNAL(monospaceFontChanged(QFont)), byte_view_text, SLOT(setMonospaceFont(QFont))); connect(byte_view_text, SIGNAL(byteFieldHovered(const QString&)), this, SIGNAL(byteFieldHovered(const QString&))); int idx = QTabWidget::addTab(byte_view_text, name); QTabWidget::setTabToolTip(idx, name); } void ByteViewTab::clear() { bool visible = isVisible(); if (visible) { hide(); } while (currentWidget()) { delete currentWidget(); } addTab(); if (visible) { show(); } } // XXX How many hex dump routines do we have? const int byte_line_length_ = 16; // Print out data for 16 bytes on one line void ByteViewTab::copyHexTextDump(const guint8 *data_p, int data_len, bool append_text) { QString clipboard_text; /* Write hex data for a line, then ascii data, then concatenate and add to buffer */ QString hex_str, char_str; int i; bool end_of_line = true; /* Initial state is end of line */ int byte_line_part_length; i = 0; while (i < data_len) { if(end_of_line) { hex_str += QString("%1 ").arg(i, 4, 16, QChar('0')); /* Offset - note that we _append_ here */ } hex_str += QString(" %1").arg(*data_p, 2, 16, QChar('0')); if(append_text) { char_str += QString("%1").arg(g_ascii_isprint(*data_p) ? QChar(*data_p) : '.'); } ++data_p; /* Look ahead to see if this is the end of the data */ byte_line_part_length = (++i) % byte_line_length_; if(i >= data_len){ /* End of data - need to fill in spaces in hex string and then do "end of line". * */ if (append_text) { int fill_len = byte_line_part_length == 0 ? 0 : byte_line_length_ - byte_line_part_length; /* Add three spaces for each missing byte */ hex_str += QString(fill_len * 3, ' '); } end_of_line = true; } else { end_of_line = (byte_line_part_length == 0); } if (end_of_line){ /* End of line */ clipboard_text += hex_str; if(append_text) { /* Two spaces between hex and text */ clipboard_text += " "; clipboard_text += char_str; } /* Setup ready for next line */ hex_str = "\n"; char_str.clear(); } } if (!clipboard_text.isEmpty()) { qApp->clipboard()->setText(clipboard_text); } } void ByteViewTab::copyPrintableText(const guint8 *data_p, int data_len) { QString clipboard_text; for (int i = 0; i < data_len; i++) { const guint8 c = data_p[i]; if (g_ascii_isprint(c) || g_ascii_isspace(c)) { clipboard_text += QChar(c); } } if (!clipboard_text.isEmpty()) { qApp->clipboard()->setText(clipboard_text); } } void ByteViewTab::copyHexStream(const guint8 *data_p, int data_len) { QString clipboard_text; for (int i = 0; i < data_len; i++) { clipboard_text += QString("%1").arg(data_p[i], 2, 16, QChar('0')); } if (!clipboard_text.isEmpty()) { qApp->clipboard()->setText(clipboard_text); } } void ByteViewTab::copyBinary(const guint8 *data_p, int data_len) { QByteArray clipboard_bytes = QByteArray::fromRawData((const char *) data_p, data_len); if (!clipboard_bytes.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", clipboard_bytes); qApp->clipboard()->setMimeData(mime_data); } } void ByteViewTab::copyEscapedString(const guint8 *data_p, int data_len) { QString clipboard_text; // Beginning quote clipboard_text += QString("\""); for (int i = 0; i < data_len; 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 != data_len - 1) { clipboard_text += QString("\" \\\n\""); } clipboard_text += QString("\\x%1").arg(data_p[i], 2, 16, QChar('0')); } // End quote clipboard_text += QString("\"\n"); if (!clipboard_text.isEmpty()) { qApp->clipboard()->setText(clipboard_text); } } void ByteViewTab::copyData(ByteViewTab::copyDataType copy_type, field_info *fi) { int i = 0; ByteViewText *byte_view_text = qobject_cast(widget(i)); if (fi) { while (byte_view_text) { if (byte_view_text->hasDataSource(fi->ds_tvb)) break; byte_view_text = qobject_cast(widget(++i)); } } if (!byte_view_text) return; guint data_len = 0; const guint8 *data_p; data_p = byte_view_text->dataAndLength(&data_len); if (!data_p) return; if (fi && fi->start >= 0 && fi->length > 0 && fi->length <= (int) data_len) { data_len = fi->length; data_p += fi->start; } if (!data_len) return; switch (copy_type) { case copyDataHexTextDump: copyHexTextDump(data_p, data_len, true); break; case copyDataHexDump: copyHexTextDump(data_p, data_len, false); break; case copyDataPrintableText: copyPrintableText(data_p, data_len); break; case copyDataHexStream: copyHexStream(data_p, data_len); break; case copyDataBinary: copyBinary(data_p, data_len); break; case copyDataEscapedString: copyEscapedString(data_p, data_len); break; default: break; } } void ByteViewTab::tabInserted(int index) { setTabsVisible(); QTabWidget::tabInserted(index); } void ByteViewTab::tabRemoved(int index) { setTabsVisible(); QTabWidget::tabRemoved(index); } void ByteViewTab::setTabsVisible() { if (count() > 1) tabBar()->show(); else tabBar()->hide(); } void ByteViewTab::protoTreeItemChanged(QTreeWidgetItem *current) { if (current && cap_file_) { field_info *fi; fi = VariantPointer::asPtr(current->data(0, Qt::UserRole)); int i = 0; ByteViewText *byte_view_text = qobject_cast(widget(i)); while (byte_view_text) { if (byte_view_text->hasDataSource(fi->ds_tvb)) { QTreeWidgetItem *parent = current->parent(); field_info *parent_fi = NULL; int f_start = -1, f_end = -1, f_len = -1; int fa_start = -1, fa_end = -1, fa_len = -1; int p_start = -1, p_end = -1, p_len = -1; guint len = tvb_captured_length(fi->ds_tvb); // Find and highlight the protocol bytes while (parent && parent->parent()) { parent = parent->parent(); } if (parent) { parent_fi = VariantPointer::asPtr(parent->data(0, Qt::UserRole)); } if (parent_fi && parent_fi->ds_tvb == fi->ds_tvb) { p_start = parent_fi->start; p_len = parent_fi->length; } 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_len = cap_file_->search_len; } else { f_start = fi->start; f_len = fi->length; } /* bmask = finfo->hfinfo->bitmask << hfinfo_bitshift(finfo->hfinfo); */ /* (value & mask) >> shift */ fa_start = fi->appendix_start; fa_len = fi->appendix_length; if (p_start >= 0 && p_len > 0 && (guint)p_start < len) { p_end = p_start + p_len; } if (f_start >= 0 && f_len > 0 && (guint)f_start < len) { f_end = f_start + f_len; } if (fa_start >= 0 && fa_len > 0 && (guint)fa_start < len) { fa_end = fa_start + fa_len; } if (f_end == -1 && fa_end != -1) { f_start = fa_start; f_end = fa_end; fa_start = fa_end = -1; } /* don't exceed the end of available data */ if (p_end != -1 && (guint)p_end > len) p_end = len; if (f_end != -1 && (guint)f_end > len) f_end = len; if (fa_end != -1 && (guint)fa_end > len) fa_end = len; // Protocol byte_view_text->setProtocolHighlight(p_start, p_end); // Field bytes byte_view_text->setFieldHighlight(f_start, f_end); // Appendix (trailer) bytes byte_view_text->setFieldAppendixHighlight(fa_start, fa_end); setCurrentIndex(i); } byte_view_text = qobject_cast(widget(++i)); } } } void ByteViewTab::setCaptureFile(capture_file *cf) { cap_file_ = cf; } void ByteViewTab::setMonospaceFont(const QFont &mono_font) { mono_font_ = mono_font; emit monospaceFontChanged(mono_font_); update(); } /* * 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: */