Huge thanks to our Platinum Members Endace and LiveAction,
and our Silver Member Veeam, for supporting the Wireshark Foundation and project.

Ethereal-dev: [Ethereal-dev] [patch] compare packets patch update

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: jcopenha <jcopenha@xxxxxxxxxxx>
Date: Sun, 12 Sep 2004 17:22:19 -0400
Here is an updated version of my compare packets patch.  I added in some
error checking, replaced all my ints and chars with g[int/char], and the
diff color is now saved in the preferences file.  It can be grabbed at
http://www.typedef.org/jcopenha/patches/ethereal/eth-compare-packets-svn-20040912.diff.

Jason


Index: menu.h
===================================================================
--- menu.h	(revision 11979)
+++ menu.h	(working copy)
@@ -60,6 +60,8 @@
    and and on whether a "Match Selected" can be done. */
 void set_menus_for_selected_tree_row(capture_file *cf);
 
+void set_menus_for_compare_packets(gboolean);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
Index: prefs.c
===================================================================
--- prefs.c	(revision 11979)
+++ prefs.c	(working copy)
@@ -1002,6 +1002,14 @@
     prefs.gui_marked_bg.red          =         0;
     prefs.gui_marked_bg.green        =         0;
     prefs.gui_marked_bg.blue         =         0;
+    prefs.gui_diff_fg.pixel          =         0;
+    prefs.gui_diff_fg.red            =         0;
+    prefs.gui_diff_fg.green          =         0;
+    prefs.gui_diff_fg.blue           =         0;
+    prefs.gui_diff_bg.pixel          =     65535;
+    prefs.gui_diff_bg.red            =     65535;
+    prefs.gui_diff_bg.green          =         0;
+    prefs.gui_diff_bg.blue           =         0;
     prefs.gui_geometry_save_position =         0;
     prefs.gui_geometry_save_size     =         1;
     prefs.gui_geometry_save_maximized=         1;
@@ -1309,6 +1317,8 @@
 #define PRS_GUI_FONT_NAME_2              "gui.gtk2.font_name"
 #define PRS_GUI_MARKED_FG                "gui.marked_frame.fg"
 #define PRS_GUI_MARKED_BG                "gui.marked_frame.bg"
+#define PRS_GUI_DIFF_FG                  "gui.diff.fg"
+#define PRS_GUI_DIFF_BG                  "gui.diff.bg"
 #define PRS_GUI_CONSOLE_OPEN             "gui.console_open"
 #define PRS_GUI_FILEOPEN_STYLE           "gui.fileopen.style"
 #define PRS_GUI_RECENT_COUNT_MAX         "gui.recent_files_count.max"
@@ -1599,6 +1609,18 @@
     prefs.gui_marked_bg.red   = RED_COMPONENT(cval);
     prefs.gui_marked_bg.green = GREEN_COMPONENT(cval);
     prefs.gui_marked_bg.blue  = BLUE_COMPONENT(cval);
+  } else if (strcmp(pref_name, PRS_GUI_DIFF_FG) == 0) {
+    cval = strtoul(value, NULL, 16);
+    prefs.gui_diff_fg.pixel = 0;
+    prefs.gui_diff_fg.red   = RED_COMPONENT(cval);
+    prefs.gui_diff_fg.green = GREEN_COMPONENT(cval);
+    prefs.gui_diff_fg.blue  = BLUE_COMPONENT(cval);
+  } else if (strcmp(pref_name, PRS_GUI_DIFF_BG) == 0) {
+    cval = strtoul(value, NULL, 16);
+    prefs.gui_diff_bg.pixel = 0;
+    prefs.gui_diff_bg.red   = RED_COMPONENT(cval);
+    prefs.gui_diff_bg.green = GREEN_COMPONENT(cval);
+    prefs.gui_diff_bg.blue  = BLUE_COMPONENT(cval);
   } else if (strcmp(pref_name, PRS_GUI_GEOMETRY_SAVE_POSITION) == 0) {
     if (strcasecmp(value, "true") == 0) {
 	    prefs.gui_geometry_save_position = TRUE;
@@ -2315,6 +2337,17 @@
     (prefs.st_server_bg.green * 255 / 65535),
     (prefs.st_server_bg.blue * 255 / 65535));
 
+  fprintf (pf, "\n# Color preferences for a diffed frame.\n");
+  fprintf (pf, "# Each value is a six digit hexadecimal color value in the form rrggbb.\n");
+  fprintf (pf, "%s: %02x%02x%02x\n", PRS_GUI_DIFF_FG,
+    (prefs.gui_diff_fg.red * 255 / 65535),
+    (prefs.gui_diff_fg.green * 255 / 65535),
+    (prefs.gui_diff_fg.blue * 255 / 65535));
+  fprintf (pf, "%s: %02x%02x%02x\n", PRS_GUI_DIFF_BG,
+    (prefs.gui_diff_bg.red * 255 / 65535),
+    (prefs.gui_diff_bg.green * 255 / 65535),
+    (prefs.gui_diff_bg.blue * 255 / 65535));
+
   fprintf(pf, "\n####### Capture ########\n");
   
   if (prefs.capture_device != NULL) {
Index: prefs.h
===================================================================
--- prefs.h	(revision 11979)
+++ prefs.h	(working copy)
@@ -121,6 +121,8 @@
   gchar   *gui_font_name2;
   color_t  gui_marked_fg;
   color_t  gui_marked_bg;
+  color_t  gui_diff_fg;
+  color_t  gui_diff_bg;
   gboolean gui_geometry_save_position;
   gboolean gui_geometry_save_size;
   gboolean gui_geometry_save_maximized;
Index: gtk/menu.c
===================================================================
--- gtk/menu.c	(revision 11979)
+++ gtk/menu.c	(working copy)
@@ -270,6 +270,8 @@
     ITEM_FACTORY_ENTRY("/View/<separator>", NULL, NULL, 0, "<Separator>", NULL),
     ITEM_FACTORY_ENTRY("/View/Show Packet in New _Window", NULL,
                        new_window_cb, 0, NULL, NULL),
+    ITEM_FACTORY_ENTRY("/View/Show Compare Packets In New Window", NULL,
+                       new_cmp_window_cb, 0, NULL, NULL),
     ITEM_FACTORY_STOCK_ENTRY("/View/_Reload", "<control>R", file_reload_cmd_cb,
                              0, GTK_STOCK_REFRESH),
     ITEM_FACTORY_ENTRY("/_Go", NULL, NULL, 0, "<Branch>", NULL),
@@ -416,6 +418,8 @@
     ITEM_FACTORY_ENTRY("/Print...", NULL, file_print_cmd_cb, 0, NULL, NULL),
     ITEM_FACTORY_ENTRY("/Show Packet in New Window", NULL, new_window_cb,
                        0, NULL, NULL),
+    ITEM_FACTORY_ENTRY("/Show Compare Packets In New Window", NULL, new_cmp_window_cb,
+                       0, NULL, NULL),
 };
 
 static GtkItemFactoryEntry tree_view_menu_items[] =
@@ -550,6 +554,7 @@
     set_menus_for_captured_packets(FALSE);
     set_menus_for_selected_packet(&cfile);
     set_menus_for_selected_tree_row(&cfile);
+    set_menus_for_compare_packets(FALSE);
 
     /* init with an empty recent files list */
     clear_menu_recent_capture_file_cmd_cb(NULL, NULL);
@@ -1470,6 +1475,13 @@
     return FALSE;
 }
 
+void
+set_menus_for_compare_packets(gboolean have_compare_packets)
+{
+  set_menu_sensitivity(main_menu_factory, "/View/Show Compare Packets In New Window", have_compare_packets);
+  set_menu_sensitivity(packet_list_menu_factory, "/Show Compare Packets In New Window", have_compare_packets);
+}
+
 /* Enable or disable menu items based on whether you have a capture file
    you've finished reading. */
 void
Index: gtk/packet_win.c
===================================================================
--- gtk/packet_win.c	(revision 11979)
+++ gtk/packet_win.c	(working copy)
@@ -74,6 +74,11 @@
 	epan_dissect_t	*edt;
 };
 
+struct PacketWinDataPtrs {
+	guint numPackets;
+	struct PacketWinData **Ptr;
+};
+
 /* List of all the packet-detail windows popped up. */
 static GList *detail_windows;
 
@@ -89,112 +94,234 @@
 
 #endif
 
-static void destroy_new_window(GtkObject *object, gpointer user_data);
+ static void destroy_new_window(GtkObject *object, gpointer user_data);
+  
+ static void new_multi_window(gint numPackets);
+ 
+ static gpointer
+ compare_packets(struct PacketWinDataPtrs DataPtrs, guint max_frame_size);
+ 
+ void proto_tree_node_set_diff(proto_node *node, gpointer diff);
+ 
+ void new_window_cb(GtkWidget *w _U_)
+ {
+ 	new_multi_window(0);
+ }
+ 
+ void new_cmp_window_cb(GtkWidget *w _U_)
+ {
+ 	new_multi_window(cfile.marked_count);
+ }
+ 
+ static
+ void new_multi_window(gint numPackets)
+ {
+       gint tv_size = 95, bv_size = 75;
+       GtkWidget *main_w = NULL, *main_hbox = NULL;
+       GtkWidget **vpane = NULL, **tree_view = NULL, **tv_scrollw = NULL, **bv_nb_ptr = NULL;
+       struct PacketWinData **DataPtr = NULL;
+       struct PacketWinDataPtrs *DataPtrs = NULL;
+       gint i, err, bCompare;
+       gchar* err_info;
+       frame_data *curframe = NULL;
+       frame_data *startframe = NULL;
+       guint max_frame_size = 0;
+       gint dead_pointer = 6; /* this value depends on how many widgets we allocate */
+       gpointer diff;
+ 
+       bCompare = 1;
+   
+       /* Handle the specail case when we aren't actually comparing packets */
+       if(numPackets == 0) {
+             numPackets = 1;
+             bCompare = 0;
+             curframe = cfile.current_frame;
+        }
+ 
+ 
+ 	/*
+  	 * try to keep all the g_free code in one place, we'll use a little fall through
+	 * trick in the switch statement
+	 */
+       vpane = (GtkWidget**)g_malloc(sizeof(GtkWidget*) * numPackets);
+       if(vpane == NULL) goto malloc_error;
+       dead_pointer--;
 
-void new_window_cb(GtkWidget *w _U_)
-{
-#define NewWinTitleLen 1000
-  char Title[NewWinTitleLen] = "";
-  char *TextPtr;
-  gint tv_size = 95, bv_size = 75;
-  GtkWidget *main_w, *main_vbox, *pane,
-                      *tree_view, *tv_scrollw,
-                      *bv_nb_ptr;
-  struct PacketWinData *DataPtr;
-  int i;
+       tree_view = (GtkWidget**)g_malloc(sizeof(GtkWidget*) * numPackets);
+       if(tree_view == NULL) goto malloc_error;
+       dead_pointer--;
 
-  /* Allocate data structure to represent this window. */
-  DataPtr = (struct PacketWinData *) g_malloc(sizeof(struct PacketWinData));
+       tv_scrollw = (GtkWidget**)g_malloc(sizeof(GtkWidget*) * numPackets);
+       if(tv_scrollw == NULL) goto malloc_error;
+       dead_pointer--;
 
-  DataPtr->frame = cfile.current_frame;
-  memcpy(&DataPtr->pseudo_header, &cfile.pseudo_header, sizeof DataPtr->pseudo_header);
-  DataPtr->pd = g_malloc(DataPtr->frame->cap_len);
-  memcpy(DataPtr->pd, cfile.pd, DataPtr->frame->cap_len);
-  DataPtr->edt = epan_dissect_new(TRUE, TRUE);
-  epan_dissect_run(DataPtr->edt, &DataPtr->pseudo_header, DataPtr->pd,
-          DataPtr->frame, &cfile.cinfo);
-  epan_dissect_fill_in_columns(DataPtr->edt);
+       bv_nb_ptr = (GtkWidget**)g_malloc(sizeof(GtkWidget*) * numPackets);
+       if(bv_nb_ptr == NULL) goto malloc_error;
+       dead_pointer--;
 
-  /*
-   * Build title of window by getting column data constructed when the
-   * frame was dissected.
-   */
-  for (i = 0; i < cfile.cinfo.num_cols; ++i) {
-    TextPtr = cfile.cinfo.col_data[i];
-    if ((strlen(Title) + strlen(TextPtr)) < NewWinTitleLen - 1) {
-      strcat(Title, TextPtr);
-      strcat(Title, " ");
-    }
-  }
+       DataPtr = (struct PacketWinData**)g_malloc(sizeof(struct PacketWinData*) * numPackets);
+       if(DataPtr == NULL) goto malloc_error;
+       dead_pointer--;
 
-  main_w = window_new(GTK_WINDOW_TOPLEVEL, Title);
-  gtk_window_set_default_size(GTK_WINDOW(main_w), DEF_WIDTH, -1);
+       DataPtrs	= (struct PacketWinDataPtrs*)g_malloc(sizeof(struct PacketWinDataPtrs));
+       if(DataPtrs == NULL) goto malloc_error;
+       dead_pointer--;
 
-  /* Container for paned windows  */
-  main_vbox = gtk_vbox_new(FALSE, 1);
-  gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
-  gtk_container_add(GTK_CONTAINER(main_w), main_vbox);
-  gtk_widget_show(main_vbox);
+malloc_error:
+       switch( dead_pointer) {
+       case 1 : g_free(DataPtr);
+       case 2 : g_free(bv_nb_ptr);
+       case 3 : g_free(tv_scrollw);
+       case 4 : g_free(tree_view);
+       case 5 : g_free(vpane);
+       case 6 :
+	 		fprintf(stderr,"Failed to allocate enough widgets for %d packet(s)\n",numPackets);
+			return;
+       		break;
+	default:
+		break;
+       };
+ 
+       startframe = cfile.plist;
+       for(i = 0; i < numPackets; i++) {
+             for(startframe; startframe != NULL && bCompare; startframe = startframe->next) {
+                   if (startframe->flags.marked) {
+                         curframe = startframe;
+                         startframe = startframe->next;
+                         break;
+                   }
+             }
+             if(curframe == NULL) {
+                   /* now what */
+                   fprintf(stderr, "curframe is NULL in new_multi_window\n");
+                   return;
+             }
+ 
+ 	      DataPtr[i] = (struct PacketWinData *)g_malloc(sizeof(struct PacketWinData));
+ 	      DataPtr[i]->frame = curframe;
+ 	      DataPtr[i]->pd = g_malloc(curframe->cap_len);
+ 	      if(curframe->cap_len > max_frame_size)
+ 	      	max_frame_size = curframe->cap_len;
+ 
+             /* should I care about err? no one else does */
+             wtap_seek_read(cfile.wth, curframe->file_off, &DataPtr[i]->pseudo_header, DataPtr[i]->pd, curframe->cap_len, &err, &err_info);
+ 
+ 	      DataPtr[i]->edt = epan_dissect_new(TRUE, TRUE);
+ 	      epan_dissect_run(DataPtr[i]->edt, &DataPtr[i]->pseudo_header, DataPtr[i]->pd,
+ 	                       DataPtr[i]->frame, NULL); /* umm.. &cfile.cinfo  what happens if NULL?*/
+              /* what is this.. why do we need it ? */
+ 	     /* epan_dissect_fill_in_columns(DataPtr[i]->edt);*/
+       }
+ 
+       main_w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ 
+       /* hmm.. what's a good title? */
+       gtk_window_set_title(GTK_WINDOW(main_w), "Compare Packets");
+       gtk_window_set_default_size(GTK_WINDOW(main_w), DEF_WIDTH, -1);
+ 
+       /* Container for paned windows  */
+       main_hbox = gtk_hbox_new(FALSE, 1);
+       gtk_container_border_width(GTK_CONTAINER(main_hbox), 1);
+       gtk_container_add(GTK_CONTAINER(main_w), main_hbox);
+       gtk_widget_show(main_hbox);
+ 
+       /* Panes for the tree and byte view */
+       for(i = 0; i < numPackets; i++) {
+             vpane[i] = gtk_vpaned_new();
+             gtk_paned_gutter_size(GTK_PANED(vpane[i]), (GTK_PANED(vpane[i]))->handle_size);
+             gtk_container_add(GTK_CONTAINER(main_hbox), vpane[i]);
+             gtk_widget_show(vpane[i]);
+ 
+             tv_scrollw[i] = main_tree_view_new(&prefs, &tree_view[i]);
+		 gtk_paned_pack1(GTK_PANED(vpane[i]), tv_scrollw[i], TRUE, TRUE);
+		 WIDGET_SET_SIZE(tv_scrollw[i], -1, tv_size);
+		 /*
+             create_tree_view(tv_size, &prefs, vpane[i], &tv_scrollw[i], &tree_view[i]);
+		 */
+		 gtk_widget_show(tv_scrollw[i]);
+             gtk_widget_show(tree_view[i]);
+ 
+             /*
+             bv_nb_ptr[i] = create_byte_view(bv_size, vpane[i]);
+		 */
+             bv_nb_ptr[i] = byte_view_new();
+		 gtk_paned_pack2(GTK_PANED(vpane[i]),bv_nb_ptr[i], FALSE, FALSE);
+		 WIDGET_SET_SIZE(bv_nb_ptr[i], -1, bv_size);
+		 gtk_widget_show(bv_nb_ptr[i]);
 
-  /* Panes for the tree and byte view */
-  pane = gtk_vpaned_new();
-  gtk_paned_gutter_size(GTK_PANED(pane), (GTK_PANED(pane))->handle_size);
-  gtk_container_add(GTK_CONTAINER(main_vbox), pane);
-  gtk_widget_show(pane);
+ 
+             DataPtr[i]->main = main_w;
+             DataPtr[i]->tv_scrollw = tv_scrollw[i];
+             DataPtr[i]->tree_view = tree_view[i];
+             DataPtr[i]->bv_nb_ptr = bv_nb_ptr[i];
+             detail_windows = g_list_append(detail_windows, DataPtr[i]);
+ 
+       }
+ 
+       DataPtrs->numPackets = numPackets;
+       DataPtrs->Ptr = (struct PacketWinData**)g_malloc(sizeof(struct PacketWinData*) * numPackets);
+       for(i = 0; i < numPackets; i++) {
+             DataPtrs->Ptr[i] = DataPtr[i];
+       }
+       diff = compare_packets(*DataPtrs,max_frame_size);
+ 
+ 
+       /* load callback handlers */
+       for(i = 0; i < numPackets; i++) {
+ #if GTK_MAJOR_VERSION < 2
+             SIGNAL_CONNECT(tree_view[i], "tree-select-row", new_tree_view_select_row_cb,
+                           DataPtr[i]);
+ 
+             SIGNAL_CONNECT(tree_view[i], "tree-unselect-row", new_tree_view_unselect_row_cb,
+                           DataPtr[i]);
+ #else
+             SIGNAL_CONNECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view[i])),
+                            "changed", new_tree_view_selection_changed_cb, DataPtr[i]);
+ #endif
+       }
+ 
+       /* this might need to be changed to pass pointers to both the left and right dataptr */
+       SIGNAL_CONNECT(main_w, "destroy", destroy_new_window, DataPtrs);
+ 
+       /* draw the protocol tree & print hex data */
+       for(i = 0; i < numPackets; i++) {
+             add_byte_views(DataPtr[i]->edt, tree_view[i], DataPtr[i]->bv_nb_ptr);
+ 
 
-  /* Tree view */
-  tv_scrollw = main_tree_view_new(&prefs, &tree_view);
-  gtk_paned_pack1(GTK_PANED(pane), tv_scrollw, TRUE, TRUE);
-  WIDGET_SET_SIZE(tv_scrollw, -1, tv_size);
-  gtk_widget_show(tv_scrollw);
-  gtk_widget_show(tree_view);
+             DataPtr[i]->edt->tree->tree_data->diff_mask = (guchar*)g_malloc(sizeof(guchar) * max_frame_size);
+		 memcpy(DataPtr[i]->edt->tree->tree_data->diff_mask,diff,max_frame_size);
+ 
+             proto_tree_children_foreach(DataPtr[i]->edt->tree, proto_tree_node_set_diff, diff);
+ 
+             proto_tree_draw(DataPtr[i]->edt->tree, tree_view[i]);
+ 
+             DataPtr[i]->finfo_selected = NULL;
+ 
+       }
+	 g_free(DataPtr);
+	 g_free(diff);
+ 
+       gtk_widget_show(main_w);
+ }	
 
-  /* Byte view */
-  bv_nb_ptr = byte_view_new();
-  gtk_paned_pack2(GTK_PANED(pane), bv_nb_ptr, FALSE, FALSE);
-  WIDGET_SET_SIZE(bv_nb_ptr, -1, bv_size);
-  gtk_widget_show(bv_nb_ptr);
+ static void
+ destroy_new_window(GtkObject *object _U_, gpointer user_data)
+ {
+       struct PacketWinDataPtrs *DataPtrs = user_data;
+       guint i;
 
-  DataPtr->main = main_w;
-  DataPtr->tv_scrollw = tv_scrollw;
-  DataPtr->tree_view = tree_view;
-  DataPtr->bv_nb_ptr = bv_nb_ptr;
-  detail_windows = g_list_append(detail_windows, DataPtr);
-
-  /* load callback handlers */
-#if GTK_MAJOR_VERSION < 2
-  SIGNAL_CONNECT(tree_view, "tree-select-row", new_tree_view_select_row_cb,
-                 DataPtr);
-
-  SIGNAL_CONNECT(tree_view, "tree-unselect-row", new_tree_view_unselect_row_cb,
-                 DataPtr);
-#else
-  SIGNAL_CONNECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)),
-                 "changed", new_tree_view_selection_changed_cb, DataPtr);
-#endif
-
-  SIGNAL_CONNECT(main_w, "destroy", destroy_new_window, DataPtr);
-
-  /* draw the protocol tree & print hex data */
-  add_byte_views(DataPtr->edt, tree_view, DataPtr->bv_nb_ptr);
-  proto_tree_draw(DataPtr->edt->tree, tree_view);
-
-  DataPtr->finfo_selected = NULL;
-  gtk_widget_show(main_w);
-}
-
-static void
-destroy_new_window(GtkObject *object _U_, gpointer user_data)
-{
-  struct PacketWinData *DataPtr = user_data;
-
-  detail_windows = g_list_remove(detail_windows, DataPtr);
-  epan_dissect_free(DataPtr->edt);
-  g_free(DataPtr->pd);
-  g_free(DataPtr);
-}
-
-#if GTK_MAJOR_VERSION < 2
+       for(i = 0; i < DataPtrs->numPackets; i++) {
+             detail_windows = g_list_remove(detail_windows, DataPtrs->Ptr[i]);
+             epan_dissect_free(DataPtrs->Ptr[i]->edt);
+             g_free(DataPtrs->Ptr[i]->pd);
+             g_free(DataPtrs->Ptr[i]);
+       }
+ 
+       g_free(DataPtrs->Ptr);
+       g_free(DataPtrs);
+  }
+  
+  #if GTK_MAJOR_VERSION < 2
 /* called when a tree row is selected in the popup packet window */
 static void
 new_tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column _U_,
@@ -331,3 +458,45 @@
 {
 	g_list_foreach(detail_windows, redraw_hex_dump_cb, NULL);
 }
+
+static gpointer
+compare_packets(struct PacketWinDataPtrs DataPtrs, guint max_frame_size) {
+
+	guint x,y;
+      guchar *diff;
+
+	/*
+	 * the caller of this function should be sure to delete this
+	 */
+	diff = (guchar*)g_malloc(sizeof(guchar) * max_frame_size);
+      memset(diff, 0, max_frame_size);
+
+	for(y = 0; y < max_frame_size; y++) {
+		for(x = 1; x < DataPtrs.numPackets; x++) {
+			if (((DataPtrs.Ptr[x-1]->frame->cap_len < y) || (DataPtrs.Ptr[x]->frame->cap_len < y)) ||
+				(DataPtrs.Ptr[x-1]->pd[y] != DataPtrs.Ptr[x]->pd[y]) ) {
+					diff[y] = 0xFF;
+				}
+		}
+	}
+
+	return (gpointer)diff;
+}
+
+void proto_tree_node_set_diff(proto_node *node, gpointer diff) {
+
+      guchar* p = (guchar*)diff;
+      gint x = 0;
+      field_info *finfo = PITEM_FINFO(node);
+
+      for(x = finfo->start; x < finfo->start + finfo->length; x++) {
+            if(p[x]) {
+                  finfo->diff = TRUE;
+                  break;
+             }
+      }
+
+      if(node->first_child)
+            proto_tree_children_foreach(node, proto_tree_node_set_diff, diff);
+}
+
Index: gtk/packet_win.h
===================================================================
--- gtk/packet_win.h	(revision 11979)
+++ gtk/packet_win.h	(working copy)
@@ -36,6 +36,7 @@
  * @param widget parent widget (unused)
  */
 extern void new_window_cb(GtkWidget *widget);
+extern void new_cmp_window_cb(GtkWidget *w);
 
 /** Redraw the hex dump panes of all packet windows. */
 void redraw_hex_dump_packet_wins(void);
Index: gtk/stream_prefs.c
===================================================================
--- gtk/stream_prefs.c	(revision 11979)
+++ gtk/stream_prefs.c	(working copy)
@@ -42,13 +42,16 @@
 #define SAMPLE_MARKED_TEXT "Sample marked packet text\n"
 #define SAMPLE_CLIENT_TEXT "Sample TCP stream client text\n"
 #define SAMPLE_SERVER_TEXT "Sample TCP stream server text\n"
+#define SAMPLE_DIFF_TEXT   "Sample diff text\n"
 #define MFG_IDX 0
 #define MBG_IDX 1
 #define CFG_IDX 2
 #define CBG_IDX 3
 #define SFG_IDX 4
 #define SBG_IDX 5
-#define MAX_IDX 6 /* set this to the number of IDX values */
+#define DFG_IDX 6
+#define DBG_IDX 7
+#define MAX_IDX 8 /* set this to the number of IDX values */
 #define STREAM_SAMPLE_KEY "stream_entry"
 #define STREAM_CS_KEY "stream_colorselection"
 #define CS_RED 0
@@ -69,7 +72,8 @@
   int        width, height, i;
   gchar     *mt[] = { "Marked packet foreground", "Marked packet background",
                       "TCP stream client foreground", "TCP stream client background",
-                      "TCP stream server foreground", "TCP stream server background" };
+                      "TCP stream server foreground", "TCP stream server background",
+			    "Diff foreground", "Diff background"};
   int mcount = sizeof(mt) / sizeof (gchar *);
 #if GTK_MAJOR_VERSION < 2
   gdouble scolor[4];
@@ -85,7 +89,10 @@
   color_t_to_gdkcolor(&tcolors[CBG_IDX], &prefs.st_client_bg);
   color_t_to_gdkcolor(&tcolors[SFG_IDX], &prefs.st_server_fg);
   color_t_to_gdkcolor(&tcolors[SBG_IDX], &prefs.st_server_bg);
+  color_t_to_gdkcolor(&tcolors[DFG_IDX], &prefs.gui_diff_fg);
+  color_t_to_gdkcolor(&tcolors[DBG_IDX], &prefs.gui_diff_bg);
 
+
   curcolor = &tcolors[CFG_IDX];
 
 #if GTK_MAJOR_VERSION < 2
@@ -138,6 +145,8 @@
                   SAMPLE_CLIENT_TEXT, -1);
   gtk_text_insert(GTK_TEXT(sample), NULL, &tcolors[SFG_IDX], &tcolors[SBG_IDX],
                   SAMPLE_SERVER_TEXT, -1);
+  gtk_text_insert(GTK_TEXT(sample), NULL, &tcolors[DFG_IDX], &tcolors[DBG_IDX],
+                  SAMPLE_DIFF_TEXT, -1);
 #else
   sample = gtk_text_view_new();
   layout = gtk_widget_create_pango_layout(sample, SAMPLE_SERVER_TEXT);
@@ -156,12 +165,17 @@
   gtk_text_buffer_create_tag(buf, "server",
                              "foreground-gdk", &tcolors[SFG_IDX],
                              "background-gdk", &tcolors[SBG_IDX], NULL);
+  gtk_text_buffer_create_tag(buf, "diff",
+                             "foreground-gdk", &tcolors[DFG_IDX],
+                             "background-gdk", &tcolors[DBG_IDX], NULL);
   gtk_text_buffer_insert_with_tags_by_name(buf, &iter, SAMPLE_MARKED_TEXT, -1,
                                            "marked", NULL);
   gtk_text_buffer_insert_with_tags_by_name(buf, &iter, SAMPLE_CLIENT_TEXT, -1,
                                            "client", NULL);
   gtk_text_buffer_insert_with_tags_by_name(buf, &iter, SAMPLE_SERVER_TEXT, -1,
                                            "server", NULL);
+  gtk_text_buffer_insert_with_tags_by_name(buf, &iter, SAMPLE_DIFF_TEXT, -1,
+                                           "diff", NULL);
 #endif
   gtk_table_attach_defaults(GTK_TABLE(main_tb), sample, 2, 3, 0, 2);
   gtk_widget_show(sample);
@@ -210,6 +224,8 @@
     SAMPLE_CLIENT_TEXT, -1);
   gtk_text_insert(sample, NULL, &tcolors[SFG_IDX], &tcolors[SBG_IDX],
     SAMPLE_SERVER_TEXT, -1);
+  gtk_text_insert(sample, NULL, &tcolors[DFG_IDX], &tcolors[DBG_IDX],
+    SAMPLE_DIFF_TEXT, -1);
   gtk_text_thaw(sample);
 #else
   gtk_color_selection_get_current_color(GTK_COLOR_SELECTION(w), curcolor);
@@ -224,6 +240,9 @@
   tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(buf), "server");
   g_object_set(tag, "foreground-gdk", &tcolors[SFG_IDX], "background-gdk",
                &tcolors[SBG_IDX], NULL);
+  tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(buf), "diff");
+  g_object_set(tag, "foreground-gdk", &tcolors[DFG_IDX], "background-gdk",
+               &tcolors[DBG_IDX], NULL);
 #endif
 }
 
@@ -259,6 +278,8 @@
   gdkcolor_to_color_t(&prefs.st_client_bg, &tcolors[CBG_IDX]);
   gdkcolor_to_color_t(&prefs.st_server_fg, &tcolors[SFG_IDX]);
   gdkcolor_to_color_t(&prefs.st_server_bg, &tcolors[SBG_IDX]);
+  gdkcolor_to_color_t(&prefs.gui_diff_fg, &tcolors[DFG_IDX]);
+  gdkcolor_to_color_t(&prefs.gui_diff_bg, &tcolors[DBG_IDX]);
 }
 
 void
Index: gtk/proto_draw.c
===================================================================
--- gtk/proto_draw.c	(revision 11979)
+++ gtk/proto_draw.c	(working copy)
@@ -1638,6 +1638,19 @@
         g_object_set (cell, "underline", PANGO_UNDERLINE_SINGLE, NULL);
         g_object_set (cell, "underline-set", TRUE, NULL);
     }
+
+    if(fi->diff) {
+    	GdkColor fg,bg;
+	color_t_to_gdkcolor(&fg,&prefs.gui_diff_fg);
+	color_t_to_gdkcolor(&bg,&prefs.gui_diff_bg);
+    	g_object_set (cell, "foreground-gdk", &fg, NULL);
+	g_object_set (cell, "foreground-set", TRUE, NULL);
+    	g_object_set (cell, "background-gdk", &bg, NULL);
+	g_object_set (cell, "background-set", TRUE, NULL);
+    } else {
+	g_object_set (cell, "foreground-set", FALSE, NULL);
+	g_object_set (cell, "background-set", FALSE, NULL);
+    }
 }
 #endif
 
Index: epan/proto.c
===================================================================
--- epan/proto.c	(revision 11979)
+++ epan/proto.c	(working copy)
@@ -417,6 +417,9 @@
         /* And then destroy the hash. */
         g_hash_table_destroy(tree_data->interesting_hfids);
 
+        /* and then the diff mask */
+        g_free(tree_data->diff_mask);
+
         /* And finally the tree_data_t itself. */
         g_free(tree_data);
 }
@@ -2080,6 +2083,7 @@
     }
 	fvalue_init(&fi->value, fi->hfinfo->type);
 	fi->rep = NULL;
+      fi->diff = FALSE;
 
 	/* add the data source tvbuff */
 	fi->ds_tvb=tvb?TVB_GET_DS_TVB(tvb):NULL;
@@ -2221,6 +2225,8 @@
 	 * changed, then we'll find out very quickly. */
 	pnode->tree_data->visible = FALSE;
 
+      pnode->tree_data->diff_mask = NULL;
+
 	return (proto_tree*) pnode;
 }
 
Index: epan/proto.h
===================================================================
--- epan/proto.h	(revision 11979)
+++ epan/proto.h	(working copy)
@@ -154,6 +154,7 @@
 	int					flags;      /**< one of FI_HIDDEN, ... */
 	tvbuff_t			*ds_tvb;    /**< data source tvbuff */
 	fvalue_t			value;
+      gboolean                diff;
 } field_info;
 
 
@@ -176,6 +177,7 @@
 typedef struct {
     GHashTable  *interesting_hfids;
     gboolean    visible;
+    char        *diff_mask;
 } tree_data_t;
 
 /** Each proto_tree, proto_item is one of these. */
Index: file.c
===================================================================
--- file.c	(revision 11979)
+++ file.c	(working copy)
@@ -2800,6 +2800,8 @@
     frame->flags.marked = TRUE;
     if (cf->count > cf->marked_count)
       cf->marked_count++;
+    if(cf->marked_count == 1)
+     set_menus_for_compare_packets(TRUE);
   }
 }
 
@@ -2813,6 +2815,8 @@
     frame->flags.marked = FALSE;
     if (cf->marked_count > 0)
       cf->marked_count--;
+    if(cf->marked_count == 0)
+     set_menus_for_compare_packets(FALSE);
   }
 }