Kerberos: add kerberos_inject_longterm_key() helper function
[wireshark-sm.git] / ui / qt / byte_view_tab.cpp
blob6cb8add70414cd351ecad82a2e7cb98af384bdf9
1 /* byte_view_tab.cpp
3 * Wireshark - Network traffic analyzer
4 * By Gerald Combs <gerald@wireshark.org>
5 * Copyright 1998 Gerald Combs
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
10 #include "byte_view_tab.h"
12 #include <QApplication>
13 #include <QClipboard>
14 #include <QMimeData>
15 #include <QTabBar>
17 #include "cfile.h"
18 #include "epan/epan_dissect.h"
19 #include "epan/tvbuff-int.h"
21 #include <main_application.h>
23 #include <ui/qt/utils/variant_pointer.h>
24 #include <ui/qt/widgets/byte_view_text.h>
26 #define tvb_data_property "tvb_data_property"
28 // To do:
29 // - We might want to add a callback to free_data_sources in so that we
30 // don't have to blindly call clear().
32 ByteViewTab::ByteViewTab(QWidget *parent, epan_dissect_t *edt_fixed) :
33 QTabWidget(parent),
34 cap_file_(0),
35 is_fixed_packet_(edt_fixed != NULL),
36 edt_(edt_fixed),
37 disable_hover_(false)
39 setAccessibleName(tr("Packet bytes"));
40 setTabPosition(QTabWidget::South);
41 setDocumentMode(true);
43 // Shrink down to a small but nonzero size in the main splitter.
44 int one_em = fontMetrics().height();
45 setMinimumSize(one_em, one_em);
47 if (!edt_fixed) {
48 connect(mainApp, SIGNAL(appInitialized()), this, SLOT(connectToMainWindow()));
52 // Connects the byte view with the main window, acting on changes to the packet
53 // list selection. It MUST NOT be used with the packet dialog as that is
54 // independent of the selection in the packet list.
55 void ByteViewTab::connectToMainWindow()
57 connect(this, SIGNAL(fieldSelected(FieldInformation *)),
58 mainApp->mainWindow(), SIGNAL(fieldSelected(FieldInformation *)));
59 connect(this, SIGNAL(fieldHighlight(FieldInformation *)),
60 mainApp->mainWindow(), SIGNAL(fieldHighlight(FieldInformation *)));
62 /* Connect change of packet selection */
63 connect(mainApp->mainWindow(), SIGNAL(framesSelected(QList<int>)), this, SLOT(selectedFrameChanged(QList<int>)));
64 connect(mainApp->mainWindow(), SIGNAL(setCaptureFile(capture_file*)), this, SLOT(setCaptureFile(capture_file*)));
65 connect(mainApp->mainWindow(), SIGNAL(fieldSelected(FieldInformation *)), this, SLOT(selectedFieldChanged(FieldInformation *)));
67 connect(mainApp->mainWindow(), SIGNAL(captureActive(int)), this, SLOT(captureActive(int)));
70 void ByteViewTab::captureActive(int cap)
72 if (cap == 0)
74 QList<ByteViewText *> allBVTs = findChildren<ByteViewText *>();
75 if (allBVTs.count() > 0)
77 ByteViewText * bvt = allBVTs.at(0);
78 tvbuff_t * stored = VariantPointer<tvbuff_t>::asPtr(bvt->property(tvb_data_property));
80 if (! stored)
81 selectedFrameChanged(QList<int>());
86 void ByteViewTab::addTab(const char *name, tvbuff_t *tvb) {
87 if (count() == 1) { // Remove empty placeholder.
88 ByteViewText *cur_text = qobject_cast<ByteViewText *>(currentWidget());
89 if (cur_text && cur_text->isEmpty()) delete currentWidget();
92 packet_char_enc encoding = PACKET_CHAR_ENC_CHAR_ASCII;
93 if (cap_file_ && cap_file_->current_frame)
94 encoding = (packet_char_enc)cap_file_->current_frame->encoding;
96 QByteArray data;
97 if (tvb) {
98 int data_len = (int) tvb_captured_length(tvb);
99 if (data_len > 0) {
100 // Note: this does not copy the data and will be invalidated
101 // when the tvbuff's real data becomes invalid (which is not
102 // necessarily when the tvb itself becomes invalid.)
103 data = QByteArray::fromRawData((const char *) tvb_get_ptr(tvb, 0, data_len), data_len);
107 ByteViewText * byte_view_text = new ByteViewText(data, encoding, this);
108 byte_view_text->setAccessibleName(name);
109 byte_view_text->setMonospaceFont(mainApp->monospaceFont(true));
111 if (tvb)
113 // There are some secondary data source tvbuffs whose datais not freed
114 // when the epan_dissect_t is freed, but at some other point expected
115 // to outlive the packet, generally when the capture file is closed.
116 // If this is a PacketDialog, it can break that assumption.
117 // To get around this, we deep copy their data when the file is closed.
119 // XXX: We could add a function to the tvbuff API and only do this if
120 // there is no free_cb (a free_cb implies the data is freed at the
121 // same time as the tvb, i.e. when leaving the packet.)
122 if (is_fixed_packet_ && count() > 0) {
123 connect(this, &ByteViewTab::detachData, byte_view_text, &ByteViewText::detachData);
125 // See above - this tvb is (expected to be) scoped to the packet, but
126 // the real data is not necessarily so. If this is a PacketDialog
127 // and such a secondary data source, then we MUST NOT use any tvb
128 // function that accesses the real data after the capture file closes.
129 // That includes via the ds_tvb item of a field_info in the tree.
130 // proto_find_field_from_offset() is OK. See #14363.
132 // XXX: It sounds appealing to clone the secondary data source tvbs
133 // and set them to be freed when the byte_view_text is freed, perhaps
134 // even doing so only when the capture file is closing. However, while
135 // relatively simple for the few number of secondary data sources, it
136 // would be a pain to change the pointers for every field_info.
137 byte_view_text->setProperty(tvb_data_property, VariantPointer<tvbuff_t>::asQVariant(tvb));
139 connect(mainApp, SIGNAL(zoomMonospaceFont(QFont)), byte_view_text, SLOT(setMonospaceFont(QFont)));
141 connect(byte_view_text, SIGNAL(byteHovered(int)), this, SLOT(byteViewTextHovered(int)));
142 connect(byte_view_text, SIGNAL(byteSelected(int)), this, SLOT(byteViewTextMarked(int)));
143 connect(byte_view_text, SIGNAL(byteViewSettingsChanged()), this, SIGNAL(byteViewSettingsChanged()));
144 connect(this, SIGNAL(byteViewSettingsChanged()), byte_view_text, SLOT(updateByteViewSettings()));
145 connect(this, SIGNAL(byteViewUnmarkField()), byte_view_text, SLOT(unmarkField()));
148 int idx = QTabWidget::addTab(byte_view_text, name);
149 byte_view_text->setProperty("tab_index", QVariant::fromValue(idx));
151 QTabWidget::setTabToolTip(idx, name);
154 void ByteViewTab::byteViewTextHovered(int idx)
156 if (idx >= 0 && edt_)
158 tvbuff_t * tvb = VariantPointer<tvbuff_t>::asPtr(sender()->property(tvb_data_property));
159 proto_tree * tree = edt_->tree;
161 if (tvb && tree)
163 field_info * fi = proto_find_field_from_offset(tree, idx, tvb);
164 if (fi)
166 FieldInformation finfo(fi, this);
167 highlightedFieldChanged(&finfo);
168 emit fieldHighlight(&finfo);
169 return;
174 emit fieldHighlight((FieldInformation *)0);
177 void ByteViewTab::byteViewTextMarked(int idx)
179 if (idx >= 0 && edt_)
181 tvbuff_t * tvb = VariantPointer<tvbuff_t>::asPtr(sender()->property(tvb_data_property));
182 proto_tree * tree = edt_->tree;
184 if (tvb && tree)
186 field_info * fi = proto_find_field_from_offset(tree, idx, tvb);
187 if (fi)
189 FieldInformation finfo(fi, this);
190 emit fieldSelected(&finfo);
191 return;
196 emit fieldSelected((FieldInformation *)0);
199 ByteViewText * ByteViewTab::findByteViewTextForTvb(tvbuff_t * search_tvb, int * idx)
202 ByteViewText * item = 0;
203 if (! search_tvb)
204 return item;
206 bool found = false;
208 QList<ByteViewText *> allBVTs = findChildren<ByteViewText *>();
209 for (int i = 0; i < allBVTs.size() && ! found; ++i)
211 ByteViewText * bvt = allBVTs.at(i);
212 tvbuff_t * stored = VariantPointer<tvbuff_t>::asPtr(bvt->property(tvb_data_property));
213 if (stored == search_tvb)
215 found = true;
216 int wdgIdx = bvt->property("tab_index").toInt();
217 if (idx)
219 *idx = wdgIdx;
221 item = (ByteViewText *)widget(wdgIdx);
225 return item;
228 void ByteViewTab::tabInserted(int tab_index) {
229 setTabsVisible();
230 QTabWidget::tabInserted(tab_index);
233 void ByteViewTab::tabRemoved(int tab_index) {
234 setTabsVisible();
235 QTabWidget::tabRemoved(tab_index);
238 void ByteViewTab::setTabsVisible() {
239 if (count() > 1)
240 tabBar()->show();
241 else
242 tabBar()->hide();
245 void ByteViewTab::selectedFrameChanged(QList<int> frames)
247 clear();
248 qDeleteAll(findChildren<ByteViewText *>());
250 if (!is_fixed_packet_) {
251 /* If this is not a fixed packet (not the packet dialog), it must be the
252 * byte view associated with the packet list. */
253 if (cap_file_ && cap_file_->edt) {
254 /* Assumes that this function is called as a result of selecting a
255 * packet in the packet list (PacketList::selectionChanged). That
256 * invokes "cf_select_packet" which will update "cap_file_->edt". */
257 edt_ = cap_file_->edt;
258 } else {
259 /* capture file is closing or packet is deselected. */
260 edt_ = NULL;
264 /* only show the bytes for single selections */
265 if (frames.count() == 1)
267 if (! cap_file_ || ! cap_file_->edt)
268 return;
270 /* This code relies on a dissection, which had happened somewhere else. It also does not
271 * really check, if the dissection happened for the correct frame. In the future we might
272 * rewrite this for directly calling the dissection engine here. */
273 GSList *src_le;
274 for (src_le = edt_->pi.data_src; src_le != NULL; src_le = src_le->next) {
275 struct data_source *source;
276 char* source_name;
277 source = (struct data_source *)src_le->data;
278 source_name = get_data_source_name(source);
279 addTab(source_name, get_data_source_tvb(source));
280 wmem_free(NULL, source_name);
283 else
284 addTab("PlaceHolder", 0);
286 setCurrentIndex(0);
289 void ByteViewTab::selectedFieldChanged(FieldInformation *selected)
291 // We need to handle both selection and deselection.
292 ByteViewText * byte_view_text = qobject_cast<ByteViewText *>(currentWidget());
293 int f_start = -1, f_length = -1;
294 int p_start = -1, p_length = -1;
295 int fa_start = -1, fa_length = -1;
297 if (selected) {
298 if (selected->parent() == this) {
299 // We only want inbound signals.
300 return;
302 const field_info *fi = selected->fieldInfo();
304 int idx = 0;
305 if (fi)
306 byte_view_text = findByteViewTextForTvb(fi->ds_tvb, &idx);
308 if (cap_file_->search_in_progress && (cap_file_->hex || (cap_file_->string && cap_file_->packet_data))) {
309 // In the hex view, only highlight the target bytes or string. The entire
310 // field can then be displayed by clicking on any of the bytes in the field.
311 f_start = (int)cap_file_->search_pos;
312 f_length = (int) cap_file_->search_len;
313 } else {
314 f_start = selected->position().start;
315 f_length = selected->position().length;
318 setCurrentIndex(idx);
320 FieldInformation *parentField = selected->parentField();
322 p_start = parentField->position().start;
323 p_length = parentField->position().length;
324 fa_start = selected->appendix().start;
325 fa_length = selected->appendix().length;
327 delete parentField;
330 if (byte_view_text)
332 byte_view_text->markField(f_start, f_length);
333 byte_view_text->markProtocol(p_start, p_length);
334 byte_view_text->markAppendix(fa_start, fa_length);
335 } else {
336 emit byteViewUnmarkField();
339 void ByteViewTab::highlightedFieldChanged(FieldInformation *highlighted)
341 ByteViewText * byte_view_text = qobject_cast<ByteViewText *>(currentWidget());
342 if (!highlighted || !byte_view_text) {
343 return;
346 int f_start = -1, f_length = -1;
348 if (cap_file_->search_in_progress && (cap_file_->hex || (cap_file_->string && cap_file_->packet_data))) {
349 // In the hex view, only highlight the target bytes or string. The entire
350 // field can then be displayed by clicking on any of the bytes in the field.
351 f_start = cap_file_->search_pos - cap_file_->search_len + 1;
352 f_length = (int) cap_file_->search_len;
353 } else {
354 f_start = highlighted->position().start;
355 f_length = highlighted->position().length;
358 byte_view_text->markField(f_start, f_length, false);
359 byte_view_text->markProtocol(-1, -1);
360 byte_view_text->markAppendix(-1, -1);
363 void ByteViewTab::setCaptureFile(capture_file *cf)
365 selectedFrameChanged(QList<int>());
367 cap_file_ = cf;
370 void ByteViewTab::captureFileClosing()
372 emit detachData();