Note in a comment that the display filter code has its own mechanism for
[obnox/wireshark/wip.git] / file.c
diff --git a/file.c b/file.c
index 7bb4d48694f41f5af94e3adb470fb1e6548f9b86..8f1cb1ba18c6fcdc1c5ec0213b2a869bd191f5c0 100644 (file)
--- a/file.c
+++ b/file.c
@@ -1,7 +1,7 @@
 /* file.c
  * File I/O routines
  *
- * $Id: file.c,v 1.243 2001/07/17 05:32:42 hagbard Exp $
+ * $Id: file.c,v 1.270 2002/04/24 05:48:43 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
 # include <netinet/in.h>
 #endif
 
-#include <epan.h>
+#include <epan/epan.h>
+#include <epan/filesystem.h>
 
 #include "gtk/main.h"
 #include "color.h"
 #include "gtk/color_utils.h"
 #include "column.h"
-#include "packet.h"
+#include <epan/packet.h>
 #include "print.h"
 #include "file.h"
 #include "menu.h"
 #include "prefs.h"
 #include "gtk/proto_draw.h"
 #include "gtk/packet_win.h"
-#include "dfilter/dfilter.h"
-#include "conversation.h"
-#include "reassemble.h"
+#include <epan/dfilter/dfilter.h>
+#include <epan/conversation.h>
 #include "globals.h"
 #include "gtk/colors.h"
+#include <epan/epan_dissect.h>
 
 extern GtkWidget *packet_list, *byte_nb_ptr, *tree_view;
 
+#ifdef HAVE_LIBPCAP
+gboolean auto_scroll_live;
+#endif
+
 static guint32 firstsec, firstusec;
 static guint32 prevsec, prevusec;
 
-static void read_packet(capture_file *cf, int offset);
+static void read_packet(capture_file *cf, long offset);
 
 static void rescan_packets(capture_file *cf, const char *action,
        gboolean refilter, gboolean redissect);
@@ -142,17 +147,8 @@ open_cap_file(char *fname, gboolean is_tempfile, capture_file *cf)
      and fill in the information for this file. */
   close_cap_file(cf);
 
-  /* Initialize the table of conversations. */
-  epan_conversation_init();
-
-  /* Initialize protocol-specific variables */
-  init_all_protocols();
-
-  /* Initialize the common data structures for fragment reassembly.
-     Must be done *after* "init_all_protocols()", as "init_all_protocols()"
-     may free up space for fragments, which it finds by using the
-     data structures that "reassemble_init()" frees. */
-  reassemble_init();
+  /* Initialize all data structures used for dissection. */
+  init_dissection();
 
   /* We're about to start reading the file. */
   cf->state = FILE_READ_IN_PROGRESS;
@@ -174,11 +170,18 @@ open_cap_file(char *fname, gboolean is_tempfile, capture_file *cf)
 
   cf->cd_t      = wtap_file_type(cf->wth);
   cf->count     = 0;
+  cf->marked_count = 0;
   cf->drops_known = FALSE;
   cf->drops     = 0;
   cf->esec      = 0;
   cf->eusec     = 0;
   cf->snap      = wtap_snapshot_length(cf->wth);
+  if (cf->snap == 0) {
+    /* Snapshot length not known. */
+    cf->has_snap = FALSE;
+    cf->snap = WTAP_MAX_PACKET_SIZE;
+  } else
+    cf->has_snap = TRUE;
   cf->progbar_quantum = 0;
   cf->progbar_nextstep = 0;
   firstsec = 0, firstusec = 0;
@@ -308,16 +311,18 @@ set_display_filename(capture_file *cf)
 read_status_t
 read_cap_file(capture_file *cf, int *err)
 {
-  gchar    *name_ptr, *load_msg, *load_fmt = " Loading: %s...";
-  size_t    msg_len;
-  char     *errmsg;
-  char      errmsg_errno[1024+1];
-  gchar     err_str[2048+1];
-  int       data_offset;
-  progdlg_t *progbar;
-  gboolean  stop_flag;
-  int       file_pos;
-  float     prog_val;
+  gchar      *name_ptr, *load_msg, *load_fmt = " Loading: %s...";
+  size_t      msg_len;
+  char       *errmsg;
+  char        errmsg_errno[1024+1];
+  gchar       err_str[2048+1];
+  long        data_offset;
+  progdlg_t  *progbar;
+  gboolean    stop_flag;
+  int         file_pos;
+  float       prog_val;
+  int         fd;
+  struct stat cf_stat;
 
   name_ptr = get_basename(cf->filename);
 
@@ -351,6 +356,21 @@ read_cap_file(capture_file *cf, int *err)
     if (data_offset >= cf->progbar_nextstep) {
         file_pos = lseek(cf->filed, 0, SEEK_CUR);
         prog_val = (gfloat) file_pos / (gfloat) cf->f_len;
+        if (prog_val > 1.0) {
+          /* The file probably grew while we were reading it.
+             Update "cf->f_len", and try again. */
+          fd = wtap_fd(cf->wth);
+          if (fstat(fd, &cf_stat) >= 0) {
+            cf->f_len = cf_stat.st_size;
+            prog_val = (gfloat) file_pos / (gfloat) cf->f_len;
+          }
+          /* If it's still > 1, either the "fstat()" failed (in which
+             case there's not much we can do about it), or the file
+             *shrank* (in which case there's not much we can do about
+             it); just clip the progress value at 1.0. */
+          if (prog_val > 1.0)
+            prog_val = 1.0;
+        }
         update_progress_dlg(progbar, prog_val);
         cf->progbar_nextstep += cf->progbar_quantum;
     }
@@ -377,6 +397,10 @@ read_cap_file(capture_file *cf, int *err)
   /* Close the sequential I/O side, to free up memory it requires. */
   wtap_sequential_close(cf->wth);
 
+  /* Allow the protocol dissectors to free up memory that they
+   * don't need after the sequential run-through of the packets. */
+  postseq_cleanup_all_protocols();
+
   /* Set the file encapsulation type now; we don't know what it is until
      we've looked at all the packets, as we don't know until then whether
      there's more than one type (and thus whether it's
@@ -476,7 +500,7 @@ start_tail_cap_file(char *fname, gboolean is_tempfile, capture_file *cf)
 read_status_t
 continue_tail_cap_file(capture_file *cf, int to_read, int *err)
 {
-  int data_offset = 0;
+  long data_offset = 0;
 
   gtk_clist_freeze(GTK_CLIST(packet_list));
 
@@ -495,7 +519,7 @@ continue_tail_cap_file(capture_file *cf, int to_read, int *err)
 
   /* XXX - this cheats and looks inside the packet list to find the final
      row number. */
-  if (prefs.capture_auto_scroll && cf->plist_end != NULL)
+  if (auto_scroll_live && cf->plist_end != NULL)
     gtk_clist_moveto(GTK_CLIST(packet_list), 
                       GTK_CLIST(packet_list)->rows - 1, -1, 1.0, 1.0);
 
@@ -517,7 +541,7 @@ continue_tail_cap_file(capture_file *cf, int to_read, int *err)
 read_status_t
 finish_tail_cap_file(capture_file *cf, int *err)
 {
-  int data_offset;
+  long data_offset;
 
   gtk_clist_freeze(GTK_CLIST(packet_list));
 
@@ -542,7 +566,7 @@ finish_tail_cap_file(capture_file *cf, int *err)
   }
 
   thaw_clist(cf);
-  if (prefs.capture_auto_scroll && cf->plist_end != NULL)
+  if (auto_scroll_live && cf->plist_end != NULL)
     /* XXX - this cheats and looks inside the packet list to find the final
        row number. */
     gtk_clist_moveto(GTK_CLIST(packet_list), 
@@ -555,6 +579,10 @@ finish_tail_cap_file(capture_file *cf, int *err)
      sequential I/O side, to free up memory it requires. */
   wtap_sequential_close(cf->wth);
 
+  /* Allow the protocol dissectors to free up memory that they
+   * don't need after the sequential run-through of the packets. */
+  postseq_cleanup_all_protocols();
+
   /* Set the file encapsulation type now; we don't know what it is until
      we've looked at all the packets, as we don't know until then whether
      there's more than one type (and thus whether it's
@@ -612,8 +640,8 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
        gboolean refilter)
 {
   apply_color_filter_args args;
-  gint          i, row;
-  proto_tree   *protocol_tree = NULL;
+  gint          row;
+  gboolean     create_proto_tree = FALSE;
   epan_dissect_t *edt;
   GdkColor      fg, bg;
 
@@ -628,12 +656,6 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
     firstusec = fdata->abs_usecs;
   }
 
-  fdata->cinfo = &cf->cinfo;
-  for (i = 0; i < fdata->cinfo->num_cols; i++) {
-    fdata->cinfo->col_buf[i][0] = '\0';
-    fdata->cinfo->col_data[i] = fdata->cinfo->col_buf[i];
-  }
-
   /* If either
 
        we have a display filter and are re-applying it;
@@ -644,10 +666,19 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
      a protocol tree against which a filter expression can be
      evaluated. */
   if ((cf->dfcode != NULL && refilter) || filter_list != NULL)
-    protocol_tree = proto_tree_create_root();
+         create_proto_tree = TRUE;
 
   /* Dissect the frame. */
-  edt = epan_dissect_new(pseudo_header, buf, fdata, protocol_tree);
+  edt = epan_dissect_new(create_proto_tree, FALSE);
+
+  if (cf->dfcode != NULL && refilter) {
+      epan_dissect_prime_dfilter(edt, cf->dfcode);
+  }
+  if (filter_list) {
+      filter_list_prime_edt(edt);
+  }
+  epan_dissect_run(edt, pseudo_header, buf, fdata, &cf->cinfo);
+
 
   /* If we have a display filter, apply it if we're refiltering, otherwise
      leave the "passed_dfilter" flag alone.
@@ -672,12 +703,6 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
     }
   }
 
-  /* There are no more filters to apply, so we don't need any protocol
-     tree; free it if we created it. */
-  if (protocol_tree != NULL)
-    proto_tree_free(protocol_tree);
-
-  epan_dissect_free(edt);
 
   if (fdata->flags.passed_dfilter) {
     /* This frame passed the display filter, so add it to the clist. */
@@ -698,8 +723,8 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
     /* If it's greater than the current elapsed time, set the elapsed time
        to it (we check for "greater than" so as not to be confused by
        time moving backwards). */
-    if (cf->esec < fdata->rel_secs
-       || (cf->esec == fdata->rel_secs && cf->eusec < fdata->rel_usecs)) {
+    if ((gint32)cf->esec < fdata->rel_secs
+       || ((gint32)cf->esec == fdata->rel_secs && (gint32)cf->eusec < fdata->rel_usecs)) {
       cf->esec = fdata->rel_secs;
       cf->eusec = fdata->rel_usecs;
     }
@@ -711,7 +736,7 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
     prevsec = fdata->abs_secs;
     prevusec = fdata->abs_usecs;
 
-    fill_in_columns(fdata);
+    epan_dissect_fill_in_columns(edt);
 
     /* If we haven't yet seen the first frame, this is it.
 
@@ -732,7 +757,7 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
     /* This is the last frame we've seen so far. */
     cf->last_displayed = fdata;
 
-    row = gtk_clist_append(GTK_CLIST(packet_list), fdata->cinfo->col_data);
+    row = gtk_clist_append(GTK_CLIST(packet_list), cf->cinfo.col_data);
     gtk_clist_set_row_data(GTK_CLIST(packet_list), row, fdata);
 
     if (fdata->flags.marked) {
@@ -752,19 +777,18 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
        to the clist, and thus has no row. */
     row = -1;
   }
-  fdata->cinfo = NULL;
+  epan_dissect_free(edt);
   return row;
 }
 
 static void
-read_packet(capture_file *cf, int offset)
+read_packet(capture_file *cf, long offset)
 {
   const struct wtap_pkthdr *phdr = wtap_phdr(cf->wth);
   union wtap_pseudo_header *pseudo_header = wtap_pseudoheader(cf->wth);
   const u_char *buf = wtap_buf_ptr(cf->wth);
   frame_data   *fdata;
   int           passed;
-  proto_tree   *protocol_tree;
   frame_data   *plist_end;
   epan_dissect_t *edt;
 
@@ -784,14 +808,13 @@ read_packet(capture_file *cf, int offset)
   fdata->flags.encoding = CHAR_ASCII;
   fdata->flags.visited = 0;
   fdata->flags.marked = 0;
-  fdata->cinfo = NULL;
 
   passed = TRUE;
   if (cf->rfcode) {
-    protocol_tree = proto_tree_create_root();
-    edt = epan_dissect_new(pseudo_header, buf, fdata, protocol_tree);
+    edt = epan_dissect_new(TRUE, FALSE);
+    epan_dissect_prime_dfilter(edt, cf->rfcode);
+    epan_dissect_run(edt, pseudo_header, buf, fdata, NULL);
     passed = dfilter_apply_edt(cf->rfcode, edt);
-    proto_tree_free(protocol_tree);
     epan_dissect_free(edt);
   }   
   if (passed) {
@@ -892,6 +915,7 @@ rescan_packets(capture_file *cf, const char *action, gboolean refilter,
   guint32 progbar_quantum;
   guint32 progbar_nextstep;
   unsigned int count;
+  int err;
   frame_data *selected_frame;
   int selected_row;
   int row;
@@ -912,17 +936,8 @@ rescan_packets(capture_file *cf, const char *action, gboolean refilter,
        which might cause the state information to be constructed differently
        by that dissector. */
 
-    /* Initialize the table of conversations. */
-    epan_conversation_init();
-
-    /* Initialize protocol-specific variables */
-    init_all_protocols();
-
-    /* Initialize the common data structures for fragment reassembly.
-       Must be done *after* "init_all_protocols()", as "init_all_protocols()"
-       may free up space for fragments, which it finds by using the
-       data structures that "reassemble_init()" frees. */
-    reassemble_init();
+    /* Initialize all data structures used for dissection. */
+    init_dissection();
   }
 
   /* Freeze the packet list while we redo it, so we don't get any
@@ -994,20 +1009,18 @@ rescan_packets(capture_file *cf, const char *action, gboolean refilter,
       /* Since all state for the frame was destroyed, mark the frame
        * as not visited, free the GSList referring to the state
        * data (the per-frame data itself was freed by
-       * "init_all_protocols()"), and null out the GSList pointer. */
+       * "init_dissection()"), and null out the GSList pointer. */
       fdata->flags.visited = 0;
       if (fdata->pfd) {
        g_slist_free(fdata->pfd);
+        fdata->pfd = NULL;
       }
-      fdata->pfd = NULL;
-      if (fdata->data_src) {   /* release data source list */
-       g_slist_free(fdata->data_src);
-      }
-      fdata->data_src = NULL;
+      free_data_sources(fdata);        /* release data source list */
     }
 
+    /* XXX - do something with "err" */
     wtap_seek_read (cf->wth, fdata->file_off, &cf->pseudo_header,
-       cf->pd, fdata->cap_len);
+       cf->pd, fdata->cap_len, &err);
 
     row = add_packet_to_packet_list(fdata, cf, &cf->pseudo_header, cf->pd,
                                        refilter);
@@ -1029,12 +1042,9 @@ rescan_packets(capture_file *cf, const char *action, gboolean refilter,
       fdata->flags.visited = 0;
       if (fdata->pfd) {
        g_slist_free(fdata->pfd);
+        fdata->pfd = NULL;
       }
-      fdata->pfd = NULL;
-      if (fdata->data_src) {
-       g_slist_free(fdata->data_src);
-      }
-      fdata->data_src = NULL;
+      free_data_sources(fdata);        /* release data source list */
     }
   }
 
@@ -1067,7 +1077,7 @@ print_packets(capture_file *cf, print_args_t *print_args)
   guint32     progbar_quantum;
   guint32     progbar_nextstep;
   guint32     count;
-  proto_tree *protocol_tree;
+  int         err;
   gint       *col_widths = NULL;
   gint        data_width;
   gboolean    print_separator;
@@ -1136,10 +1146,6 @@ print_packets(capture_file *cf, print_args_t *print_args)
 
   print_separator = FALSE;
 
-  /* The protocol tree will be "visible", i.e., printed, only if we're
-     not printing a summary. */
-  proto_tree_is_visible = !print_args->print_summary;
-
   /* Update the progress bar when it gets to this value. */
   progbar_nextstep = 0;
   /* When we reach the value that triggers a progress bar update,
@@ -1184,19 +1190,17 @@ print_packets(capture_file *cf, print_args_t *print_args)
     /* Check to see if we are suppressing unmarked packets, if so, 
      * suppress them and then proceed to check for visibility.
      */
-    if (((print_args->suppress_unmarked && fdata->flags.marked ) || !(print_args->suppress_unmarked)) && fdata->flags.passed_dfilter) {
+    if (((print_args->suppress_unmarked && fdata->flags.marked ) ||
+        !(print_args->suppress_unmarked)) && fdata->flags.passed_dfilter) {
+      /* XXX - do something with "err" */
       wtap_seek_read (cf->wth, fdata->file_off, &cf->pseudo_header,
-                       cf->pd, fdata->cap_len);
+                       cf->pd, fdata->cap_len, &err);
       if (print_args->print_summary) {
         /* Fill in the column information, but don't bother creating
            the logical protocol tree. */
-        fdata->cinfo = &cf->cinfo;
-        for (i = 0; i < fdata->cinfo->num_cols; i++) {
-          fdata->cinfo->col_buf[i][0] = '\0';
-          fdata->cinfo->col_data[i] = fdata->cinfo->col_buf[i];
-        }
-        edt = epan_dissect_new(&cf->pseudo_header, cf->pd, fdata, NULL);
-        fill_in_columns(fdata);
+        edt = epan_dissect_new(FALSE, FALSE);
+        epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, &cf->cinfo);
+        epan_dissect_fill_in_columns(edt);
         cp = &line_buf[0];
         line_len = 0;
         for (i = 0; i < cf->cinfo.num_cols; i++) {
@@ -1230,16 +1234,16 @@ print_packets(capture_file *cf, print_args_t *print_args)
         if (print_separator)
           print_line(cf->print_fh, print_args->format, "\n");
 
-        /* Create the logical protocol tree. */
-        protocol_tree = proto_tree_create_root();
-        edt = epan_dissect_new(&cf->pseudo_header, cf->pd, fdata, protocol_tree);
+        /* Create the logical protocol tree, complete with the display
+           representation of the items; we don't need the columns here,
+           however. */
+        edt = epan_dissect_new(TRUE, TRUE);
+        epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, NULL);
 
         /* Print the information in that tree. */
-        proto_tree_print(FALSE, print_args, (GNode *)protocol_tree,
+        proto_tree_print(print_args, (GNode *)edt->tree,
                        fdata, cf->print_fh);
 
-        proto_tree_free(protocol_tree);
-
        if (print_args->print_hex) {
          /* Print the full packet data as hex. */
          print_hex_data(cf->print_fh, print_args->format, fdata);
@@ -1266,8 +1270,6 @@ print_packets(capture_file *cf, print_args_t *print_args)
  
   cf->print_fh = NULL;
 
-  proto_tree_is_visible = FALSE;
-
   return TRUE;
 }
 
@@ -1287,6 +1289,18 @@ change_time_formats(capture_file *cf)
   int i;
   GtkStyle  *pl_style;
 
+  /* Are there any columns with time stamps in the "command-line-specified"
+     format?
+
+     XXX - we have to force the "column is writable" flag on, as it
+     might be off from the last frame that was dissected. */
+  col_set_writable(&cf->cinfo, TRUE);
+  if (!check_col(&cf->cinfo, COL_CLS_TIME)) {
+    /* No, there aren't any columns in that format, so we have no work
+       to do. */
+    return;
+  }
+
   /* Freeze the packet list while we redo it, so we don't get any
      screen updates while it happens. */
   freeze_clist(cf);
@@ -1340,23 +1354,14 @@ change_time_formats(capture_file *cf)
     if (row != -1) {
       /* This packet is in the summary list, on row "row". */
 
-      /* XXX - there really should be a way of checking "cf->cinfo" for this;
-         the answer isn't going to change from packet to packet, so we should
-         simply skip all the "change_time_formats()" work if we're not
-         changing anything. */
-      fdata->cinfo = &cf->cinfo;
-      if (check_col(fdata, COL_CLS_TIME)) {
-        /* There are columns that show the time in the "command-line-specified"
-           format; update them. */
-        for (i = 0; i < cf->cinfo.num_cols; i++) {
-          if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
-            /* This is one of the columns that shows the time in
-               "command-line-specified" format; update it. */
-            cf->cinfo.col_buf[i][0] = '\0';
-            col_set_cls_time(fdata, i);
-            gtk_clist_set_text(GTK_CLIST(packet_list), row, i,
-                         cf->cinfo.col_data[i]);
-         }
+      for (i = 0; i < cf->cinfo.num_cols; i++) {
+        if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
+          /* This is one of the columns that shows the time in
+             "command-line-specified" format; update it. */
+          cf->cinfo.col_buf[i][0] = '\0';
+          col_set_cls_time(fdata, &cf->cinfo, i);
+          gtk_clist_set_text(GTK_CLIST(packet_list), row, i,
+                            cf->cinfo.col_data[i]);
         }
       }
     }
@@ -1390,7 +1395,7 @@ find_packet(capture_file *cf, dfilter_t *sfcode)
   guint32 progbar_quantum;
   guint32 progbar_nextstep;
   unsigned int count;
-  proto_tree *protocol_tree;
+  int err;
   gboolean frame_matched;
   int row;
   epan_dissect_t       *edt;
@@ -1455,13 +1460,14 @@ find_packet(capture_file *cf, dfilter_t *sfcode)
       /* Is this packet in the display? */
       if (fdata->flags.passed_dfilter) {
         /* Yes.  Does it match the search filter? */
-        protocol_tree = proto_tree_create_root();
+        /* XXX - do something with "err" */
         wtap_seek_read(cf->wth, fdata->file_off, &cf->pseudo_header,
-                       cf->pd, fdata->cap_len);
-        edt = epan_dissect_new(&cf->pseudo_header, cf->pd, fdata, protocol_tree);
+                       cf->pd, fdata->cap_len, &err);
+        edt = epan_dissect_new(TRUE, FALSE);
+        epan_dissect_prime_dfilter(edt, sfcode);
+        epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, NULL);
         frame_matched = dfilter_apply_edt(sfcode, edt);
-        proto_tree_free(protocol_tree);
-       epan_dissect_free(edt);
+        epan_dissect_free(edt);
         if (frame_matched) {
           new_fd = fdata;
           break;       /* found it! */
@@ -1520,8 +1526,7 @@ void
 select_packet(capture_file *cf, int row)
 {
   frame_data *fdata;
-  tvbuff_t *bv_tvb;
-  int i;
+  int err;
 
   /* Get the frame data struct pointer for this frame */
   fdata = (frame_data *) gtk_clist_get_row_data(GTK_CLIST(packet_list), row);
@@ -1561,33 +1566,26 @@ select_packet(capture_file *cf, int row)
   cf->current_frame = fdata;
 
   /* Get the data in that frame. */
+  /* XXX - do something with "err" */
   wtap_seek_read (cf->wth, fdata->file_off, &cf->pseudo_header,
-                       cf->pd, fdata->cap_len);
+                       cf->pd, fdata->cap_len, &err);
 
   /* Create the logical protocol tree. */
-  if (cf->protocol_tree)
-      proto_tree_free(cf->protocol_tree);
-  cf->protocol_tree = proto_tree_create_root();
-  proto_tree_is_visible = TRUE;
   if (cf->edt != NULL) {
     epan_dissect_free(cf->edt);
     cf->edt = NULL;
   }
-  cf->edt = epan_dissect_new(&cf->pseudo_header, cf->pd, cf->current_frame,
-               cf->protocol_tree);
-  proto_tree_is_visible = FALSE;
-
-  /* Display the GUI protocol tree and hex dump. */
-  clear_tree_and_hex_views();
-
-  i = 0; 
-  while((bv_tvb = g_slist_nth_data ( cf->current_frame->data_src, i++))){
-       add_byte_view( tvb_get_name( bv_tvb), tvb_get_ptr(bv_tvb, 0, -1), tvb_length(bv_tvb));
-  }
-
-  proto_tree_draw(cf->protocol_tree, tree_view);
-
-  set_notebook_page( byte_nb_ptr, 0);
+  /* We don't need the columns here. */
+  cf->edt = epan_dissect_new(TRUE, TRUE);
+  epan_dissect_run(cf->edt, &cf->pseudo_header, cf->pd, cf->current_frame,
+          NULL);
+
+  /* Display the GUI protocol tree and hex dump.
+     XXX - why do we dump core if we call "proto_tree_draw()"
+     before calling "add_byte_views()"? */
+  add_byte_views(cf->current_frame, cf->edt->tree, tree_view,
+      byte_nb_ptr);
+  proto_tree_draw(cf->edt->tree, tree_view);
 
   /* A packet is selected. */
   set_menus_for_selected_packet(TRUE);
@@ -1597,11 +1595,7 @@ select_packet(capture_file *cf, int row)
 void
 unselect_packet(capture_file *cf)
 {
-  /* Destroy the protocol tree and epan_dissect_t for that packet. */
-  if (cf->protocol_tree != NULL) {
-    proto_tree_free(cf->protocol_tree);
-    cf->protocol_tree = NULL;
-  }
+  /* Destroy the epan_dissect_t for the unselected packet. */
   if (cf->edt != NULL) {
     epan_dissect_free(cf->edt);
     cf->edt = NULL;
@@ -1647,6 +1641,26 @@ unselect_field(void)
   set_menus_for_selected_tree_row(FALSE);
 }
 
+/*
+ * Mark a particular frame.
+ */
+void
+mark_frame(capture_file *cf, frame_data *frame)
+{
+  frame->flags.marked = TRUE;
+  cf->marked_count++;
+}
+
+/*
+ * Unmark a particular frame.
+ */
+void
+unmark_frame(capture_file *cf, frame_data *frame)
+{
+  frame->flags.marked = FALSE;
+  cf->marked_count--;
+}
+
 static void
 freeze_clist(capture_file *cf)
 {
@@ -1753,8 +1767,18 @@ save_cap_file(char *fname, capture_file *cf, gboolean save_filtered, gboolean sa
       do_copy = TRUE;
       from_filename = cf->filename;
     }
-    /* Copy the file, if we haven't moved it. */
+
+    /* Check that the from file is not the same as to file */
+
     if (do_copy) {
+
+            /* Copy the file, if we haven't moved it. */
+           if (strncmp(from_filename, fname, sizeof(cf->filename)) == 0) {
+                   simple_dialog(ESD_TYPE_WARN, NULL, 
+                                 "Can't save over current capture file: %s!", from_filename);
+                   goto done;
+           }
+
            if (!copy_binary_file(from_filename, fname)) {
                goto done;
            }
@@ -1794,8 +1818,13 @@ save_cap_file(char *fname, capture_file *cf, gboolean save_filtered, gboolean sa
         hdr.caplen = fdata->cap_len;
         hdr.len = fdata->pkt_len;
         hdr.pkt_encap = fdata->lnk_t;
-       wtap_seek_read(cf->wth, fdata->file_off, &pseudo_header,
-               pd, fdata->cap_len);
+       if (!wtap_seek_read(cf->wth, fdata->file_off, &pseudo_header,
+               pd, fdata->cap_len, &err)) {
+           simple_dialog(ESD_TYPE_CRIT, NULL,
+                               file_read_error_message(err), cf->filename);
+           wtap_dump_close(pdh, &err);
+           goto done;
+       }
 
         if (!wtap_dump(pdh, &hdr, &pseudo_header, pd, &err)) {
            simple_dialog(ESD_TYPE_CRIT, NULL,
@@ -1900,7 +1929,7 @@ file_open_error_message(int err, gboolean for_writing)
 
   case WTAP_ERR_SHORT_READ:
     errmsg = "The file \"%s\" appears to have been cut short"
-             " in the middle of a packet.";
+             " in the middle of a packet or other data.";
     break;
 
   case WTAP_ERR_SHORT_WRITE: