Fix a few minor memory leaks...
[obnox/wireshark/wip.git] / file.c
diff --git a/file.c b/file.c
index 7b328b4b57db4def419da37d204445250292448b..799130b6153cf6e918b8d746f2faa6de839a5aae 100644 (file)
--- a/file.c
+++ b/file.c
@@ -3,8 +3,8 @@
  *
  * $Id$
  *
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@ethereal.com>
+ * 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
 
 #include <time.h>
 
-#ifdef HAVE_IO_H
-#include <io.h>
-#endif
-
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 
 #include "color.h"
 #include "color_filters.h"
+#include "cfile.h"
 #include <epan/column.h>
 #include <epan/packet.h>
 #include "packet-range.h"
 #include "print.h"
 #include "file.h"
 #include "fileset.h"
-#include "util.h"
+#include "tempfile.h"
 #include "merge.h"
 #include "alert_box.h"
 #include "simple_dialog.h"
 #include <epan/conversation.h>
 #include <epan/epan_dissect.h>
 #include <epan/tap.h>
-#include "stat_menu.h"
-#include "tap_dfilter_dlg.h"
 #include <epan/dissectors/packet-data.h>
+#include <epan/dissectors/packet-ber.h>
 #include <epan/timestamp.h>
-
-
-/* Win32 needs the O_BINARY flag for open() */
-#ifndef O_BINARY
-#define O_BINARY       0
-#endif
+#include <epan/dfilter/dfilter-macro.h>
+#include <wsutil/file_util.h>
+#include <epan/column-utils.h>
+#include <epan/strutil.h>
 
 #ifdef HAVE_LIBPCAP
 gboolean auto_scroll_live;
 #endif
 
 static nstime_t first_ts;
-static nstime_t prev_ts;
+static nstime_t prev_dis_ts;
 static guint32 cum_bytes = 0;
 
 static void cf_reset_state(capture_file *cf);
 
-static void read_packet(capture_file *cf, long offset);
+static int read_packet(capture_file *cf, dfilter_t *dfcode, gint64 offset);
 
 static void rescan_packets(capture_file *cf, const char *action, const char *action_item,
        gboolean refilter, gboolean redissect);
@@ -134,34 +128,60 @@ static   gboolean copy_binary_file(const char *from_filename, const char *to_fil
 #define        FRAME_DATA_CHUNK_SIZE   1024
 
 
-/* one callback for now, we could have a list later */
-static cf_callback_t cf_cb = NULL;
-static gpointer cf_cb_user_data = NULL;
+/* this callback mechanism should possibly be replaced by the g_signal_...() stuff (if I only would know how :-) */
+typedef struct {
+    cf_callback_t cb_fct;
+    gpointer user_data;
+} cf_callback_data_t;
 
-void
+static GList *cf_callbacks = NULL;
+
+static void
 cf_callback_invoke(int event, gpointer data)
 {
-    g_assert(cf_cb != NULL);
-    cf_cb(event, data, cf_cb_user_data);
+    cf_callback_data_t *cb;
+    GList *cb_item = cf_callbacks;
+
+    /* there should be at least one interested */
+    g_assert(cb_item != NULL);
+
+    while(cb_item != NULL) {
+        cb = cb_item->data;
+        cb->cb_fct(event, data, cb->user_data);
+        cb_item = g_list_next(cb_item);
+    }
 }
 
 
 void
 cf_callback_add(cf_callback_t func, gpointer user_data)
 {
-    /* More than one callback listener is currently not implemented,
-       but should be easy to do. */
-    g_assert(cf_cb == NULL);
-    cf_cb = func;
-    cf_cb_user_data = user_data;
+    cf_callback_data_t *cb;
+
+    cb = g_malloc(sizeof(cf_callback_data_t));
+    cb->cb_fct = func;
+    cb->user_data = user_data;
+
+    cf_callbacks = g_list_append(cf_callbacks, cb);
 }
 
 void
-cf_callback_remove(cf_callback_t func _U_)
+cf_callback_remove(cf_callback_t func)
 {
-    g_assert(cf_cb != NULL);
-    cf_cb = NULL;
-    cf_cb_user_data = NULL;
+    cf_callback_data_t *cb;
+    GList *cb_item = cf_callbacks;
+
+    while(cb_item != NULL) {
+        cb = cb_item->data;
+        if(cb->cb_fct == func) {
+            cf_callbacks = g_list_remove(cf_callbacks, cb);
+            g_free(cb);
+            return;
+        }
+        cb_item = g_list_next(cb_item);
+    }
+
+    g_assert_not_reached();
 }
 
 void
@@ -258,8 +278,8 @@ cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
   } else
     cf->has_snap = TRUE;
   nstime_set_zero(&cf->elapsed_time);
-  nstime_set_zero(&first_ts);
-  nstime_set_zero(&prev_ts);
+  nstime_set_unset(&first_ts);
+  nstime_set_unset(&prev_dis_ts);
 
   cf->plist_chunk = g_mem_chunk_new("frame_data_chunk",
        sizeof(frame_data),
@@ -272,6 +292,11 @@ cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
 
   fileset_file_opened(fname);
 
+  if(cf->cd_t == WTAP_FILE_BER) {
+    /* tell the BER dissector the file name */
+    ber_set_filename(cf->filename);
+  }
+
   return CF_OK;
 
 fail:
@@ -301,7 +326,7 @@ cf_reset_state(capture_file *cf)
   if (cf->filename != NULL) {
     /* If it's a temporary file, remove it. */
     if (cf->is_tempfile)
-      unlink(cf->filename);
+      ws_unlink(cf->filename);
     g_free(cf->filename);
     cf->filename = NULL;
   }
@@ -324,6 +349,7 @@ cf_reset_state(capture_file *cf)
 
   /* No frame selected, no field in that frame selected. */
   cf->current_frame = NULL;
+  cf->current_row = 0;
   cf->finfo_selected = NULL;
 
   /* Clear the packet list. */
@@ -347,13 +373,29 @@ cf_reset_state(capture_file *cf)
 void
 cf_close(capture_file *cf)
 {
-  cf_reset_state(cf);
+  /* do GUI things even if file is already closed,
+   * e.g. to cleanup things if a capture couldn't be started */
+  cf_callback_invoke(cf_cb_file_closing, cf);
 
-  cleanup_dissection();
+  /* close things, if not already closed before */
+  if(cf->state != FILE_CLOSED) {
+
+         color_filters_cleanup();
+
+         cf_reset_state(cf);
+
+         cleanup_dissection();
+  }
 
   cf_callback_invoke(cf_cb_file_closed, cf);
 }
 
+/* an out of memory exception occured, wait for a user button press to exit */
+void outofmemory_cb(gpointer dialog _U_, gint btn _U_, gpointer data _U_)
+{
+    main_window_exit();
+}
+
 cf_read_status_t
 cf_read(capture_file *cf)
 {
@@ -362,21 +404,30 @@ cf_read(capture_file *cf)
   const gchar *name_ptr;
   const char  *errmsg;
   char         errmsg_errno[1024+1];
-  gchar        err_str[2048+1];
-  long         data_offset;
-  progdlg_t   *progbar = NULL;
+  gint64       data_offset;
+  progdlg_t *volatile progbar = NULL;
   gboolean     stop_flag;
-  gint64       size, file_pos;
-  float        prog_val;
+  volatile gint64 size;
+  gint64       file_pos;
+  volatile float progbar_val;
   GTimeVal     start_time;
   gchar        status_str[100];
-  gint64       progbar_nextstep;
-  gint64       progbar_quantum;
+  volatile gint64 progbar_nextstep;
+  volatile gint64 progbar_quantum;
+  dfilter_t   *dfcode;
+
+  /* Compile the current display filter.
+   * We assume this will not fail since cf->dfilter is only set in
+   * cf_filter IFF the filter was valid.
+   */
+  dfcode=NULL;
+  if(cf->dfilter){
+    dfilter_compile(cf->dfilter, &dfcode);
+  }
 
   cum_bytes=0;
 
   reset_tap_listeners();
-  tap_dfilter_dlg_update();
 
   cf_callback_invoke(cf_cb_file_read_start, cf);
 
@@ -389,10 +440,12 @@ cf_read(capture_file *cf)
   progbar_nextstep = 0;
   /* When we reach the value that triggers a progress bar update,
      bump that value by this amount. */
-  if (size >= 0)     
+  if (size >= 0)
     progbar_quantum = size/N_PROGBAR_UPDATES;
   else
     progbar_quantum = 0;
+  /* Progress so far. */
+  progbar_val = 0.0;
 
   packet_list_freeze();
 
@@ -401,6 +454,16 @@ cf_read(capture_file *cf)
 
   while ((wtap_read(cf->wth, &err, &err_info, &data_offset))) {
     if (size >= 0) {
+      /* 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) {
+        progbar = delayed_create_progress_dlg("Loading", name_ptr,
+          TRUE, &stop_flag, &start_time, progbar_val);
+      }
+
       /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
          when we update it, we have to run the GTK+ main loop to get it
          to repaint what's pending, and doing so may involve an "ioctl()"
@@ -408,46 +471,79 @@ cf_read(capture_file *cf)
          that for every packet can be costly, especially on a big file. */
       if (data_offset >= progbar_nextstep) {
           file_pos = wtap_read_so_far(cf->wth, NULL);
-          prog_val = (gfloat) file_pos / (gfloat) size;
-          if (prog_val > 1.0) {
+          progbar_val = (gfloat) file_pos / (gfloat) size;
+          if (progbar_val > 1.0) {
             /* The file probably grew while we were reading it.
                Update file size, and try again. */
             size = wtap_file_size(cf->wth, NULL);
             if (size >= 0)
-              prog_val = (gfloat) file_pos / (gfloat) size;
+              progbar_val = (gfloat) file_pos / (gfloat) size;
             /* If it's still > 1, either "wtap_file_size()" 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;
-          }
-          if (progbar == NULL) {
-            /* Create the progress bar if necessary */
-            progbar = delayed_create_progress_dlg("Loading", name_ptr,
-              &stop_flag, &start_time, prog_val);
+            if (progbar_val > 1.0)
+              progbar_val = 1.0;
           }
           if (progbar != NULL) {
+               /* update the packet lists content on the first run or frequently on very large files */
+              /* (on smaller files the display update takes longer than reading the file) */
+#ifdef HAVE_LIBPCAP
+              if(progbar_quantum > 500000 || progbar_nextstep == 0) {
+            packet_list_thaw();
+            if (auto_scroll_live && cf->plist_end != NULL)
+              packet_list_moveto_end();
+            packet_list_freeze();
+              }
+#endif
+
             g_snprintf(status_str, sizeof(status_str),
-                       "%" PRId64 "KB of %" PRId64 "KB",
+                       "%" G_GINT64_MODIFIER "dKB of %" G_GINT64_MODIFIER "dKB",
                        file_pos / 1024, size / 1024);
-            update_progress_dlg(progbar, prog_val, status_str);
+            update_progress_dlg(progbar, progbar_val, status_str);
           }
          progbar_nextstep += progbar_quantum;
       }
     }
 
     if (stop_flag) {
-      /* Well, the user decided to abort the read.  Destroy the progress
-         bar, close the capture file, and return CF_READ_ABORTED so our caller
-        can do whatever is appropriate when that happens. */
-      destroy_progress_dlg(progbar);
-      cf->state = FILE_READ_ABORTED;   /* so that we're allowed to close it */
-      packet_list_thaw();              /* undo our freeze */
-      cf_close(cf);
-      return CF_READ_ABORTED;
+      /* Well, the user decided to abort the read. He/She will be warned and
+         it might be enough for him/her to work with the already loaded
+         packets.
+         This is especially true for very large capture files, where you don't
+         want to wait loading the whole file (which may last minutes or even
+         hours even on fast machines) just to see that it was the wrong file. */
+      break;
+    }
+    TRY {
+        read_packet(cf, dfcode, data_offset);
+    }
+    CATCH(OutOfMemoryError) {
+        gpointer dialog;
+
+        dialog = simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+              "%sOut Of Memory!%s\n"
+              "\n"
+              "Sorry, but Wireshark has to terminate now!\n"
+              "\n"
+              "Some infos / workarounds can be found at:\n"
+              "http://wiki.wireshark.org/KnownBugs/OutOfMemory",
+              simple_dialog_primary_start(), simple_dialog_primary_end());
+        /* we have to terminate, as we cannot recover from the memory error */
+        simple_dialog_set_cb(dialog, outofmemory_cb, NULL);
+        while(1) {
+            main_window_update();
+            /* XXX - how to avoid a busy wait? */
+            /* Sleep(100); */
+        };
+        break;
     }
-    read_packet(cf, data_offset);
+    ENDTRY;
+  }
+
+  /* Cleanup and release all dfilter resources */
+  if (dfcode != NULL){
+    dfilter_free(dfcode);
   }
 
   /* We're done reading the file; destroy the progress bar if it was created. */
@@ -471,6 +567,8 @@ cf_read(capture_file *cf)
   cf->lnk_t = wtap_file_encap(cf->wth);
 
   cf->current_frame = cf->first_displayed;
+  cf->current_row = 0;
+
   packet_list_thaw();
 
   cf_callback_invoke(cf_cb_file_read_finished, cf);
@@ -480,6 +578,18 @@ cf_read(capture_file *cf)
   if (cf->first_displayed != NULL)
     packet_list_select_row(0);
 
+  if(stop_flag) {
+    simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
+          "%sFile loading was cancelled!%s\n"
+          "\n"
+                 "The remaining packets in the file were discarded.\n"
+          "\n"
+          "As a lot of packets from the original file will be missing,\n"
+                 "remember to be careful when saving the current content to a file.\n",
+          simple_dialog_primary_start(), simple_dialog_primary_end());
+    return CF_READ_ERROR;
+  }
+
   if (err != 0) {
     /* Put up a message box noting that the read failed somewhere along
        the line.  Don't throw out the stuff we managed to read, though,
@@ -488,7 +598,7 @@ cf_read(capture_file *cf)
 
     case WTAP_ERR_UNSUPPORTED_ENCAP:
       g_snprintf(errmsg_errno, sizeof(errmsg_errno),
-               "The capture file has a packet with a network type that Ethereal doesn't support.\n(%s)",
+               "The capture file has a packet with a network type that Wireshark doesn't support.\n(%s)",
                err_info);
       g_free(err_info);
       errmsg = errmsg_errno;
@@ -519,8 +629,7 @@ cf_read(capture_file *cf)
       errmsg = errmsg_errno;
       break;
     }
-    g_snprintf(err_str, sizeof err_str, errmsg);
-    simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, err_str);
+    simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", errmsg);
     return CF_READ_ERROR;
   } else
     return CF_READ_OK;
@@ -537,35 +646,91 @@ cf_start_tail(capture_file *cf, const char *fname, gboolean is_tempfile, int *er
 }
 
 cf_read_status_t
-cf_continue_tail(capture_file *cf, int to_read, int *err)
+cf_continue_tail(capture_file *cf, volatile int to_read, int *err)
 {
-  long data_offset = 0;
+  gint64 data_offset = 0;
   gchar *err_info;
+  volatile int newly_displayed_packets = 0;
+  dfilter_t   *dfcode;
+
+  /* Compile the current display filter.
+   * We assume this will not fail since cf->dfilter is only set in
+   * cf_filter IFF the filter was valid.
+   */
+  dfcode=NULL;
+  if(cf->dfilter){
+    dfilter_compile(cf->dfilter, &dfcode);
+  }
 
   *err = 0;
 
+  packet_list_check_end();
   packet_list_freeze();
 
+  /*g_log(NULL, G_LOG_LEVEL_MESSAGE, "cf_continue_tail: %u new: %u", cf->count, to_read);*/
+
   while (to_read != 0 && (wtap_read(cf->wth, err, &err_info, &data_offset))) {
     if (cf->state == FILE_READ_ABORTED) {
-      /* Well, the user decided to exit Ethereal.  Break out of the
+      /* Well, the user decided to exit Wireshark.  Break out of the
          loop, and let the code below (which is called even if there
         aren't any packets left to read) exit. */
       break;
     }
-    read_packet(cf, data_offset);
+    TRY{
+        if (read_packet(cf, dfcode, data_offset) != -1) {
+            newly_displayed_packets++;
+        }
+    }
+    CATCH(OutOfMemoryError) {
+        gpointer dialog;
+
+        dialog = simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+              "%sOut Of Memory!%s\n"
+              "\n"
+              "Sorry, but Wireshark has to terminate now!\n"
+              "\n"
+              "The capture file is not lost, it can be found at:\n"
+              "%s\n"
+              "\n"
+              "Some infos / workarounds can be found at:\n"
+              "http://wiki.wireshark.org/KnownBugs/OutOfMemory",
+              simple_dialog_primary_start(), simple_dialog_primary_end(), cf->filename);
+        /* we have to terminate, as we cannot recover from the memory error */
+        simple_dialog_set_cb(dialog, outofmemory_cb, NULL);
+        while(1) {
+            main_window_update();
+            /* XXX - how to avoid a busy wait? */
+            /* Sleep(100); */
+        };
+        packet_list_thaw();
+        return CF_READ_ABORTED;
+    }
+    ENDTRY;
     to_read--;
   }
 
+  /* Cleanup and release all dfilter resources */
+  if (dfcode != NULL){
+    dfilter_free(dfcode);
+  }
+
+  /*g_log(NULL, G_LOG_LEVEL_MESSAGE, "cf_continue_tail: count %u state: %u err: %u",
+         cf->count, cf->state, *err);*/
+
+  /* XXX - this causes "flickering" of the list */
   packet_list_thaw();
 
+  /* moving to the end of the packet list - if the user requested so and
+     we have some new packets.
+     this doesn't seem to work well with a frozen GTK_Clist, so do this after
+     packet_list_thaw() is done, see bugzilla 1188 */
   /* XXX - this cheats and looks inside the packet list to find the final
      row number. */
-  if (auto_scroll_live && cf->plist_end != NULL)
+  if (newly_displayed_packets && auto_scroll_live && cf->plist_end != NULL)
     packet_list_moveto_end();
 
   if (cf->state == FILE_READ_ABORTED) {
-    /* Well, the user decided to exit Ethereal.  Return CF_READ_ABORTED
+    /* Well, the user decided to exit Wireshark.  Return CF_READ_ABORTED
        so that our caller can kill off the capture child process;
        this will cause an EOF on the pipe from the child, so
        "cf_finish_tail()" will be called, and it will clean up
@@ -573,7 +738,10 @@ cf_continue_tail(capture_file *cf, int to_read, int *err)
     return CF_READ_ABORTED;
   } else if (*err != 0) {
     /* We got an error reading the capture file.
-       XXX - pop up a dialog box? */
+       XXX - pop up a dialog box instead? */
+       g_warning("Error \"%s\" while reading: \"%s\"\n",
+               wtap_strerror(*err), cf->filename);
+
     return CF_READ_ERROR;
   } else
     return CF_READ_OK;
@@ -583,13 +751,24 @@ cf_read_status_t
 cf_finish_tail(capture_file *cf, int *err)
 {
   gchar *err_info;
-  long data_offset;
+  gint64 data_offset;
+  dfilter_t   *dfcode;
+
+  /* Compile the current display filter.
+   * We assume this will not fail since cf->dfilter is only set in
+   * cf_filter IFF the filter was valid.
+   */
+  dfcode=NULL;
+  if(cf->dfilter){
+    dfilter_compile(cf->dfilter, &dfcode);
+  }
 
   if(cf->wth == NULL) {
     cf_close(cf);
     return CF_READ_ERROR;
   }
 
+  packet_list_check_end();
   packet_list_freeze();
 
   while ((wtap_read(cf->wth, err, &err_info, &data_offset))) {
@@ -599,9 +778,16 @@ cf_finish_tail(capture_file *cf, int *err)
         aren't any packets left to read) exit. */
       break;
     }
-    read_packet(cf, data_offset);
+        read_packet(cf, dfcode, data_offset);
   }
 
+  /* Cleanup and release all dfilter resources */
+  if (dfcode != NULL){
+    dfilter_free(dfcode);
+  }
+
+  packet_list_thaw();
+
   if (cf->state == FILE_READ_ABORTED) {
     /* Well, the user decided to abort the read.  We're only called
        when the child capture process closes the pipe to us (meaning
@@ -612,7 +798,6 @@ cf_finish_tail(capture_file *cf, int *err)
     return CF_READ_ABORTED;
   }
 
-  packet_list_thaw();
   if (auto_scroll_live && cf->plist_end != NULL)
     /* XXX - this cheats and looks inside the packet list to find the final
        row number. */
@@ -668,11 +853,18 @@ cf_get_display_name(capture_file *cf)
 
 /* XXX - use a macro instead? */
 int
-cf_packet_count(capture_file *cf)
+cf_get_packet_count(capture_file *cf)
 {
     return cf->count;
 }
 
+/* XXX - use a macro instead? */
+void
+cf_set_packet_count(capture_file *cf, int packet_count)
+{
+    cf->count = packet_count;
+}
+
 /* XXX - use a macro instead? */
 gboolean
 cf_is_tempfile(capture_file *cf)
@@ -717,6 +909,7 @@ void cf_set_rfcode(capture_file *cf, dfilter_t *rfcode)
 
 static int
 add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
+       dfilter_t *dfcode,
        union wtap_pseudo_header *pseudo_header, const guchar *buf,
        gboolean refilter)
 {
@@ -730,7 +923,7 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
   /* If we don't have the time stamp of the first packet in the
      capture, it's because this is the first packet.  Save the time
      stamp of this packet as the time stamp of the first packet. */
-  if (nstime_is_zero(&first_ts)) {
+  if (nstime_is_unset(&first_ts)) {
     first_ts  = fdata->abs_ts;
   }
   /* if this frames is marked as a reference time frame, reset
@@ -743,8 +936,8 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
      it's because this is the first displayed packet.  Save the time
      stamp of this packet as the time stamp of the previous displayed
      packet. */
-  if (nstime_is_zero(&prev_ts)) {
-    prev_ts = fdata->abs_ts;
+  if (nstime_is_unset(&prev_dis_ts)) {
+    prev_dis_ts = fdata->abs_ts;
   }
 
   /* Get the time elapsed between the first packet and this packet. */
@@ -760,7 +953,7 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
 
   /* Get the time elapsed between the previous displayed packet and
      this packet. */
-  nstime_delta(&fdata->del_ts, &fdata->abs_ts, &prev_ts);
+  nstime_delta(&fdata->del_dis_ts, &fdata->abs_ts, &prev_dis_ts);
 
   /* If either
 
@@ -770,22 +963,28 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
 
        we have tap listeners;
 
+       we have custom columns;
+
      allocate a protocol tree root node, so that we'll construct
      a protocol tree against which a filter expression can be
      evaluated. */
-  if ((cf->dfcode != NULL && refilter) || color_filters_used()
-        || num_tap_filters != 0)
+  if ((dfcode != NULL && refilter) || color_filters_used()
+      || num_tap_filters != 0 || have_custom_cols(&cf->cinfo))
          create_proto_tree = TRUE;
 
   /* Dissect the frame. */
   edt = epan_dissect_new(create_proto_tree, FALSE);
 
-  if (cf->dfcode != NULL && refilter) {
-      epan_dissect_prime_dfilter(edt, cf->dfcode);
+  if (dfcode != NULL && refilter) {
+      epan_dissect_prime_dfilter(edt, dfcode);
   }
+  /* prepare color filters */
   if (color_filters_used()) {
       color_filters_prime_edt(edt);
   }
+
+  col_custom_prime_edt(edt, &cf->cinfo);
+
   tap_queue_init(edt);
   epan_dissect_run(edt, pseudo_header, buf, fdata, &cf->cinfo);
   tap_push_tapped_queue(edt);
@@ -794,27 +993,27 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
      leave the "passed_dfilter" flag alone.
 
      If we don't have a display filter, set "passed_dfilter" to 1. */
-  if (cf->dfcode != NULL) {
+  if (dfcode != NULL) {
     if (refilter) {
-      fdata->flags.passed_dfilter = dfilter_apply_edt(cf->dfcode, edt) ? 1 : 0;
+      fdata->flags.passed_dfilter = dfilter_apply_edt(dfcode, edt) ? 1 : 0;
     }
   } else
     fdata->flags.passed_dfilter = 1;
 
-  if( (fdata->flags.passed_dfilter) 
+  if( (fdata->flags.passed_dfilter)
    || (edt->pi.fd->flags.ref_time) ){
     /* This frame either passed the display filter list or is marked as
        a time reference frame.  All time reference frames are displayed
        even if they dont pass the display filter */
-    /* if this was a TIME REF frame we should reset the cul bytes field */
     if(edt->pi.fd->flags.ref_time){
+      /* if this was a TIME REF frame we should reset the cul bytes field */
       cum_bytes = fdata->pkt_len;
-      fdata->cum_bytes  = cum_bytes;
+      fdata->cum_bytes =  cum_bytes;
+    } else {
+      /* increase cum_bytes with this packets length */
+      cum_bytes += fdata->pkt_len;
     }
 
-    /* increase cum_bytes with this packets length */
-    cum_bytes += fdata->pkt_len;
-
     epan_dissect_fill_in_columns(edt);
 
     /* If we haven't yet seen the first frame, this is it.
@@ -836,20 +1035,24 @@ 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;
 
+    fdata->col_expr.col_expr = cf->cinfo.col_expr.col_expr;
+    fdata->col_expr.col_expr_val = cf->cinfo.col_expr.col_expr_val;
+
     row = packet_list_append(cf->cinfo.col_data, fdata);
 
-    /* colorize packet: if packet is marked, use preferences, 
-       otherwise try to apply color filters */
+    /* colorize packet: first apply color filters
+     * then if packet is marked, use preferences to overwrite color
+     * we do both to make sure that when a packet gets un-marked, the
+     * color will be correctly set (fixes bug 2038)
+     */
+      fdata->color_filter = color_filters_colorize_packet(row, edt);
       if (fdata->flags.marked) {
-          fdata->color_filter = NULL;
           packet_list_set_colors(row, &prefs.gui_marked_fg, &prefs.gui_marked_bg);
-      } else {
-          fdata->color_filter = color_filters_colorize_packet(row, edt);
       }
 
     /* Set the time of the previous displayed frame to the time of this
        frame. */
-    prev_ts = fdata->abs_ts;
+    prev_dis_ts = fdata->abs_ts;
 
     cf->displayed_count++;
   } else {
@@ -861,8 +1064,10 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
   return row;
 }
 
-static void
-read_packet(capture_file *cf, long offset)
+/* read in a new packet */
+/* returns the row of the new packet in the packet list or -1 if not displayed */
+static int
+read_packet(capture_file *cf, dfilter_t *dfcode, gint64 offset)
 {
   const struct wtap_pkthdr *phdr = wtap_phdr(cf->wth);
   union wtap_pseudo_header *pseudo_header = wtap_pseudoheader(cf->wth);
@@ -871,10 +1076,12 @@ read_packet(capture_file *cf, long offset)
   int           passed;
   frame_data   *plist_end;
   epan_dissect_t *edt;
+  int row = -1;
 
   /* Allocate the next list entry, and add it to the list. */
   fdata = g_mem_chunk_alloc(cf->plist_chunk);
 
+  fdata->num = 0;
   fdata->next = NULL;
   fdata->prev = NULL;
   fdata->pfd  = NULL;
@@ -886,8 +1093,15 @@ read_packet(capture_file *cf, long offset)
   fdata->flags.visited = 0;
   fdata->flags.marked = 0;
   fdata->flags.ref_time = 0;
+  fdata->color_filter = NULL;
 
-  fdata->abs_ts  = *((nstime_t *) &phdr->ts);
+  fdata->abs_ts.secs = phdr->ts.secs;
+  fdata->abs_ts.nsecs = phdr->ts.nsecs;
+
+  if (cf->plist_end != NULL)
+    nstime_delta(&fdata->del_cap_ts, &fdata->abs_ts, &cf->plist_end->abs_ts);
+  else
+    nstime_set_zero(&fdata->del_cap_ts);
 
   passed = TRUE;
   if (cf->rfcode) {
@@ -909,7 +1123,9 @@ read_packet(capture_file *cf, long offset)
     cf->count++;
     cf->f_datalen = offset + phdr->caplen;
     fdata->num = cf->count;
-    add_packet_to_packet_list(fdata, cf, pseudo_header, buf, TRUE);
+    if (!cf->redissecting) {
+      row = add_packet_to_packet_list(fdata, cf, dfcode, pseudo_header, buf, TRUE);
+    }
   } else {
     /* XXX - if we didn't have read filters, or if we could avoid
        allocating the "frame_data" structure until we knew whether
@@ -921,6 +1137,8 @@ read_packet(capture_file *cf, long offset)
        seem to save a noticeable amount of time or space. */
     g_mem_chunk_free(cf->plist_chunk, fdata);
   }
+
+  return row;
 }
 
 cf_status_t
@@ -935,17 +1153,16 @@ cf_merge_files(char **out_filenamep, int in_file_count,
   wtap_dumper      *pdh;
   int               open_err, read_err, write_err, close_err;
   gchar            *err_info;
-  int               err_fileno; 
+  int               err_fileno;
   int               i;
   char              errmsg_errno[1024+1];
-  gchar             err_str[2048+1];
   const char       *errmsg;
   gboolean          got_read_error = FALSE, got_write_error = FALSE;
-  long              data_offset;
+  gint64            data_offset;
   progdlg_t        *progbar = NULL;
   gboolean          stop_flag;
   gint64            f_len, file_pos;
-  float             prog_val;
+  float             progbar_val;
   GTimeVal          start_time;
   gchar             status_str[100];
   gint64            progbar_nextstep;
@@ -954,7 +1171,7 @@ cf_merge_files(char **out_filenamep, int in_file_count,
   /* open the input files */
   if (!merge_open_in_files(in_file_count, in_filenames, &in_files,
                            &open_err, &err_info, &err_fileno)) {
-    free(in_files);
+    g_free(in_files);
     cf_open_failure_alert_box(in_filenames[err_fileno], open_err, err_info,
                               FALSE, 0);
     return CF_ERROR;
@@ -962,7 +1179,7 @@ cf_merge_files(char **out_filenamep, int in_file_count,
 
   if (*out_filenamep != NULL) {
     out_filename = *out_filenamep;
-    out_fd = open(out_filename, O_CREAT|O_TRUNC|O_BINARY, 0600);
+    out_fd = ws_open(out_filename, O_CREAT|O_TRUNC|O_BINARY, 0600);
     if (out_fd == -1)
       open_err = errno;
   } else {
@@ -975,18 +1192,19 @@ cf_merge_files(char **out_filenamep, int in_file_count,
   if (out_fd == -1) {
     err_info = NULL;
     merge_close_in_files(in_file_count, in_files);
-    free(in_files);
+    g_free(in_files);
     cf_open_failure_alert_box(out_filename, open_err, NULL, TRUE, file_type);
     return CF_ERROR;
   }
 
   pdh = wtap_dump_fdopen(out_fd, file_type,
       merge_select_frame_type(in_file_count, in_files),
-      merge_max_snapshot_length(in_file_count, in_files), &open_err);
+      merge_max_snapshot_length(in_file_count, in_files),
+         FALSE /* compressed */, &open_err);
   if (pdh == NULL) {
-    close(out_fd);
+    ws_close(out_fd);
     merge_close_in_files(in_file_count, in_files);
-    free(in_files);
+    g_free(in_files);
     cf_open_failure_alert_box(out_filename, open_err, err_info, TRUE,
                               file_type);
     return CF_ERROR;
@@ -1002,6 +1220,8 @@ cf_merge_files(char **out_filenamep, int in_file_count,
   /* When we reach the value that triggers a progress bar update,
      bump that value by this amount. */
   progbar_quantum = f_len/N_PROGBAR_UPDATES;
+  /* Progress so far. */
+  progbar_val = 0.0;
 
   stop_flag = FALSE;
   g_get_current_time(&start_time);
@@ -1025,32 +1245,47 @@ cf_merge_files(char **out_filenamep, int in_file_count,
     for (i = 0; i < in_file_count; i++)
       data_offset += in_files[i].data_offset;
 
+    /* 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) {
+      progbar = delayed_create_progress_dlg("Merging", "files",
+        FALSE, &stop_flag, &start_time, progbar_val);
+    }
+
+    /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
+       when we update it, we have to run the GTK+ main loop to get it
+       to repaint what's pending, and doing so may involve an "ioctl()"
+       to see if there's any pending input from an X server, and doing
+       that for every packet can be costly, especially on a big file. */
     if (data_offset >= progbar_nextstep) {
         /* Get the sum of the seek positions in all of the files. */
         file_pos = 0;
         for (i = 0; i < in_file_count; i++)
           file_pos += wtap_read_so_far(in_files[i].wth, NULL);
-        prog_val = (gfloat) file_pos / (gfloat) f_len;
-        if (prog_val > 1.0) {
+        progbar_val = (gfloat) file_pos / (gfloat) f_len;
+        if (progbar_val > 1.0) {
           /* Some file probably grew while we were reading it.
              That "shouldn't happen", so we'll just clip the progress
              value at 1.0. */
-          prog_val = 1.0;
-        }
-        if (progbar == NULL) {
-          /* Create the progress bar if necessary */
-          progbar = delayed_create_progress_dlg("Merging", "files",
-            &stop_flag, &start_time, prog_val);
+          progbar_val = 1.0;
         }
         if (progbar != NULL) {
           g_snprintf(status_str, sizeof(status_str),
-                     "%" PRId64 "KB of %" PRId64 "KB",
+                     "%" G_GINT64_MODIFIER "dKB of %" G_GINT64_MODIFIER "dKB",
                      file_pos / 1024, f_len / 1024);
-          update_progress_dlg(progbar, prog_val, status_str);
+          update_progress_dlg(progbar, progbar_val, status_str);
         }
         progbar_nextstep += progbar_quantum;
     }
 
+    if (stop_flag) {
+      /* Well, the user decided to abort the merge. */
+      break;
+    }
+
     if (!wtap_dump(pdh, wtap_phdr(wth), wtap_pseudoheader(wth),
          wtap_buf_ptr(wth), &write_err)) {
       got_write_error = TRUE;
@@ -1081,7 +1316,7 @@ cf_merge_files(char **out_filenamep, int in_file_count,
 
        case WTAP_ERR_UNSUPPORTED_ENCAP:
          g_snprintf(errmsg_errno, sizeof(errmsg_errno),
-                  "The capture file %%s has a packet with a network type that Ethereal doesn't support.\n(%s)",
+                  "The capture file %%s has a packet with a network type that Wireshark doesn't support.\n(%s)",
                   err_info);
          g_free(err_info);
          errmsg = errmsg_errno;
@@ -1112,8 +1347,7 @@ cf_merge_files(char **out_filenamep, int in_file_count,
          errmsg = errmsg_errno;
          break;
        }
-       g_snprintf(err_str, sizeof err_str, errmsg, in_files[i].filename);
-        simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, err_str);
+        simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, errmsg, in_files[i].filename);
       }
     }
   }
@@ -1123,24 +1357,33 @@ cf_merge_files(char **out_filenamep, int in_file_count,
     cf_write_failure_alert_box(out_filename, write_err);
   }
 
-  return (!got_read_error && !got_write_error) ? CF_OK : CF_ERROR;
+  if (got_read_error || got_write_error || stop_flag) {
+    /* Callers aren't expected to treat an error or an explicit abort
+       differently - we put up error dialogs ourselves, so they don't
+       have to. */
+    return CF_ERROR;
+  } else
+    return CF_OK;
 }
 
 cf_status_t
 cf_filter_packets(capture_file *cf, gchar *dftext, gboolean force)
 {
-  dfilter_t  *dfcode;
   const char *filter_new = dftext ? dftext : "";
   const char *filter_old = cf->dfilter ? cf->dfilter : "";
+  dfilter_t   *dfcode;
 
   /* if new filter equals old one, do nothing unless told to do so */
   if (!force && strcmp(filter_new, filter_old) == 0) {
     return CF_OK;
   }
 
+  dfcode=NULL;
+
   if (dftext == NULL) {
-    /* The new filter is an empty filter (i.e., display all packets). */
-    dfcode = NULL;
+    /* The new filter is an empty filter (i.e., display all packets).
+     * so leave dfcode==NULL
+     */
   } else {
     /*
      * We have a filter; make a copy of it (as we'll be saving it),
@@ -1152,7 +1395,7 @@ cf_filter_packets(capture_file *cf, gchar *dftext, gboolean force)
       gchar *safe_dftext = simple_dialog_format_message(dftext);
       gchar *safe_dfilter_error_msg = simple_dialog_format_message(
          dfilter_error_msg);
-      simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, 
+      simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
           "%s%s%s\n"
           "\n"
           "The following display filter isn't a valid display filter:\n%s\n"
@@ -1177,9 +1420,6 @@ cf_filter_packets(capture_file *cf, gchar *dftext, gboolean force)
   if (cf->dfilter != NULL)
     g_free(cf->dfilter);
   cf->dfilter = dftext;
-  if (cf->dfcode != NULL)
-    dfilter_free(cf->dfcode);
-  cf->dfcode = dfcode;
 
   /* Now rescan the packet list, applying the new filter, but not
      throwing away information constructed on a previous pass. */
@@ -1188,6 +1428,11 @@ cf_filter_packets(capture_file *cf, gchar *dftext, gboolean force)
   } else {
     rescan_packets(cf, "Filtering", dftext, TRUE, FALSE);
   }
+
+  /* Cleanup and release all dfilter resources */
+  if (dfcode != NULL){
+    dfilter_free(dfcode);
+  }
   return CF_OK;
 }
 
@@ -1237,11 +1482,21 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item,
   int         selected_row, prev_row, preceding_row, following_row;
   gboolean    selected_frame_seen;
   int         row;
-  float       prog_val;
+  float       progbar_val;
   GTimeVal    start_time;
   gchar       status_str[100];
   int         progbar_nextstep;
   int         progbar_quantum;
+  dfilter_t   *dfcode;
+
+  /* Compile the current display filter.
+   * We assume this will not fail since cf->dfilter is only set in
+   * cf_filter IFF the filter was valid.
+   */
+  dfcode=NULL;
+  if(cf->dfilter){
+    dfilter_compile(cf->dfilter, &dfcode);
+  }
 
   cum_bytes=0;
   reset_tap_listeners();
@@ -1261,6 +1516,10 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item,
        which might cause the state information to be constructed differently
        by that dissector. */
 
+    /* We might receive new packets while redissecting, and we don't
+       want to dissect those before their time. */
+    cf->redissecting = TRUE;
+
     /* Initialize all data structures used for dissection. */
     init_dissection();
   }
@@ -1282,8 +1541,8 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item,
   /* Iterate through the list of frames.  Call a routine for each frame
      to check whether it should be displayed and, if so, add it to
      the display list. */
-  nstime_set_zero(&first_ts);
-  nstime_set_zero(&prev_ts);
+  nstime_set_unset(&first_ts);
+  nstime_set_unset(&prev_dis_ts);
 
   /* Update the progress bar when it gets to this value. */
   progbar_nextstep = 0;
@@ -1292,6 +1551,8 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item,
   progbar_quantum = cf->count/N_PROGBAR_UPDATES;
   /* Count of packets at which we've looked. */
   count = 0;
+  /* Progress so far. */
+  progbar_val = 0.0;
 
   stop_flag = FALSE;
   g_get_current_time(&start_time);
@@ -1308,6 +1569,16 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item,
   selected_frame_seen = FALSE;
 
   for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
+    /* 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)
+      progbar = delayed_create_progress_dlg(action, action_item, TRUE,
+                                            &stop_flag, &start_time,
+                                            progbar_val);
+
     /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
        when we update it, we have to run the GTK+ main loop to get it
        to repaint what's pending, and doing so may involve an "ioctl()"
@@ -1318,17 +1589,12 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item,
        * with count == 0, so let's assert that
        */
       g_assert(cf->count > 0);
-      prog_val = (gfloat) count / cf->count;
-
-      if (progbar == NULL)
-        /* Create the progress bar if necessary */
-        progbar = delayed_create_progress_dlg(action, action_item, &stop_flag,
-          &start_time, prog_val);
+      progbar_val = (gfloat) count / cf->count;
 
       if (progbar != NULL) {
         g_snprintf(status_str, sizeof(status_str),
                   "%4u of %u frames", count, cf->count);
-        update_progress_dlg(progbar, prog_val, status_str);
+        update_progress_dlg(progbar, progbar_val, status_str);
       }
 
       progbar_nextstep += progbar_quantum;
@@ -1378,7 +1644,7 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item,
       preceding_row = prev_row;
       preceding_frame = prev_frame;
     }
-    row = add_packet_to_packet_list(fdata, cf, &cf->pseudo_header, cf->pd,
+    row = add_packet_to_packet_list(fdata, cf, dfcode, &cf->pseudo_header, cf->pd,
                                        refilter);
 
     /* If this frame is displayed, and this is the first frame we've
@@ -1400,6 +1666,12 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item,
     prev_frame = fdata;
   }
 
+  /* We are done redissecting the packet list. */
+  cf->redissecting = FALSE;
+
+  /* Re-sort the list using the previously selected order */
+  packet_list_set_sort_column();
+
   if (redissect) {
     /* Clear out what remains of the visited flags and per-frame data
        pointers.
@@ -1408,7 +1680,7 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item,
        these frames, as they won't have been seen by this sequential
        pass, but the only alternative I see is to keep scanning them
        even though the user requested that the scan stop, and that
-       would leave the user stuck with an Ethereal grinding on
+       would leave the user stuck with an Wireshark grinding on
        until it finishes.  Should we just stick them with that? */
     for (; fdata != NULL; fdata = fdata->next) {
       fdata->flags.visited = 0;
@@ -1453,18 +1725,9 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item,
            frame. */
         selected_row = following_row;
       } else {
-        /* Choose the closer of the last displayed frame before the
-           selected frame and the first displayed frame after the
-           selected frame; in case of a tie, choose the first displayed
-           frame after the selected frame. */
-        if (following_frame->num - selected_frame->num <=
-            selected_frame->num - preceding_frame->num) {
-          selected_row = following_row;
-        } else {
-          /* The previous frame is closer to the selected frame than the
-             next frame. */
-          selected_row = preceding_row;
-        }
+        /* Frames before and after the selected frame passed the filter, so
+          we'll select the previous frame */
+        selected_row = preceding_row;
       }
     }
   }
@@ -1476,8 +1739,17 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item,
     /* Either the frame that was selected passed the filter, or we've
        found the nearest displayed frame to that frame.  Select it, make
        it the focus row, and make it visible. */
+    if (selected_row == 0) {
+      /* Set to invalid to force update of packet list and packet details */
+      cf->current_row = -1;
+    }
     packet_list_set_selected_row(selected_row);
   }
+
+  /* Cleanup and release all dfilter resources */
+  if (dfcode != NULL){
+    dfilter_free(dfcode);
+  }
 }
 
 typedef enum {
@@ -1488,7 +1760,7 @@ typedef enum {
 
 static psp_return_t
 process_specified_packets(capture_file *cf, packet_range_t *range,
-    const char *string1, const char *string2,
+    const char *string1, const char *string2, gboolean terminate_is_stop,
     gboolean (*callback)(capture_file *, frame_data *,
                          union wtap_pseudo_header *, const guint8 *, void *),
     void *callback_args)
@@ -1517,6 +1789,8 @@ process_specified_packets(capture_file *cf, packet_range_t *range,
   progbar_quantum = cf->count/N_PROGBAR_UPDATES;
   /* Count of packets at which we've looked. */
   progbar_count = 0;
+  /* Progress so far. */
+  progbar_val = 0.0;
 
   progbar_stop_flag = FALSE;
   g_get_current_time(&progbar_start_time);
@@ -1526,6 +1800,18 @@ process_specified_packets(capture_file *cf, packet_range_t *range,
   /* Iterate through the list of packets, printing the packets that
      were selected by the current display filter.  */
   for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
+    /* 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)
+      progbar = delayed_create_progress_dlg(string1, string2,
+                                            terminate_is_stop,
+                                            &progbar_stop_flag,
+                                            &progbar_start_time,
+                                            progbar_val);
+
     /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
        when we update it, we have to run the GTK+ main loop to get it
        to repaint what's pending, and doing so may involve an "ioctl()"
@@ -1538,13 +1824,6 @@ process_specified_packets(capture_file *cf, packet_range_t *range,
       g_assert(cf->count > 0);
       progbar_val = (gfloat) progbar_count / cf->count;
 
-      if (progbar == NULL)
-        /* Create the progress bar if necessary */
-        progbar = delayed_create_progress_dlg(string1, string2,
-                                              &progbar_stop_flag,
-                                              &progbar_start_time,
-                                              progbar_val);
-
       if (progbar != NULL) {
         g_snprintf(progbar_status_str, sizeof(progbar_status_str),
                    "%4u of %u packets", progbar_count, cf->count);
@@ -1556,8 +1835,8 @@ process_specified_packets(capture_file *cf, packet_range_t *range,
 
     if (progbar_stop_flag) {
       /* Well, the user decided to abort the operation.  Just stop,
-         and arrange to return TRUE to our caller, so they know it
-         was stopped explicitly. */
+         and arrange to return PSP_STOPPED to our caller, so they know
+         it was stopped explicitly. */
       ret = PSP_STOPPED;
       break;
     }
@@ -1602,8 +1881,9 @@ process_specified_packets(capture_file *cf, packet_range_t *range,
 static gboolean
 retap_packet(capture_file *cf _U_, frame_data *fdata,
              union wtap_pseudo_header *pseudo_header, const guint8 *pd,
-             void *argsp _U_)
+             void *argsp)
 {
+  column_info *cinfo = argsp;
   epan_dissect_t *edt;
 
   /* If we have tap listeners, allocate a protocol tree root node, so that
@@ -1611,7 +1891,7 @@ retap_packet(capture_file *cf _U_, frame_data *fdata,
      be evaluated. */
   edt = epan_dissect_new(num_tap_filters != 0, FALSE);
   tap_queue_init(edt);
-  epan_dissect_run(edt, pseudo_header, pd, fdata, NULL);
+  epan_dissect_run(edt, pseudo_header, pd, fdata, cinfo);
   tap_push_tapped_queue(edt);
   epan_dissect_free(edt);
 
@@ -1619,7 +1899,7 @@ retap_packet(capture_file *cf _U_, frame_data *fdata,
 }
 
 cf_read_status_t
-cf_retap_packets(capture_file *cf)
+cf_retap_packets(capture_file *cf, gboolean do_columns)
 {
   packet_range_t range;
 
@@ -1631,11 +1911,11 @@ cf_retap_packets(capture_file *cf)
   packet_range_init(&range);
   packet_range_process_init(&range);
   switch (process_specified_packets(cf, &range, "Refiltering statistics on",
-                                    "all packets", retap_packet,
-                                    NULL)) {
+                                    "all packets", TRUE, retap_packet,
+                                    do_columns ? &cf->cinfo : NULL)) {
   case PSP_FINISHED:
     /* Completed successfully. */
-    return CF_OK;
+    return CF_READ_OK;
 
   case PSP_STOPPED:
     /* Well, the user decided to abort the refiltering.
@@ -1682,8 +1962,8 @@ print_packet(capture_file *cf, frame_data *fdata,
   /* Create the protocol tree, and make it visible, if we're printing
      the dissection or the hex data.
      XXX - do we need it if we're just printing the hex data? */
-  proto_tree_needed = 
-      args->print_args->print_dissections != print_dissections_none || args->print_args->print_hex;
+  proto_tree_needed =
+      args->print_args->print_dissections != print_dissections_none || args->print_args->print_hex || have_custom_cols(&cf->cinfo);
   edt = epan_dissect_new(proto_tree_needed, proto_tree_needed);
 
   /* Fill in the column information if we're printing the summary
@@ -1894,7 +2174,7 @@ cf_print_packets(capture_file *cf, print_args_t *print_args)
   /* Iterate through the list of packets, printing the packets we were
      told to print. */
   ret = process_specified_packets(cf, &print_args->range, "Printing",
-                                  "selected packets", print_packet,
+                                  "selected packets", TRUE, print_packet,
                                   &callback_args);
 
   if (callback_args.header_line_buf != NULL)
@@ -1967,7 +2247,7 @@ cf_write_pdml_packets(capture_file *cf, print_args_t *print_args)
   FILE        *fh;
   psp_return_t ret;
 
-  fh = fopen(print_args->file, "w");
+  fh = ws_fopen(print_args->file, "w");
   if (fh == NULL)
     return CF_PRINT_OPEN_ERROR;        /* attempt to open destination failed */
 
@@ -1980,8 +2260,8 @@ cf_write_pdml_packets(capture_file *cf, print_args_t *print_args)
   /* Iterate through the list of packets, printing the packets we were
      told to print. */
   ret = process_specified_packets(cf, &print_args->range, "Writing PDML",
-                                  "selected packets", write_pdml_packet,
-                                  fh);
+                                  "selected packets", TRUE,
+                                  write_pdml_packet, fh);
 
   switch (ret) {
 
@@ -2018,9 +2298,12 @@ write_psml_packet(capture_file *cf, frame_data *fdata,
 {
   FILE *fh = argsp;
   epan_dissect_t *edt;
+  gboolean proto_tree_needed;
 
-  /* Fill in the column information, but don't create the protocol tree. */
-  edt = epan_dissect_new(FALSE, FALSE);
+  /* Fill in the column information, only create the protocol tree
+     if having custom columns. */
+  proto_tree_needed = have_custom_cols(&cf->cinfo);
+  edt = epan_dissect_new(proto_tree_needed, proto_tree_needed);
   epan_dissect_run(edt, pseudo_header, pd, fdata, &cf->cinfo);
   epan_dissect_fill_in_columns(edt);
 
@@ -2038,7 +2321,7 @@ cf_write_psml_packets(capture_file *cf, print_args_t *print_args)
   FILE        *fh;
   psp_return_t ret;
 
-  fh = fopen(print_args->file, "w");
+  fh = ws_fopen(print_args->file, "w");
   if (fh == NULL)
     return CF_PRINT_OPEN_ERROR;        /* attempt to open destination failed */
 
@@ -2051,8 +2334,8 @@ cf_write_psml_packets(capture_file *cf, print_args_t *print_args)
   /* Iterate through the list of packets, printing the packets we were
      told to print. */
   ret = process_specified_packets(cf, &print_args->range, "Writing PSML",
-                                  "selected packets", write_psml_packet,
-                                  fh);
+                                  "selected packets", TRUE,
+                                  write_psml_packet, fh);
 
   switch (ret) {
 
@@ -2089,9 +2372,12 @@ write_csv_packet(capture_file *cf, frame_data *fdata,
 {
   FILE *fh = argsp;
   epan_dissect_t *edt;
+  gboolean proto_tree_needed;
 
-  /* Fill in the column information, but don't create the protocol tree. */
-  edt = epan_dissect_new(FALSE, FALSE);
+  /* Fill in the column information, only create the protocol tree
+     if having custom columns. */
+  proto_tree_needed = have_custom_cols(&cf->cinfo);
+  edt = epan_dissect_new(proto_tree_needed, proto_tree_needed);
   epan_dissect_run(edt, pseudo_header, pd, fdata, &cf->cinfo);
   epan_dissect_fill_in_columns(edt);
 
@@ -2109,7 +2395,7 @@ cf_write_csv_packets(capture_file *cf, print_args_t *print_args)
   FILE        *fh;
   psp_return_t ret;
 
-  fh = fopen(print_args->file, "w");
+  fh = ws_fopen(print_args->file, "w");
   if (fh == NULL)
     return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
 
@@ -2122,8 +2408,8 @@ cf_write_csv_packets(capture_file *cf, print_args_t *print_args)
   /* Iterate through the list of packets, printing the packets we were
      told to print. */
   ret = process_specified_packets(cf, &print_args->range, "Writing CSV",
-                                  "selected packets", write_csv_packet,
-                                  fh);
+                                  "selected packets", TRUE,
+                                  write_csv_packet, fh);
 
   switch (ret) {
 
@@ -2153,6 +2439,65 @@ cf_write_csv_packets(capture_file *cf, print_args_t *print_args)
   return CF_PRINT_OK;
 }
 
+static gboolean
+write_carrays_packet(capture_file *cf _U_, frame_data *fdata,
+                    union wtap_pseudo_header *pseudo_header _U_,
+                    const guint8 *pd, void *argsp)
+{
+  FILE *fh = argsp;
+
+  proto_tree_write_carrays(pd, fdata->cap_len, fdata->num, fh);
+  return !ferror(fh);
+}
+
+cf_print_status_t
+cf_write_carrays_packets(capture_file *cf, print_args_t *print_args)
+{
+  FILE        *fh;
+  psp_return_t ret;
+
+  fh = ws_fopen(print_args->file, "w");
+
+  if (fh == NULL)
+    return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
+
+  write_carrays_preamble(fh);
+
+  if (ferror(fh)) {
+    fclose(fh);
+    return CF_PRINT_WRITE_ERROR;
+  }
+
+  /* Iterate through the list of packets, printing the packets we were
+     told to print. */
+  ret = process_specified_packets(cf, &print_args->range,
+                                 "Writing C Arrays",
+                                 "selected packets", TRUE,
+                                  write_carrays_packet, fh);
+  switch (ret) {
+  case PSP_FINISHED:
+    /* Completed successfully. */
+    break;
+  case PSP_STOPPED:
+    /* Well, the user decided to abort the printing. */
+    break;
+  case PSP_FAILED:
+    /* Error while printing. */
+    fclose(fh);
+    return CF_PRINT_WRITE_ERROR;
+  }
+
+  write_carrays_finale(fh);
+
+  if (ferror(fh)) {
+    fclose(fh);
+    return CF_PRINT_WRITE_ERROR;
+  }
+
+  fclose(fh);
+  return CF_PRINT_OK;
+}
+
 /* Scan through the packet list and change all columns that use the
    "command-line-specified" time stamp format to use the current
    value of that format. */
@@ -2165,12 +2510,11 @@ cf_change_time_formats(capture_file *cf)
   int         count;
   int         row;
   int         i;
-  float       prog_val;
+  float       progbar_val;
   GTimeVal    start_time;
   gchar       status_str[100];
   int         progbar_nextstep;
   int         progbar_quantum;
-  int         first, last;
   gboolean    sorted_by_frame_column;
 
 
@@ -2183,14 +2527,16 @@ cf_change_time_formats(capture_file *cf)
      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)) {
+  if (!check_col(&cf->cinfo, COL_CLS_TIME) &&
+      !check_col(&cf->cinfo, COL_ABS_TIME) &&
+      !check_col(&cf->cinfo, COL_ABS_DATE_TIME) &&
+      !check_col(&cf->cinfo, COL_REL_TIME) &&
+      !check_col(&cf->cinfo, COL_DELTA_TIME) &&
+      !check_col(&cf->cinfo, COL_DELTA_TIME_DIS)) {
     /* No, there aren't any columns in that format, so we have no work
        to do. */
     return;
   }
-  first = cf->cinfo.col_first[COL_CLS_TIME];
-  g_assert(first >= 0);
-  last = cf->cinfo.col_last[COL_CLS_TIME];
 
   /* Freeze the packet list while we redo it, so we don't get any
      screen updates while it happens. */
@@ -2203,6 +2549,8 @@ cf_change_time_formats(capture_file *cf)
   progbar_quantum = cf->count/N_PROGBAR_UPDATES;
   /* Count of packets at which we've looked. */
   count = 0;
+  /* Progress so far. */
+  progbar_val = 0.0;
 
   /*  If the rows are currently sorted by the frame column then we know
    *  the row number of each packet: it's the row number of the previously
@@ -2233,6 +2581,15 @@ cf_change_time_formats(capture_file *cf)
      any columns that show the time in the "command-line-specified"
      format and, if so, update that row. */
   for (fdata = cf->plist, row = -1; fdata != NULL; fdata = fdata->next) {
+    /* 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)
+      progbar = delayed_create_progress_dlg("Changing", "time display",
+        TRUE, &stop_flag, &start_time, progbar_val);
+
     /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
        when we update it, we have to run the GTK+ main loop to get it
        to repaint what's pending, and doing so may involve an "ioctl()"
@@ -2244,17 +2601,12 @@ cf_change_time_formats(capture_file *cf)
        */
       g_assert(cf->count > 0);
 
-      prog_val = (gfloat) count / cf->count;
-
-      if (progbar == NULL)
-        /* Create the progress bar if necessary */
-        progbar = delayed_create_progress_dlg("Changing", "time display", 
-          &stop_flag, &start_time, prog_val);
+      progbar_val = (gfloat) count / cf->count;
 
       if (progbar != NULL) {
         g_snprintf(status_str, sizeof(status_str),
                    "%4u of %u packets", count, cf->count);
-        update_progress_dlg(progbar, prog_val, status_str);
+        update_progress_dlg(progbar, progbar_val, status_str);
       }
 
       progbar_nextstep += progbar_quantum;
@@ -2290,12 +2642,12 @@ cf_change_time_formats(capture_file *cf)
     if (row != -1) {
       /* This packet is in the summary list, on row "row". */
 
-      for (i = first; i <= last; i++) {
-        if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
+      for (i = 0; i < cf->cinfo.num_cols; i++) {
+        if (col_has_time_fmt(&cf->cinfo, i)) {
           /* 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);
+          col_set_fmt_time(fdata, &cf->cinfo, cf->cinfo.col_fmt[i], i);
           packet_list_set_text(row, i, cf->cinfo.col_data[i]);
         }
       }
@@ -2309,9 +2661,9 @@ cf_change_time_formats(capture_file *cf)
 
   /* Set the column widths of those columns that show the time in
      "command-line-specified" format. */
-  for (i = first; i <= last; i++) {
-    if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
-      packet_list_set_cls_time_width(i);
+  for (i = 0; i < cf->cinfo.num_cols; i++) {
+    if (col_has_time_fmt(&cf->cinfo, i)) {
+      packet_list_set_time_width(cf->cinfo.col_fmt[i], i);
     }
   }
 
@@ -2387,7 +2739,7 @@ match_subtree_text(proto_node *node, gpointer data)
     label_ptr = label_str;
     proto_item_fill_label(fi, label_str);
   }
-    
+
   /* Does that label match? */
   label_len = strlen(label_ptr);
   for (i = 0; i < label_len; i++) {
@@ -2404,7 +2756,7 @@ match_subtree_text(proto_node *node, gpointer data)
     } else
       c_match = 0;
   }
-  
+
   /* Recurse into the subtree, if it exists */
   if (node->first_child != NULL)
     proto_tree_children_foreach(node, match_subtree_text, mdata);
@@ -2505,7 +2857,7 @@ static gboolean
 match_ascii_and_unicode(capture_file *cf, frame_data *fdata, void *criterion)
 {
   cbs_t                *info = criterion;
-  const char   *ascii_text = info->data;
+  const guint8 *ascii_text = info->data;
   size_t       textlen = info->data_len;
   gboolean     frame_matched;
   guint32      buf_len;
@@ -2524,6 +2876,8 @@ match_ascii_and_unicode(capture_file *cf, frame_data *fdata, void *criterion)
        c_match++;
        if (c_match == textlen) {
          frame_matched = TRUE;
+         cf->search_pos = i; /* Save the position of the last character
+                              for highlighting the field. */
          break;
        }
       } else
@@ -2537,7 +2891,7 @@ static gboolean
 match_ascii(capture_file *cf, frame_data *fdata, void *criterion)
 {
   cbs_t                *info = criterion;
-  const char   *ascii_text = info->data;
+  const guint8 *ascii_text = info->data;
   size_t       textlen = info->data_len;
   gboolean     frame_matched;
   guint32      buf_len;
@@ -2555,6 +2909,8 @@ match_ascii(capture_file *cf, frame_data *fdata, void *criterion)
       c_match++;
       if (c_match == textlen) {
        frame_matched = TRUE;
+       cf->search_pos = i; /* Save the position of the last character
+                              for highlighting the field. */
        break;
       }
     } else
@@ -2567,7 +2923,7 @@ static gboolean
 match_unicode(capture_file *cf, frame_data *fdata, void *criterion)
 {
   cbs_t                *info = criterion;
-  const char   *ascii_text = info->data;
+  const guint8 *ascii_text = info->data;
   size_t       textlen = info->data_len;
   gboolean     frame_matched;
   guint32      buf_len;
@@ -2586,6 +2942,8 @@ match_unicode(capture_file *cf, frame_data *fdata, void *criterion)
       i++;
       if (c_match == textlen) {
        frame_matched = TRUE;
+       cf->search_pos = i; /* Save the position of the last character
+                              for highlighting the field. */
        break;
       }
     } else
@@ -2612,6 +2970,8 @@ match_binary(capture_file *cf, frame_data *fdata, void *criterion)
       c_match++;
       if (c_match == datalen) {
        frame_matched = TRUE;
+       cf->search_pos = i; /* Save the position of the last character
+                              for highlighting the field. */
        break;
       }
     } else
@@ -2655,11 +3015,12 @@ find_packet(capture_file *cf,
   int         err;
   gchar      *err_info;
   int         row;
-  float       prog_val;
+  float       progbar_val;
   GTimeVal    start_time;
   gchar       status_str[100];
   int         progbar_nextstep;
   int         progbar_quantum;
+  char       *title;
 
   start_fd = cf->current_frame;
   if (start_fd != NULL)  {
@@ -2669,16 +3030,29 @@ find_packet(capture_file *cf,
     count = 0;
     fdata = start_fd;
 
+    /* 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 = cf->count/N_PROGBAR_UPDATES;
+    /* Progress so far. */
+    progbar_val = 0.0;
 
     stop_flag = FALSE;
     g_get_current_time(&start_time);
 
     fdata = start_fd;
+    title = cf->sfilter?cf->sfilter:"";
     for (;;) {
+      /* 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)
+         progbar = delayed_create_progress_dlg("Searching", title,
+           FALSE, &stop_flag, &start_time, progbar_val);
+
       /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
          when we update it, we have to run the GTK+ main loop to get it
          to repaint what's pending, and doing so may involve an "ioctl()"
@@ -2690,17 +3064,12 @@ find_packet(capture_file *cf,
          */
         g_assert(cf->count > 0);
 
-        prog_val = (gfloat) count / cf->count;
-
-        /* Create the progress bar if necessary */
-        if (progbar == NULL)
-           progbar = delayed_create_progress_dlg("Searching", cf->sfilter, 
-             &stop_flag, &start_time, prog_val);
+        progbar_val = (gfloat) count / cf->count;
 
         if (progbar != NULL) {
           g_snprintf(status_str, sizeof(status_str),
                      "%4u of %u packets", count, cf->count);
-          update_progress_dlg(progbar, prog_val, status_str);
+          update_progress_dlg(progbar, progbar_val, status_str);
         }
 
         progbar_nextstep += progbar_quantum;
@@ -2914,7 +3283,7 @@ cf_goto_framenum(capture_file *cf)
     hfinfo = cf->finfo_selected->hfinfo;
     g_assert(hfinfo);
     if (hfinfo->type == FT_FRAMENUM) {
-      framenum = fvalue_get_integer(&cf->finfo_selected->value);
+      framenum = fvalue_get_uinteger(&cf->finfo_selected->value);
       if (framenum != 0)
         return cf_goto_frame(cf, framenum);
       }
@@ -2965,6 +3334,11 @@ cf_select_packet(capture_file *cf, int row)
          fdata = cf->first_displayed;
   }
 
+  /* If fdata _still_ isn't set simply give up. */
+  if (fdata == NULL) {
+    return;
+  }
+
   /* Get the data in that frame. */
   if (!wtap_seek_read (cf->wth, fdata->file_off, &cf->pseudo_header,
                       cf->pd, fdata->cap_len, &err, &err_info)) {
@@ -2975,6 +3349,7 @@ cf_select_packet(capture_file *cf, int row)
 
   /* Record that this frame is the current frame. */
   cf->current_frame = fdata;
+  cf->current_row = row;
 
   /* Create the logical protocol tree. */
   if (cf->edt != NULL) {
@@ -2983,9 +3358,12 @@ cf_select_packet(capture_file *cf, int row)
   }
   /* 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);
 
+  dfilter_macro_build_ftv_cache(cf->edt->tree);
+
   cf_callback_invoke(cf_cb_packet_selected, cf);
 }
 
@@ -3001,6 +3379,7 @@ cf_unselect_packet(capture_file *cf)
 
   /* No packet is selected. */
   cf->current_frame = NULL;
+  cf->current_row = 0;
 
   cf_callback_invoke(cf_cb_packet_unselected, cf);
 
@@ -3065,7 +3444,8 @@ save_packet(capture_file *cf _U_, frame_data *fdata,
   int           err;
 
   /* init the wtap header for saving */
-  hdr.ts         = *(struct wtap_nstime *) &fdata->abs_ts;
+  hdr.ts.secs    = fdata->abs_ts.secs;
+  hdr.ts.nsecs   = fdata->abs_ts.nsecs;
   hdr.caplen     = fdata->cap_len;
   hdr.len        = fdata->pkt_len;
   hdr.pkt_encap  = fdata->lnk_t;
@@ -3078,8 +3458,30 @@ save_packet(capture_file *cf _U_, frame_data *fdata,
   return TRUE;
 }
 
+/*
+ * Can this capture file be saved in any format except by copying the raw data?
+ */
+gboolean
+cf_can_save_as(capture_file *cf)
+{
+  int ft;
+
+  for (ft = 0; ft < WTAP_NUM_FILE_TYPES; ft++) {
+    /* To save a file with Wiretap, Wiretap has to handle that format,
+       and its code to handle that format must be able to write a file
+       with this file's encapsulation type. */
+    if (wtap_dump_can_open(ft) && wtap_dump_can_write_encap(ft, cf->lnk_t)) {
+      /* OK, we can write it out in this type. */
+      return TRUE;
+    }
+  }
+
+  /* No, we couldn't save it in any format. */
+  return FALSE;
+}
+
 cf_status_t
-cf_save(capture_file *cf, const char *fname, packet_range_t *range, guint save_format)
+cf_save(capture_file *cf, const char *fname, packet_range_t *range, guint save_format, gboolean compressed)
 {
   gchar        *from_filename;
   int           err;
@@ -3101,11 +3503,7 @@ cf_save(capture_file *cf, const char *fname, packet_range_t *range, guint save_f
 
   packet_range_process_init(range);
 
-  /* Used to be :
-   * if (!save_filtered && !save_marked && !save_manual_range && 
-   *     !save_marked_range && !save_curr && save_format == cf->cd_t) {
-   */ 
-       
+
   if (packet_range_process_all(range) && save_format == cf->cd_t) {
     /* We're not filtering packets, and we're saving it in the format
        it's already in, so we can just move or copy the raw data. */
@@ -3115,7 +3513,7 @@ cf_save(capture_file *cf, const char *fname, packet_range_t *range, guint save_f
          capture, so it doesn't need to stay around under that name;
         first, try renaming the capture buffer file to the new name. */
 #ifndef _WIN32
-      if (rename(cf->filename, fname) == 0) {
+      if (ws_rename(cf->filename, fname) == 0) {
        /* That succeeded - there's no need to copy the source file. */
        from_filename = NULL;
        do_copy = FALSE;
@@ -3158,7 +3556,8 @@ cf_save(capture_file *cf, const char *fname, packet_range_t *range, guint save_f
     /* Either we're filtering packets, or we're saving in a different
        format; we can't do that by copying or moving the capture file,
        we have to do it by writing the packets out in Wiretap. */
-    pdh = wtap_dump_open(fname, save_format, cf->lnk_t, cf->snap, &err);
+    pdh = wtap_dump_open(fname, save_format, cf->lnk_t, cf->snap,
+               compressed, &err);
     if (pdh == NULL) {
       cf_open_failure_alert_box(fname, err, NULL, TRUE, save_format);
       goto fail;
@@ -3179,9 +3578,8 @@ cf_save(capture_file *cf, const char *fname, packet_range_t *range, guint save_f
        "range" since we initialized it. */
     callback_args.pdh = pdh;
     callback_args.fname = fname;
-    switch (process_specified_packets(cf, range, "Saving",
-                                      "selected packets", save_packet,
-                                      &callback_args)) {
+    switch (process_specified_packets(cf, range, "Saving", "selected packets",
+                                      TRUE, save_packet, &callback_args)) {
 
     case PSP_FINISHED:
       /* Completed successfully. */
@@ -3265,21 +3663,21 @@ cf_open_failure_alert_box(const char *filename, int err, gchar *err_info,
     case WTAP_ERR_RANDOM_OPEN_PIPE:
       /* Seen only when opening a capture file for reading. */
       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
-                   "The file \"%s\" is a pipe or FIFO; Ethereal can't read pipe or FIFO files.",
+                   "The file \"%s\" is a pipe or FIFO; Wireshark can't read pipe or FIFO files.",
                    filename);
       break;
 
     case WTAP_ERR_FILE_UNKNOWN_FORMAT:
       /* Seen only when opening a capture file for reading. */
       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
-                   "The file \"%s\" isn't a capture file in a format Ethereal understands.",
+                   "The file \"%s\" isn't a capture file in a format Wireshark understands.",
                    filename);
       break;
 
     case WTAP_ERR_UNSUPPORTED:
       /* Seen only when opening a capture file for reading. */
       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
-                   "The file \"%s\" isn't a capture file in a format Ethereal understands.\n"
+                   "The file \"%s\" isn't a capture file in a format Wireshark understands.\n"
                    "(%s)",
                    filename, err_info);
       g_free(err_info);
@@ -3296,16 +3694,16 @@ cf_open_failure_alert_box(const char *filename, int err, gchar *err_info,
     case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
       /* Seen only when opening a capture file for writing. */
       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
-                   "Ethereal doesn't support writing capture files in that format.");
+                   "Wireshark doesn't support writing capture files in that format.");
       break;
 
     case WTAP_ERR_UNSUPPORTED_ENCAP:
       if (for_writing) {
        simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
-                     "Ethereal can't save this capture in that format.");
+                     "Wireshark can't save this capture in that format.");
       } else {
        simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
-                     "The file \"%s\" is a capture for a network type that Ethereal doesn't support.\n"
+                     "The file \"%s\" is a capture for a network type that Wireshark doesn't support.\n"
                      "(%s)",
                      filename, err_info);
         g_free(err_info);
@@ -3315,10 +3713,10 @@ cf_open_failure_alert_box(const char *filename, int err, gchar *err_info,
     case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
       if (for_writing) {
        simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
-                     "Ethereal can't save this capture in that format.");
+                     "Wireshark can't save this capture in that format.");
       } else {
        simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
-                     "The file \"%s\" is a capture for a network type that Ethereal doesn't support.",
+                     "The file \"%s\" is a capture for a network type that Wireshark doesn't support.",
                      filename);
       }
       break;
@@ -3357,6 +3755,11 @@ cf_open_failure_alert_box(const char *filename, int err, gchar *err_info,
                    filename);
       break;
 
+    case WTAP_ERR_COMPRESSION_NOT_SUPPORTED:
+      simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+                   "Gzip compression not supported by this file type.");
+      break;
+
     default:
       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
                    "The file \"%s\" could not be %s: %s.",
@@ -3398,22 +3801,24 @@ file_rename_error_message(int err)
 }
 
 char *
-cf_read_error_message(int err, const gchar *err_info)
+cf_read_error_message(int err, gchar *err_info)
 {
   static char errmsg_errno[1024+1];
 
   switch (err) {
 
   case WTAP_ERR_UNSUPPORTED_ENCAP:
-      g_snprintf(errmsg_errno, sizeof(errmsg_errno),
-               "The file \"%%s\" has a packet with a network type that Ethereal doesn't support.\n(%s)",
+    g_snprintf(errmsg_errno, sizeof(errmsg_errno),
+               "The file \"%%s\" has a packet with a network type that Wireshark doesn't support.\n(%s)",
                err_info);
-      break;
+    g_free(err_info);
+    break;
 
   case WTAP_ERR_BAD_RECORD:
     g_snprintf(errmsg_errno, sizeof(errmsg_errno),
             "An error occurred while reading from the file \"%%s\": %s.\n(%s)",
             wtap_strerror(err), err_info);
+    g_free(err_info);
     break;
 
   default:
@@ -3539,7 +3944,7 @@ copy_binary_file(const char *from_filename, const char *to_filename)
   guint8        pd[65536];
 
   /* Copy the raw bytes of the file. */
-  from_fd = open(from_filename, O_RDONLY | O_BINARY);
+  from_fd = ws_open(from_filename, O_RDONLY | O_BINARY, 0000 /* no creation so don't matter */);
   if (from_fd < 0) {
     open_failure_alert_box(from_filename, errno, FALSE);
     goto done;
@@ -3550,23 +3955,23 @@ copy_binary_file(const char *from_filename, const char *to_filename)
      may open the file in text mode, not binary mode, but we want
      to copy the raw bytes of the file, so we need the output file
      to be open in binary mode. */
-  to_fd = open(to_filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
+  to_fd = ws_open(to_filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
   if (to_fd < 0) {
     open_failure_alert_box(to_filename, errno, TRUE);
-    close(from_fd);
+    ws_close(from_fd);
     goto done;
   }
 
-  while ((nread = read(from_fd, pd, sizeof pd)) > 0) {
-    nwritten = write(to_fd, pd, nread);
+  while ((nread = ws_read(from_fd, pd, sizeof pd)) > 0) {
+    nwritten = ws_write(to_fd, pd, nread);
     if (nwritten < nread) {
       if (nwritten < 0)
        err = errno;
       else
        err = WTAP_ERR_SHORT_WRITE;
       write_failure_alert_box(to_filename, err);
-      close(from_fd);
-      close(to_fd);
+      ws_close(from_fd);
+      ws_close(to_fd);
       goto done;
     }
   }
@@ -3575,12 +3980,12 @@ copy_binary_file(const char *from_filename, const char *to_filename)
     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
                  "An error occurred while reading from the file \"%s\": %s.",
                  from_filename, strerror(err));
-    close(from_fd);
-    close(to_fd);
+    ws_close(from_fd);
+    ws_close(to_fd);
     goto done;
   }
-  close(from_fd);
-  if (close(to_fd) < 0) {
+  ws_close(from_fd);
+  if (ws_close(to_fd) < 0) {
     write_failure_alert_box(to_filename, errno);
     goto done;
   }