forked from osmocom/wireshark
8ed7a73e22
Cast away some implicit 64-bit-to-32-bit conversion errors due to use of sizeof. Cast away some implicit 64-bit-to-32-bit conversion errors due to use of strtol() and strtoul(). Change some data types to avoid those implicit conversion warnings. When assigning a constant to a float, make sure the constant isn't a double, by appending "f" to the constant. Constify a bunch of variables, parameters, and return values to eliminate warnings due to strings being given const qualifiers. Cast away those warnings in some cases where an API we don't control forces us to do so. Enable a bunch of additional warnings by default. Note why at least some of the other warnings aren't enabled. randpkt.c and text2pcap.c are used to build programs, so they don't need to be in EXTRA_DIST. If the user specifies --enable-warnings-as-errors, add -Werror *even if the user specified --enable-extra-gcc-flags; assume they know what they're doing and are willing to have the compile fail due to the extra GCC warnings being treated as errors. svn path=/trunk/; revision=46748
1301 lines
37 KiB
C
1301 lines
37 KiB
C
/* packet_list_store.c
|
|
* Routines to implement a custom GTK+ list model for Wireshark's packet list
|
|
* Copyright 2008-2009, Stephen Fisher (see AUTHORS file)
|
|
* * Co-authors Anders Broman and Kovarththanan Rajaratnam.
|
|
*
|
|
* $Id$
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
/* This code was originally based on the GTK+ Tree View tutorial at
|
|
* http://scentric.net/tutorial */
|
|
|
|
#include "config.h"
|
|
|
|
#include <string.h>
|
|
|
|
#include <gtk/gtk.h>
|
|
#include <glib.h>
|
|
|
|
#include "packet_list_store.h"
|
|
|
|
#include "ui/progress_dlg.h"
|
|
#include "ui/ui_util.h"
|
|
|
|
#include "ui/gtk/old-gtk-compat.h"
|
|
|
|
#include <epan/epan_dissect.h>
|
|
#include <epan/column_info.h>
|
|
#include <epan/column.h>
|
|
#include <epan/nstime.h>
|
|
|
|
#include "color.h"
|
|
#include "color_filters.h"
|
|
|
|
#include "globals.h"
|
|
|
|
/* #define PACKET_PARANOID_CHECKS */
|
|
|
|
/** PacketListRecord: represents a row */
|
|
typedef struct _PacketListRecord {
|
|
/** The column text for some columns */
|
|
const gchar **col_text;
|
|
/**< The length of the column text strings in 'col_text' */
|
|
gushort *col_text_len;
|
|
|
|
frame_data *fdata;
|
|
|
|
/* admin stuff used by the custom list model */
|
|
#ifdef PACKET_PARANOID_CHECKS
|
|
/** position within the physical array */
|
|
guint physical_pos;
|
|
#endif
|
|
/** position within the visible array */
|
|
gint visible_pos;
|
|
|
|
/** Has this record been columnized? */
|
|
guint columnized : 1;
|
|
/** Has this record been colorized? */
|
|
guint colorized : 1;
|
|
|
|
} PacketListRecord;
|
|
|
|
static void packet_list_init(PacketList *pkg_tree);
|
|
static void packet_list_class_init(PacketListClass *klass);
|
|
static void packet_list_tree_model_init(GtkTreeModelIface *iface);
|
|
static void packet_list_finalize(GObject *object);
|
|
static GtkTreeModelFlags packet_list_get_flags(GtkTreeModel *tree_model);
|
|
static gint packet_list_get_n_columns(GtkTreeModel *tree_model);
|
|
static GType packet_list_get_column_type(GtkTreeModel *tree_model, gint idx);
|
|
static gboolean packet_list_get_iter(GtkTreeModel *tree_model,
|
|
GtkTreeIter *iter, GtkTreePath *path);
|
|
static GtkTreePath *packet_list_get_path(GtkTreeModel *tree_model,
|
|
GtkTreeIter *iter);
|
|
static void packet_list_get_value(GtkTreeModel *tree_model, GtkTreeIter *iter,
|
|
gint column, GValue *value);
|
|
static gboolean packet_list_iter_next(GtkTreeModel *tree_model,
|
|
GtkTreeIter *iter);
|
|
static gboolean packet_list_iter_children(GtkTreeModel *tree_model,
|
|
GtkTreeIter *iter,
|
|
GtkTreeIter *parent);
|
|
static gboolean packet_list_iter_has_child(GtkTreeModel *tree_model _U_,
|
|
GtkTreeIter *iter _U_);
|
|
static gint packet_list_iter_n_children(GtkTreeModel *tree_model,
|
|
GtkTreeIter *iter);
|
|
static gboolean packet_list_iter_nth_child(GtkTreeModel *tree_model,
|
|
GtkTreeIter *iter,
|
|
GtkTreeIter *parent,
|
|
gint n);
|
|
static gboolean packet_list_iter_parent(GtkTreeModel *tree_model _U_,
|
|
GtkTreeIter *iter _U_,
|
|
GtkTreeIter *child _U_);
|
|
|
|
static gboolean packet_list_sortable_get_sort_column_id(GtkTreeSortable
|
|
*sortable,
|
|
gint *sort_col_id,
|
|
GtkSortType *order);
|
|
static void packet_list_sortable_set_sort_column_id(GtkTreeSortable *sortable,
|
|
gint sort_col_id,
|
|
GtkSortType order);
|
|
static void packet_list_sortable_set_sort_func(GtkTreeSortable *sortable,
|
|
gint sort_col_id,
|
|
GtkTreeIterCompareFunc sort_func,
|
|
gpointer user_data,
|
|
GDestroyNotify destroy_func);
|
|
static void packet_list_sortable_set_default_sort_func(GtkTreeSortable
|
|
*sortable,
|
|
GtkTreeIterCompareFunc
|
|
sort_func,
|
|
gpointer user_data,
|
|
GDestroyNotify
|
|
destroy_func);
|
|
static gboolean packet_list_sortable_has_default_sort_func(GtkTreeSortable
|
|
*sortable);
|
|
static void packet_list_sortable_init(GtkTreeSortableIface *iface);
|
|
static void packet_list_resort(PacketList *packet_list);
|
|
static void packet_list_dissect_and_cache_record(PacketList *packet_list, PacketListRecord *record, gboolean dissect_columns, gboolean dissect_color );
|
|
|
|
static GObjectClass *parent_class = NULL;
|
|
|
|
|
|
GType
|
|
packet_list_get_type(void)
|
|
{
|
|
static GType packet_list_type = 0;
|
|
|
|
if(packet_list_type == 0) {
|
|
static const GTypeInfo packet_list_info = {
|
|
sizeof(PacketListClass),
|
|
NULL, /* base_init */
|
|
NULL, /* base_finalize */
|
|
(GClassInitFunc) packet_list_class_init,
|
|
NULL, /* class finalize */
|
|
NULL, /* class_data */
|
|
sizeof(PacketList),
|
|
0, /* n_preallocs */
|
|
(GInstanceInitFunc) packet_list_init,
|
|
NULL /* value_table */
|
|
};
|
|
|
|
static const GInterfaceInfo tree_model_info = {
|
|
(GInterfaceInitFunc) packet_list_tree_model_init,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
static const GInterfaceInfo tree_sortable_info = {
|
|
(GInterfaceInitFunc) packet_list_sortable_init,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
/* Register the new derived type with the GObject type system */
|
|
packet_list_type = g_type_register_static(G_TYPE_OBJECT,
|
|
"PacketList",
|
|
&packet_list_info,
|
|
(GTypeFlags)0);
|
|
|
|
g_type_add_interface_static(packet_list_type,
|
|
GTK_TYPE_TREE_MODEL,
|
|
&tree_model_info);
|
|
|
|
|
|
/* Register our GtkTreeModel interface with the type system */
|
|
g_type_add_interface_static(packet_list_type,
|
|
GTK_TYPE_TREE_SORTABLE,
|
|
&tree_sortable_info);
|
|
}
|
|
|
|
return packet_list_type;
|
|
}
|
|
|
|
static void
|
|
packet_list_sortable_init(GtkTreeSortableIface *iface)
|
|
{
|
|
iface->get_sort_column_id = packet_list_sortable_get_sort_column_id;
|
|
iface->set_sort_column_id = packet_list_sortable_set_sort_column_id;
|
|
/* The following three functions are not implemented */
|
|
iface->set_sort_func = packet_list_sortable_set_sort_func;
|
|
iface->set_default_sort_func =
|
|
packet_list_sortable_set_default_sort_func;
|
|
iface->has_default_sort_func =
|
|
packet_list_sortable_has_default_sort_func;
|
|
}
|
|
|
|
static void
|
|
packet_list_class_init(PacketListClass *klass)
|
|
{
|
|
GObjectClass *object_class;
|
|
|
|
parent_class = (GObjectClass*) g_type_class_peek_parent(klass);
|
|
object_class = (GObjectClass*) klass;
|
|
|
|
object_class->finalize = packet_list_finalize;
|
|
|
|
#if !GTK_CHECK_VERSION(3,0,0)
|
|
/* XXX this seems to affect TreeView Application wide
|
|
* Move to main.c ??? as it's not a bad thing(tm)
|
|
*/
|
|
gtk_rc_parse_string (
|
|
"style \"PacketList-style\"\n"
|
|
"{\n"
|
|
" GtkTreeView::horizontal-separator = 0\n"
|
|
" GtkTreeView::vertical-separator = 1\n"
|
|
"} widget_class \"*TreeView*\""
|
|
" style \"PacketList-style\"");
|
|
#endif
|
|
|
|
}
|
|
|
|
static void
|
|
packet_list_tree_model_init(GtkTreeModelIface *iface)
|
|
{
|
|
iface->get_flags = packet_list_get_flags;
|
|
iface->get_n_columns = packet_list_get_n_columns;
|
|
iface->get_column_type = packet_list_get_column_type;
|
|
iface->get_iter = packet_list_get_iter;
|
|
iface->get_path = packet_list_get_path;
|
|
iface->get_value = packet_list_get_value;
|
|
iface->iter_next = packet_list_iter_next;
|
|
iface->iter_children = packet_list_iter_children;
|
|
iface->iter_has_child = packet_list_iter_has_child;
|
|
iface->iter_n_children = packet_list_iter_n_children;
|
|
iface->iter_nth_child = packet_list_iter_nth_child;
|
|
iface->iter_parent = packet_list_iter_parent;
|
|
}
|
|
|
|
/* This is called every time a new packet list object instance is created in
|
|
* packet_list_new. Initialize the list structure's fields here. */
|
|
static void
|
|
packet_list_init(PacketList *packet_list)
|
|
{
|
|
gint i, j;
|
|
|
|
/* To check whether an iter belongs to our model. */
|
|
packet_list->stamp = g_random_int();
|
|
|
|
packet_list->n_cols = cfile.cinfo.num_cols;
|
|
packet_list->physical_rows = g_ptr_array_new();
|
|
packet_list->visible_rows = g_ptr_array_new();
|
|
|
|
packet_list->columnized = FALSE;
|
|
packet_list->sort_id = 0; /* defaults to first column for now */
|
|
packet_list->sort_order = GTK_SORT_ASCENDING;
|
|
|
|
packet_list->col_to_text = g_new(int, packet_list->n_cols);
|
|
for (i = 0, j = 0; i < packet_list->n_cols; i++) {
|
|
if (!col_based_on_frame_data(&cfile.cinfo, i)) {
|
|
packet_list->col_to_text[i] = j;
|
|
j++;
|
|
} else
|
|
packet_list->col_to_text[i] = -1;
|
|
}
|
|
packet_list->n_text_cols = j;
|
|
|
|
#ifdef PACKET_LIST_STATISTICS
|
|
packet_list->const_strings = 0;
|
|
#endif
|
|
}
|
|
|
|
/* This function is called just before a packet list is destroyed. Free
|
|
* dynamically allocated memory here. */
|
|
static void
|
|
packet_list_finalize(GObject *object)
|
|
{
|
|
/* PacketList *packet_list = PACKET_LIST(object); */
|
|
|
|
/* XXX - Free all records and free all memory used by the list */
|
|
|
|
/* must chain up - finalize parent */
|
|
(* parent_class->finalize) (object);
|
|
}
|
|
|
|
static GtkTreeModelFlags
|
|
packet_list_get_flags(GtkTreeModel *tree_model)
|
|
{
|
|
g_return_val_if_fail(PACKETLIST_IS_LIST(tree_model),
|
|
(GtkTreeModelFlags)0);
|
|
|
|
return (GTK_TREE_MODEL_LIST_ONLY | GTK_TREE_MODEL_ITERS_PERSIST);
|
|
}
|
|
|
|
static gint
|
|
packet_list_get_n_columns(GtkTreeModel *tree_model)
|
|
{
|
|
PacketList *packet_list;
|
|
|
|
g_return_val_if_fail(PACKETLIST_IS_LIST(tree_model), 0);
|
|
packet_list = (PacketList *) tree_model;
|
|
|
|
/* Note: We need one extra column to store the entire frame_data */
|
|
return packet_list->n_cols + 1;
|
|
}
|
|
|
|
static GType
|
|
packet_list_get_column_type(GtkTreeModel *tree_model, gint idx)
|
|
{
|
|
PacketList *packet_list;
|
|
|
|
g_return_val_if_fail(PACKETLIST_IS_LIST(tree_model), G_TYPE_INVALID);
|
|
packet_list = (PacketList *) tree_model;
|
|
|
|
/* Note: We use one extra column to store the entire frame_data */
|
|
g_return_val_if_fail(idx >= 0 && idx < packet_list->n_cols + 1, G_TYPE_INVALID);
|
|
|
|
if (idx >= 0 && idx < packet_list->n_cols)
|
|
return G_TYPE_STRING;
|
|
else if (idx == packet_list->n_cols)
|
|
return G_TYPE_POINTER;
|
|
else
|
|
return G_TYPE_INVALID;
|
|
}
|
|
|
|
static gboolean
|
|
packet_list_get_iter(GtkTreeModel *tree_model, GtkTreeIter *iter,
|
|
GtkTreePath *path)
|
|
{
|
|
PacketList *packet_list;
|
|
PacketListRecord *record;
|
|
gint *indices, depth;
|
|
gint n;
|
|
|
|
g_assert(PACKETLIST_IS_LIST(tree_model));
|
|
packet_list = (PacketList *) tree_model;
|
|
|
|
g_assert(path != NULL);
|
|
|
|
indices = gtk_tree_path_get_indices(path);
|
|
depth = gtk_tree_path_get_depth(path);
|
|
|
|
/* we do not allow children since it's just a list */
|
|
g_assert(depth == 1);
|
|
|
|
n = indices[0]; /* the n-th top level row */
|
|
|
|
if(PACKET_LIST_RECORD_COUNT(packet_list->visible_rows) == 0)
|
|
return FALSE;
|
|
|
|
if(!PACKET_LIST_RECORD_INDEX_VALID(packet_list->visible_rows, n))
|
|
return FALSE;
|
|
|
|
record = PACKET_LIST_RECORD_GET(packet_list->visible_rows, n);
|
|
|
|
g_assert(record->visible_pos == n);
|
|
|
|
/* We simply store a pointer to our custom record in the iter */
|
|
iter->stamp = packet_list->stamp;
|
|
iter->user_data = record;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static GtkTreePath *
|
|
packet_list_get_path(GtkTreeModel *tree_model, GtkTreeIter *iter)
|
|
{
|
|
GtkTreePath *path;
|
|
PacketListRecord *record;
|
|
PacketList *packet_list;
|
|
|
|
g_return_val_if_fail(PACKETLIST_IS_LIST(tree_model), NULL);
|
|
packet_list = (PacketList *) tree_model;
|
|
|
|
g_return_val_if_fail(iter != NULL, NULL);
|
|
g_return_val_if_fail(iter->stamp == packet_list->stamp, NULL);
|
|
g_return_val_if_fail(iter->user_data != NULL, NULL);
|
|
|
|
record = (PacketListRecord*) iter->user_data;
|
|
|
|
path = gtk_tree_path_new();
|
|
gtk_tree_path_append_index(path, record->visible_pos);
|
|
|
|
return path;
|
|
}
|
|
|
|
static void
|
|
packet_list_get_value(GtkTreeModel *tree_model, GtkTreeIter *iter, gint column,
|
|
GValue *value)
|
|
{
|
|
PacketListRecord *record;
|
|
PacketList *packet_list;
|
|
|
|
g_return_if_fail(PACKETLIST_IS_LIST(tree_model));
|
|
packet_list = (PacketList *) tree_model;
|
|
|
|
g_return_if_fail(iter != NULL);
|
|
g_return_if_fail(iter->stamp == packet_list->stamp);
|
|
g_return_if_fail(iter->user_data != NULL);
|
|
|
|
/* Note: We use one extra column to store the entire frame_data */
|
|
g_return_if_fail(column >= 0 && column < packet_list->n_cols + 1);
|
|
|
|
record = (PacketListRecord*) iter->user_data;
|
|
|
|
#ifdef PACKET_PARANOID_CHECKS
|
|
g_return_if_fail(PACKET_LIST_RECORD_INDEX_VALID(packet_list->physical_rows, record->physical_pos));
|
|
#endif
|
|
g_return_if_fail(PACKET_LIST_RECORD_INDEX_VALID(packet_list->visible_rows, record->visible_pos));
|
|
|
|
if (column >= 0 && column < packet_list->n_cols) {
|
|
int text_column;
|
|
|
|
g_value_init(value, G_TYPE_STRING);
|
|
|
|
if (!record->columnized || !record->colorized)
|
|
packet_list_dissect_and_cache_record(packet_list, record, !record->columnized, !record->colorized);
|
|
|
|
text_column = packet_list->col_to_text[column];
|
|
if (text_column == -1) { /* column based on frame_data */
|
|
col_fill_in_frame_data(record->fdata, &cfile.cinfo, column, FALSE);
|
|
g_value_set_string(value, cfile.cinfo.col_data[column]);
|
|
} else {
|
|
g_return_if_fail(record->col_text);
|
|
g_value_set_string(value, record->col_text[text_column]);
|
|
}
|
|
|
|
} else if (column == packet_list->n_cols) {
|
|
g_value_init(value, G_TYPE_POINTER);
|
|
g_value_set_pointer(value, record->fdata);
|
|
}
|
|
}
|
|
|
|
static PacketListRecord *
|
|
packet_list_iter_next_visible(PacketList *packet_list, PacketListRecord *record)
|
|
{
|
|
PacketListRecord *nextrecord;
|
|
gint next_visible_pos;
|
|
|
|
g_assert(record->visible_pos >= 0);
|
|
next_visible_pos = record->visible_pos + 1;
|
|
|
|
/* Is this the last record in the list? */
|
|
if(!PACKET_LIST_RECORD_INDEX_VALID(packet_list->visible_rows, next_visible_pos))
|
|
return NULL;
|
|
|
|
nextrecord = PACKET_LIST_RECORD_GET(packet_list->visible_rows, next_visible_pos);
|
|
|
|
g_assert(nextrecord->visible_pos == (record->visible_pos + 1));
|
|
#ifdef PACKET_PARANOID_CHECKS
|
|
g_assert(nextrecord->physical_pos >= (record->physical_pos + 1));
|
|
#endif
|
|
|
|
return nextrecord;
|
|
}
|
|
|
|
/* Takes an iter structure and sets it to point to the next row. */
|
|
static gboolean
|
|
packet_list_iter_next(GtkTreeModel *tree_model, GtkTreeIter *iter)
|
|
{
|
|
PacketListRecord *record, *nextrecord;
|
|
PacketList *packet_list;
|
|
|
|
g_return_val_if_fail(PACKETLIST_IS_LIST(tree_model), FALSE);
|
|
packet_list = (PacketList *) tree_model;
|
|
|
|
if(iter == NULL)
|
|
return FALSE;
|
|
|
|
g_return_val_if_fail(iter->stamp == packet_list->stamp, FALSE);
|
|
g_return_val_if_fail(iter->user_data, FALSE);
|
|
|
|
record = (PacketListRecord*) iter->user_data;
|
|
nextrecord = packet_list_iter_next_visible(packet_list, record);
|
|
|
|
if (!nextrecord)
|
|
return FALSE;
|
|
|
|
/* iter->stamp = packet_list->stamp; */
|
|
iter->user_data = nextrecord;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
packet_list_iter_children(GtkTreeModel *tree_model, GtkTreeIter *iter,
|
|
GtkTreeIter *parent)
|
|
{
|
|
PacketList *packet_list;
|
|
|
|
g_return_val_if_fail(PACKETLIST_IS_LIST(tree_model), FALSE);
|
|
packet_list = (PacketList *) tree_model;
|
|
|
|
/* This is a list, nodes have no children. */
|
|
if(parent) {
|
|
g_return_val_if_fail(parent->stamp == packet_list->stamp, FALSE);
|
|
g_return_val_if_fail(parent->user_data, FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
/* No rows => no first row */
|
|
if(PACKET_LIST_RECORD_COUNT(packet_list->visible_rows) == 0)
|
|
return FALSE;
|
|
|
|
/* Set iter to first item in list */
|
|
iter->stamp = packet_list->stamp;
|
|
iter->user_data = PACKET_LIST_RECORD_GET(packet_list->visible_rows, 0);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
packet_list_iter_has_child(GtkTreeModel *tree_model _U_, GtkTreeIter *iter _U_)
|
|
{
|
|
return FALSE; /* Lists have no children */
|
|
}
|
|
|
|
static gint
|
|
packet_list_iter_n_children(GtkTreeModel *tree_model, GtkTreeIter *iter)
|
|
{
|
|
PacketList *packet_list;
|
|
|
|
g_return_val_if_fail(PACKETLIST_IS_LIST(tree_model), 0);
|
|
packet_list = (PacketList *) tree_model;
|
|
|
|
if(!iter) {
|
|
/* special case: if iter == NULL, return number of top-level rows */
|
|
return PACKET_LIST_RECORD_COUNT(packet_list->visible_rows);
|
|
}
|
|
else {
|
|
g_return_val_if_fail(iter->stamp == packet_list->stamp, 0);
|
|
g_return_val_if_fail(iter->user_data, 0);
|
|
/* Lists have zero children */
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
packet_list_iter_nth_child(GtkTreeModel *tree_model, GtkTreeIter *iter,
|
|
GtkTreeIter *parent, gint n)
|
|
{
|
|
PacketListRecord *record;
|
|
PacketList *packet_list;
|
|
|
|
g_return_val_if_fail(PACKETLIST_IS_LIST(tree_model), FALSE);
|
|
packet_list = (PacketList *) tree_model;
|
|
|
|
/* A list only has top-level rows */
|
|
if(parent) {
|
|
g_return_val_if_fail(parent->stamp == packet_list->stamp, FALSE);
|
|
g_return_val_if_fail(parent->user_data, FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Special case: if parent == NULL, set iter to n-th top-level row. */
|
|
if(!PACKET_LIST_RECORD_INDEX_VALID(packet_list->visible_rows, n))
|
|
return FALSE;
|
|
|
|
record = PACKET_LIST_RECORD_GET(packet_list->visible_rows, n);
|
|
|
|
g_assert(record->visible_pos == n);
|
|
|
|
iter->stamp = packet_list->stamp;
|
|
iter->user_data = record;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
packet_list_iter_parent(GtkTreeModel *tree_model _U_, GtkTreeIter *iter _U_,
|
|
GtkTreeIter *child _U_)
|
|
{
|
|
return FALSE; /* No parents since no children in a list */
|
|
}
|
|
|
|
PacketList *
|
|
packet_list_new(void)
|
|
{
|
|
PacketList *newpacketlist;
|
|
|
|
newpacketlist = (PacketList*) g_object_new(PACKETLIST_TYPE_LIST, NULL);
|
|
|
|
g_assert(newpacketlist != NULL);
|
|
|
|
return newpacketlist;
|
|
}
|
|
|
|
#if 0
|
|
static void
|
|
packet_list_row_deleted(PacketList *packet_list, guint pos)
|
|
{
|
|
GtkTreePath *path;
|
|
|
|
/* Inform the tree view and other interested objects (such as tree row
|
|
* references) that we have deleted a row */
|
|
path = gtk_tree_path_new();
|
|
gtk_tree_path_append_index(path, pos);
|
|
|
|
gtk_tree_model_row_deleted(GTK_TREE_MODEL(packet_list), path);
|
|
|
|
gtk_tree_path_free(path);
|
|
}
|
|
#endif
|
|
|
|
void
|
|
packet_list_store_clear(PacketList *packet_list)
|
|
{
|
|
g_return_if_fail(packet_list != NULL);
|
|
g_return_if_fail(PACKETLIST_IS_LIST(packet_list));
|
|
|
|
/* Don't issue a row_deleted signal. We rely on our caller to have disconnected
|
|
* the model from the view.
|
|
for( ; packet_list->num_rows > 0; --packet_list->num_rows)
|
|
packet_list_row_deleted(packet_list, packet_list->num_rows-1);
|
|
*/
|
|
|
|
/* XXX - hold on to these rows and reuse them instead */
|
|
if(packet_list->physical_rows)
|
|
g_ptr_array_free(packet_list->physical_rows, TRUE);
|
|
if(packet_list->visible_rows)
|
|
g_ptr_array_free(packet_list->visible_rows, TRUE);
|
|
packet_list->physical_rows = g_ptr_array_new();
|
|
packet_list->visible_rows = g_ptr_array_new();
|
|
|
|
packet_list->columnized = FALSE;
|
|
|
|
/* Generate new number */
|
|
packet_list->stamp = g_random_int();
|
|
|
|
#ifdef PACKET_LIST_STATISTICS
|
|
g_warning("Const strings: %u", packet_list->const_strings);
|
|
packet_list->const_strings = 0;
|
|
#endif
|
|
}
|
|
|
|
gint
|
|
packet_list_append_record(PacketList *packet_list, frame_data *fdata)
|
|
{
|
|
PacketListRecord *newrecord;
|
|
|
|
g_return_val_if_fail(PACKETLIST_IS_LIST(packet_list), -1);
|
|
|
|
newrecord = se_alloc(sizeof(PacketListRecord));
|
|
newrecord->columnized = FALSE;
|
|
newrecord->colorized = FALSE;
|
|
newrecord->col_text_len = se_alloc0(sizeof(*newrecord->col_text_len) * packet_list->n_text_cols);
|
|
newrecord->col_text = se_alloc0(sizeof(*newrecord->col_text) * packet_list->n_text_cols);
|
|
newrecord->fdata = fdata;
|
|
#ifdef PACKET_PARANOID_CHECKS
|
|
newrecord->physical_pos = PACKET_LIST_RECORD_COUNT(packet_list->physical_rows);
|
|
#endif
|
|
|
|
if (fdata->flags.passed_dfilter || fdata->flags.ref_time) {
|
|
newrecord->visible_pos = PACKET_LIST_RECORD_COUNT(packet_list->visible_rows);
|
|
PACKET_LIST_RECORD_APPEND(packet_list->visible_rows, newrecord);
|
|
}
|
|
else
|
|
newrecord->visible_pos = -1;
|
|
|
|
PACKET_LIST_RECORD_APPEND(packet_list->physical_rows, newrecord);
|
|
|
|
packet_list->columnized = FALSE; /* XXX, dissect? */
|
|
|
|
/*
|
|
* Issue a row_inserted signal if the model is connected
|
|
* and the row is visible.
|
|
*/
|
|
if (gtk_tree_view_get_model(GTK_TREE_VIEW(packet_list->view)) && newrecord->visible_pos != -1) {
|
|
GtkTreeIter iter;
|
|
GtkTreePath *path;
|
|
|
|
path = gtk_tree_path_new();
|
|
gtk_tree_path_append_index(path, newrecord->visible_pos);
|
|
|
|
iter.stamp = packet_list->stamp;
|
|
iter.user_data = newrecord;
|
|
|
|
gtk_tree_model_row_inserted(GTK_TREE_MODEL(packet_list), path, &iter);
|
|
gtk_tree_path_free(path);
|
|
}
|
|
|
|
/* XXXX If the model is connected and sort column != frame_num we should
|
|
* probably resort.
|
|
* Don't resort the list for every row, the list will be in packet order any way.
|
|
* packet_list_resort(packet_list);
|
|
*/
|
|
|
|
return newrecord->visible_pos;
|
|
}
|
|
|
|
static void
|
|
packet_list_change_record(PacketList *packet_list, PacketListRecord *record, gint col, column_info *cinfo)
|
|
{
|
|
gchar *str;
|
|
size_t col_text_len;
|
|
int text_col;
|
|
|
|
text_col = packet_list->col_to_text[col];
|
|
|
|
/* Column based on frame_data or it already contains a value */
|
|
if (text_col == -1 || record->col_text[text_col] != NULL)
|
|
return;
|
|
|
|
switch (cfile.cinfo.col_fmt[col]) {
|
|
case COL_DEF_SRC:
|
|
case COL_RES_SRC: /* COL_DEF_SRC is currently just like COL_RES_SRC */
|
|
case COL_UNRES_SRC:
|
|
case COL_DEF_DL_SRC:
|
|
case COL_RES_DL_SRC:
|
|
case COL_UNRES_DL_SRC:
|
|
case COL_DEF_NET_SRC:
|
|
case COL_RES_NET_SRC:
|
|
case COL_UNRES_NET_SRC:
|
|
case COL_DEF_DST:
|
|
case COL_RES_DST: /* COL_DEF_DST is currently just like COL_RES_DST */
|
|
case COL_UNRES_DST:
|
|
case COL_DEF_DL_DST:
|
|
case COL_RES_DL_DST:
|
|
case COL_UNRES_DL_DST:
|
|
case COL_DEF_NET_DST:
|
|
case COL_RES_NET_DST:
|
|
case COL_UNRES_NET_DST:
|
|
case COL_PROTOCOL:
|
|
case COL_INFO:
|
|
case COL_IF_DIR:
|
|
case COL_DCE_CALL:
|
|
case COL_8021Q_VLAN_ID:
|
|
case COL_EXPERT:
|
|
case COL_FREQ_CHAN:
|
|
if (cinfo->col_data[col] && cinfo->col_data[col] != cinfo->col_buf[col]) {
|
|
col_text_len = strlen(cinfo->col_data[col]);
|
|
if (col_text_len > G_MAXUSHORT)
|
|
col_text_len = G_MAXUSHORT;
|
|
|
|
/* This is a constant string, so we don't have to copy it */
|
|
record->col_text[text_col] = (gchar *) cinfo->col_data[col];
|
|
record->col_text_len[text_col] = (gushort) col_text_len;
|
|
#ifdef PACKET_LIST_STATISTICS
|
|
++packet_list->const_strings;
|
|
#endif
|
|
break;
|
|
}
|
|
/* !! FALL-THROUGH!! */
|
|
|
|
default:
|
|
col_text_len = strlen(cinfo->col_data[col]);
|
|
if (col_text_len > G_MAXUSHORT)
|
|
col_text_len = G_MAXUSHORT;
|
|
|
|
record->col_text_len[text_col] = (gushort) col_text_len;
|
|
if (!record->col_text_len[text_col]) {
|
|
record->col_text[text_col] = "";
|
|
#ifdef PACKET_LIST_STATISTICS
|
|
++packet_list->const_strings;
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
if(!packet_list->string_pool)
|
|
packet_list->string_pool = g_string_chunk_new(32);
|
|
if (!get_column_resolved (col) && cinfo->col_expr.col_expr_val[col]) {
|
|
/* Use the unresolved value in col_expr_val */
|
|
str = g_string_chunk_insert_const (packet_list->string_pool, (const gchar *)cinfo->col_expr.col_expr_val[col]);
|
|
} else {
|
|
str = g_string_chunk_insert_const (packet_list->string_pool, (const gchar *)cinfo->col_data[col]);
|
|
}
|
|
record->col_text[text_col] = str;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
packet_list_sortable_get_sort_column_id(GtkTreeSortable *sortable,
|
|
gint *sort_col_id,
|
|
GtkSortType *order)
|
|
{
|
|
PacketList *packet_list;
|
|
|
|
g_return_val_if_fail(sortable != NULL, FALSE);
|
|
g_return_val_if_fail(PACKETLIST_IS_LIST(sortable), FALSE);
|
|
|
|
packet_list = (PacketList *) sortable;
|
|
|
|
if(sort_col_id)
|
|
*sort_col_id = packet_list->sort_id;
|
|
|
|
if(order)
|
|
*order = packet_list->sort_order;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
packet_list_column_contains_values(PacketList *packet_list, gint sort_col_id)
|
|
{
|
|
if (packet_list->columnized || col_based_on_frame_data(&cfile.cinfo, sort_col_id))
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
/* packet_list_dissect_and_cache_all()
|
|
* returns:
|
|
* TRUE if columnization completed;
|
|
* packet_list->columnized set to TRUE;
|
|
* FALSE: columnization did not complete (i.e., was stopped by the user);
|
|
* packet_list->columnized unchanged (i.e., FALSE).
|
|
*/
|
|
|
|
static gboolean
|
|
packet_list_dissect_and_cache_all(PacketList *packet_list)
|
|
{
|
|
PacketListRecord *record;
|
|
|
|
int progbar_nextstep;
|
|
int progbar_quantum;
|
|
gboolean progbar_stop_flag;
|
|
GTimeVal progbar_start_time;
|
|
float progbar_val;
|
|
progdlg_t *progbar = NULL;
|
|
gchar progbar_status_str[100];
|
|
gint progbar_loop_max;
|
|
gint progbar_loop_var;
|
|
gint progbar_updates = 100 /* 100% */;
|
|
|
|
g_assert(packet_list->columnized == FALSE);
|
|
|
|
progbar_loop_max = PACKET_LIST_RECORD_COUNT(packet_list->physical_rows);
|
|
/* Update the progress bar when it gets to this value. */
|
|
progbar_nextstep = 0;
|
|
/* When we reach the value that triggers a progress bar update,
|
|
bump that value by this amount. */
|
|
progbar_quantum = progbar_loop_max/progbar_updates;
|
|
/* Progress so far. */
|
|
progbar_val = 0.0f;
|
|
|
|
progbar_stop_flag = FALSE;
|
|
g_get_current_time(&progbar_start_time);
|
|
|
|
main_window_update();
|
|
|
|
for (progbar_loop_var = 0; progbar_loop_var < progbar_loop_max; ++progbar_loop_var) {
|
|
record = PACKET_LIST_RECORD_GET(packet_list->physical_rows, progbar_loop_var);
|
|
packet_list_dissect_and_cache_record(packet_list, record, TRUE, FALSE);
|
|
|
|
/* Create the progress bar if necessary.
|
|
We check on every iteration of the loop, so that it takes no
|
|
longer than the standard time to create it (otherwise, for a
|
|
large file, we might take considerably longer than that standard
|
|
time in order to get to the next progress bar step). */
|
|
if (progbar == NULL)
|
|
/* Note: The following may call gtk_main_iteration() which will */
|
|
/* allow certain "interupts" to happen during this code. */
|
|
/* (Note that the progress_dlg window is set to "modal" */
|
|
/* so that clicking on other windows is disabled). */
|
|
progbar = delayed_create_progress_dlg(gtk_widget_get_window(packet_list->view),
|
|
"Construct", "Columns",
|
|
TRUE, &progbar_stop_flag,
|
|
&progbar_start_time, progbar_val);
|
|
|
|
if (progbar_loop_var >= progbar_nextstep) {
|
|
/* let's not divide by zero. We should never be started
|
|
* with count == 0, so let's assert that */
|
|
g_assert(progbar_loop_max > 0);
|
|
|
|
progbar_val = (gfloat) progbar_loop_var / progbar_loop_max;
|
|
|
|
if (progbar != NULL) {
|
|
g_snprintf(progbar_status_str, sizeof(progbar_status_str),
|
|
"%u of %u frames", progbar_loop_var+1, progbar_loop_max);
|
|
/* Note: See comment above re use of gtk_main_iteration() */
|
|
update_progress_dlg(progbar, progbar_val, progbar_status_str);
|
|
}
|
|
|
|
progbar_nextstep += progbar_quantum;
|
|
}
|
|
|
|
if (progbar_stop_flag) {
|
|
/* Well, the user decided to abort ... */
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* We're done; destroy the progress bar if it was created. */
|
|
if (progbar != NULL)
|
|
destroy_progress_dlg(progbar);
|
|
|
|
if (progbar_stop_flag) {
|
|
return FALSE; /* user aborted before columnization completed */
|
|
}
|
|
|
|
packet_list->columnized = TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
/* packet_list_do_packet_list_dissect_and_cache_all()
|
|
* returns:
|
|
* TRUE: if columnization not needed or columnization completed;
|
|
* FALSE: columnization did not complete (i.e., stopped by the user)
|
|
*/
|
|
gboolean
|
|
packet_list_do_packet_list_dissect_and_cache_all(PacketList *packet_list, gint sort_col_id)
|
|
{
|
|
if (!packet_list_column_contains_values(packet_list, sort_col_id)) {
|
|
return packet_list_dissect_and_cache_all(packet_list);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
packet_list_sortable_set_sort_column_id(GtkTreeSortable *sortable,
|
|
gint sort_col_id,
|
|
GtkSortType order)
|
|
{
|
|
PacketList *packet_list;
|
|
|
|
g_return_if_fail(sortable != NULL);
|
|
g_return_if_fail(PACKETLIST_IS_LIST(sortable));
|
|
|
|
packet_list = (PacketList *) sortable;
|
|
|
|
if(packet_list->sort_id == sort_col_id &&
|
|
packet_list->sort_order == order)
|
|
return;
|
|
|
|
packet_list->sort_id = sort_col_id;
|
|
packet_list->sort_order = order;
|
|
|
|
if(PACKET_LIST_RECORD_COUNT(packet_list->physical_rows) == 0)
|
|
return;
|
|
|
|
packet_list_resort(packet_list);
|
|
|
|
/* emit "sort-column-changed" signal to tell any tree views
|
|
* that the sort column has changed (so the little arrow
|
|
* in the column header of the sort column is drawn
|
|
* in the right column) */
|
|
|
|
gtk_tree_sortable_sort_column_changed(sortable);
|
|
}
|
|
|
|
static void
|
|
packet_list_sortable_set_sort_func(GtkTreeSortable *sortable _U_,
|
|
gint sort_col_id _U_,
|
|
GtkTreeIterCompareFunc sort_func _U_,
|
|
gpointer user_data _U_,
|
|
GDestroyNotify destroy_func _U_)
|
|
{
|
|
g_warning(G_STRLOC ": is not supported by the PacketList model.\n");
|
|
}
|
|
|
|
static void
|
|
packet_list_sortable_set_default_sort_func(GtkTreeSortable *sortable _U_,
|
|
GtkTreeIterCompareFunc sort_func _U_,
|
|
gpointer user_data _U_,
|
|
GDestroyNotify destroy_func _U_)
|
|
{
|
|
g_warning(G_STRLOC ": is not supported by the PacketList model.\n");
|
|
}
|
|
|
|
static gboolean
|
|
packet_list_sortable_has_default_sort_func(GtkTreeSortable *sortable _U_)
|
|
{
|
|
return FALSE; /* Since packet_list_sortable_set_sort_func and
|
|
set_default_sort_func are not implemented. */
|
|
}
|
|
|
|
static gint
|
|
packet_list_compare_custom(gint sort_id, gint text_sort_id, PacketListRecord *a, PacketListRecord *b)
|
|
{
|
|
header_field_info *hfi;
|
|
|
|
hfi = proto_registrar_get_byname(cfile.cinfo.col_custom_field[sort_id]);
|
|
|
|
if (hfi == NULL) {
|
|
return frame_data_compare(a->fdata, b->fdata, COL_NUMBER);
|
|
} else if ((hfi->strings == NULL) &&
|
|
(((IS_FT_INT(hfi->type) || IS_FT_UINT(hfi->type)) &&
|
|
((hfi->display == BASE_DEC) || (hfi->display == BASE_DEC_HEX) ||
|
|
(hfi->display == BASE_OCT))) ||
|
|
(hfi->type == FT_DOUBLE) || (hfi->type == FT_FLOAT) ||
|
|
(hfi->type == FT_BOOLEAN) || (hfi->type == FT_FRAMENUM) ||
|
|
(hfi->type == FT_RELATIVE_TIME)))
|
|
{
|
|
/* Attempt to convert to numbers */
|
|
double num_a = atof(a->col_text[text_sort_id]);
|
|
double num_b = atof(b->col_text[text_sort_id]);
|
|
|
|
if (num_a < num_b)
|
|
return -1;
|
|
else if (num_a > num_b)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
return strcmp(a->col_text[text_sort_id], b->col_text[text_sort_id]);
|
|
}
|
|
|
|
static gint
|
|
_packet_list_compare_records(gint sort_id, gint text_sort_id, PacketListRecord *a, PacketListRecord *b)
|
|
{
|
|
g_assert(a->col_text);
|
|
g_assert(b->col_text);
|
|
g_assert(a->col_text[text_sort_id]);
|
|
g_assert(b->col_text[text_sort_id]);
|
|
|
|
if(a->col_text[text_sort_id] == b->col_text[text_sort_id])
|
|
return 0; /* no need to call strcmp() */
|
|
|
|
if (cfile.cinfo.col_fmt[sort_id] == COL_CUSTOM)
|
|
return packet_list_compare_custom(sort_id, text_sort_id, a, b);
|
|
|
|
return strcmp(a->col_text[text_sort_id], b->col_text[text_sort_id]);
|
|
}
|
|
|
|
static gint
|
|
packet_list_compare_records(gint sort_id, gint text_sort_id, PacketListRecord *a, PacketListRecord *b)
|
|
{
|
|
gint ret;
|
|
|
|
if (text_sort_id == -1) /* based on frame_data ? */
|
|
return frame_data_compare(a->fdata, b->fdata, cfile.cinfo.col_fmt[sort_id]);
|
|
|
|
ret = _packet_list_compare_records(sort_id, text_sort_id, a, b);
|
|
if (ret == 0)
|
|
ret = frame_data_compare(a->fdata, b->fdata, COL_NUMBER);
|
|
return ret;
|
|
}
|
|
|
|
static gint
|
|
packet_list_qsort_physical_compare_func(PacketListRecord **a, PacketListRecord **b,
|
|
PacketList *packet_list)
|
|
{
|
|
gint ret;
|
|
gint sort_id = packet_list->sort_id;
|
|
|
|
g_assert((a) && (b) && (packet_list));
|
|
|
|
ret = packet_list_compare_records(sort_id, packet_list->col_to_text[sort_id], *a, *b);
|
|
|
|
/* Swap -1 and 1 if sort order is reverse */
|
|
if(ret != 0 && packet_list->sort_order == GTK_SORT_DESCENDING)
|
|
ret = (ret < 0) ? 1 : -1;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void
|
|
packet_list_resort(PacketList *packet_list)
|
|
{
|
|
PacketListRecord *record;
|
|
GtkTreePath *path;
|
|
gint *neworder;
|
|
guint phy_idx;
|
|
guint vis_idx;
|
|
|
|
g_return_if_fail(packet_list != NULL);
|
|
g_return_if_fail(PACKETLIST_IS_LIST(packet_list));
|
|
|
|
if(PACKET_LIST_RECORD_COUNT(packet_list->visible_rows) == 0)
|
|
return;
|
|
|
|
/* resort physical rows according to sorting column */
|
|
g_ptr_array_sort_with_data(packet_list->physical_rows,
|
|
(GCompareDataFunc) packet_list_qsort_physical_compare_func,
|
|
packet_list);
|
|
|
|
/* let other objects know about the new order */
|
|
neworder = g_new0(gint, PACKET_LIST_RECORD_COUNT(packet_list->visible_rows));
|
|
|
|
for(phy_idx = 0, vis_idx = 0; phy_idx < PACKET_LIST_RECORD_COUNT(packet_list->physical_rows); ++phy_idx) {
|
|
record = PACKET_LIST_RECORD_GET(packet_list->physical_rows, phy_idx);
|
|
#ifdef PACKET_PARANOID_CHECKS
|
|
record->physical_pos = phy_idx;
|
|
#endif
|
|
g_assert(record->visible_pos >= -1);
|
|
if (record->visible_pos >= 0) {
|
|
g_assert(record->fdata->flags.passed_dfilter || record->fdata->flags.ref_time);
|
|
neworder[vis_idx] = record->visible_pos;
|
|
PACKET_LIST_RECORD_SET(packet_list->visible_rows, vis_idx, record);
|
|
record->visible_pos = vis_idx;
|
|
++vis_idx;
|
|
}
|
|
}
|
|
|
|
g_assert(vis_idx == PACKET_LIST_RECORD_COUNT(packet_list->visible_rows));
|
|
|
|
path = gtk_tree_path_new();
|
|
|
|
gtk_tree_model_rows_reordered(GTK_TREE_MODEL(packet_list), path, NULL,
|
|
neworder);
|
|
|
|
gtk_tree_path_free(path);
|
|
g_free(neworder);
|
|
}
|
|
|
|
guint
|
|
packet_list_recreate_visible_rows_list(PacketList *packet_list)
|
|
{
|
|
guint phy_idx;
|
|
guint vis_idx;
|
|
PacketListRecord *record;
|
|
|
|
g_return_val_if_fail(packet_list != NULL, 0);
|
|
g_return_val_if_fail(PACKETLIST_IS_LIST(packet_list), 0);
|
|
|
|
if(PACKET_LIST_RECORD_COUNT(packet_list->physical_rows) == 0)
|
|
return 0;
|
|
|
|
if(packet_list->visible_rows)
|
|
g_ptr_array_free(packet_list->visible_rows, TRUE);
|
|
|
|
packet_list->visible_rows = g_ptr_array_new();
|
|
|
|
for(phy_idx = 0, vis_idx = 0; phy_idx < PACKET_LIST_RECORD_COUNT(packet_list->physical_rows); ++phy_idx) {
|
|
record = PACKET_LIST_RECORD_GET(packet_list->physical_rows, phy_idx);
|
|
if (record->fdata->flags.passed_dfilter || record->fdata->flags.ref_time) {
|
|
record->visible_pos = vis_idx++;
|
|
PACKET_LIST_RECORD_APPEND(packet_list->visible_rows, record);
|
|
}
|
|
else
|
|
record->visible_pos = -1;
|
|
}
|
|
|
|
return vis_idx;
|
|
}
|
|
|
|
static void
|
|
packet_list_dissect_and_cache_record(PacketList *packet_list, PacketListRecord *record, gboolean dissect_columns, gboolean dissect_color)
|
|
{
|
|
epan_dissect_t edt;
|
|
frame_data *fdata;
|
|
column_info *cinfo;
|
|
gint col;
|
|
gboolean create_proto_tree;
|
|
struct wtap_pkthdr phdr; /* Packet header */
|
|
guint8 pd[WTAP_MAX_PACKET_SIZE]; /* Packet data */
|
|
|
|
g_return_if_fail(packet_list);
|
|
g_return_if_fail(PACKETLIST_IS_LIST(packet_list));
|
|
|
|
g_assert((record->col_text != NULL)&&(record->col_text_len != NULL));
|
|
|
|
/* XXX: Does it work to check if the record is already columnized/colorized ?
|
|
* i.e.: test record->columnized and record->colorized and just return
|
|
* if they're both TRUE.
|
|
* Note: Part of the patch submitted with Bug #4273 had code to do this but it
|
|
* was commented out in the patch and was not included in SVN #33011.
|
|
*/
|
|
fdata = record->fdata;
|
|
|
|
if (dissect_columns)
|
|
cinfo = &cfile.cinfo;
|
|
else
|
|
cinfo = NULL;
|
|
|
|
if (!cf_read_frame_r(&cfile, fdata, &phdr, pd)) {
|
|
/*
|
|
* Error reading the frame.
|
|
*
|
|
* Don't set the color filter for now (we might want
|
|
* to colorize it in some fashion to warn that the
|
|
* row couldn't be filled in or colorized), and
|
|
* set the columns to placeholder values, except
|
|
* for the Info column, where we'll put in an
|
|
* error message.
|
|
*/
|
|
if (dissect_columns) {
|
|
col_fill_in_error(cinfo, fdata, FALSE, FALSE /* fill_fd_columns */);
|
|
|
|
for(col = 0; col < cinfo->num_cols; ++col)
|
|
packet_list_change_record(packet_list, record, col, cinfo);
|
|
record->columnized = TRUE;
|
|
}
|
|
if (dissect_color) {
|
|
fdata->color_filter = NULL;
|
|
record->colorized = TRUE;
|
|
}
|
|
return; /* error reading the frame */
|
|
}
|
|
|
|
create_proto_tree = (dissect_color && color_filters_used()) ||
|
|
(dissect_columns && have_custom_cols(cinfo));
|
|
|
|
epan_dissect_init(&edt,
|
|
create_proto_tree,
|
|
FALSE /* proto_tree_visible */);
|
|
|
|
if (dissect_color)
|
|
color_filters_prime_edt(&edt);
|
|
if (dissect_columns)
|
|
col_custom_prime_edt(&edt, cinfo);
|
|
|
|
/*
|
|
* XXX - need to catch an OutOfMemoryError exception and
|
|
* attempt to recover from it.
|
|
*/
|
|
epan_dissect_run(&edt, &phdr, pd, fdata, cinfo);
|
|
|
|
if (dissect_color)
|
|
fdata->color_filter = color_filters_colorize_packet(&edt);
|
|
|
|
if (dissect_columns) {
|
|
/* "Stringify" non frame_data vals */
|
|
epan_dissect_fill_in_columns(&edt, FALSE, FALSE /* fill_fd_columns */);
|
|
|
|
for(col = 0; col < cinfo->num_cols; ++col)
|
|
packet_list_change_record(packet_list, record, col, cinfo);
|
|
}
|
|
|
|
if (dissect_columns)
|
|
record->columnized = TRUE;
|
|
if (dissect_color)
|
|
record->colorized = TRUE;
|
|
|
|
epan_dissect_cleanup(&edt);
|
|
}
|
|
|
|
void
|
|
packet_list_reset_colorized(PacketList *packet_list)
|
|
{
|
|
PacketListRecord *record;
|
|
guint i;
|
|
|
|
for(i = 0; i < PACKET_LIST_RECORD_COUNT(packet_list->physical_rows); ++i) {
|
|
record = PACKET_LIST_RECORD_GET(packet_list->physical_rows, i);
|
|
record->colorized = FALSE;
|
|
}
|
|
}
|
|
|
|
const char*
|
|
packet_list_get_widest_column_string(PacketList *packet_list, gint col)
|
|
{
|
|
int text_col;
|
|
|
|
g_return_val_if_fail(packet_list != NULL, NULL);
|
|
g_return_val_if_fail(PACKETLIST_IS_LIST(packet_list), NULL);
|
|
/* We need real column here, so not packet_list->n_cols+1 */
|
|
g_return_val_if_fail(col >= 0 && col < packet_list->n_cols, NULL);
|
|
|
|
if (PACKET_LIST_RECORD_COUNT(packet_list->visible_rows) == 0)
|
|
return "";
|
|
|
|
text_col = packet_list->col_to_text[col];
|
|
|
|
if (text_col == -1) { /* column based on frame data */
|
|
PacketListRecord *record;
|
|
guint vis_idx;
|
|
|
|
guint widest_packet = 0;
|
|
gint widest_column_len = -1;
|
|
|
|
for(vis_idx = 0; vis_idx < PACKET_LIST_RECORD_COUNT(packet_list->visible_rows); ++vis_idx) {
|
|
gint column_len;
|
|
|
|
record = PACKET_LIST_RECORD_GET(packet_list->visible_rows, vis_idx);
|
|
|
|
col_fill_in_frame_data(record->fdata, &cfile.cinfo, col, FALSE);
|
|
column_len = (gint) strlen(cfile.cinfo.col_buf[col]);
|
|
if (column_len > widest_column_len) {
|
|
widest_column_len = column_len;
|
|
widest_packet = vis_idx;
|
|
}
|
|
}
|
|
|
|
if (widest_column_len != -1) {
|
|
record = PACKET_LIST_RECORD_GET(packet_list->visible_rows, widest_packet);
|
|
col_fill_in_frame_data(record->fdata, &cfile.cinfo, col, FALSE);
|
|
|
|
return cfile.cinfo.col_buf[col];
|
|
} else
|
|
return "";
|
|
}
|
|
else {
|
|
PacketListRecord *record;
|
|
guint vis_idx;
|
|
|
|
const gchar *widest_column_str = NULL;
|
|
guint widest_column_len = 0;
|
|
|
|
if (!packet_list->columnized)
|
|
packet_list_dissect_and_cache_all(packet_list); /* XXX: need to handle case of "incomplete" ? */
|
|
|
|
for(vis_idx = 0; vis_idx < PACKET_LIST_RECORD_COUNT(packet_list->visible_rows); ++vis_idx) {
|
|
record = PACKET_LIST_RECORD_GET(packet_list->visible_rows, vis_idx);
|
|
if (record->col_text_len[text_col] > widest_column_len) {
|
|
widest_column_str = record->col_text[text_col];
|
|
widest_column_len = record->col_text_len[text_col];
|
|
}
|
|
}
|
|
|
|
return widest_column_str;
|
|
}
|
|
}
|