Fix a few minor memory leaks...
[obnox/wireshark/wip.git] / file.c
diff --git a/file.c b/file.c
index 62522039efc7dc068ace6027b9006e325a638b03..799130b6153cf6e918b8d746f2faa6de839a5aae 100644 (file)
--- a/file.c
+++ b/file.c
@@ -52,6 +52,7 @@
 
 #include "color.h"
 #include "color_filters.h"
+#include "cfile.h"
 #include <epan/column.h>
 #include <epan/packet.h>
 #include "packet-range.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>
-#include "file_util.h"
-
-
+#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);
@@ -127,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
@@ -251,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),
@@ -265,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:
@@ -294,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)
-      eth_unlink(cf->filename);
+      ws_unlink(cf->filename);
     g_free(cf->filename);
     cf->filename = NULL;
   }
@@ -317,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. */
@@ -357,6 +390,12 @@ cf_close(capture_file *cf)
   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)
 {
@@ -365,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        progbar_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);
 
@@ -438,8 +486,19 @@ cf_read(capture_file *cf)
               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, progbar_val, status_str);
           }
@@ -456,7 +515,35 @@ cf_read(capture_file *cf)
          hours even on fast machines) just to see that it was the wrong file. */
       break;
     }
-    read_packet(cf, data_offset);
+    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;
+    }
+    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. */
@@ -480,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);
@@ -540,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;
@@ -558,13 +646,25 @@ 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);*/
@@ -576,20 +676,59 @@ cf_continue_tail(capture_file *cf, int to_read, int *err)
         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();
 
-  packet_list_thaw();
-
   if (cf->state == FILE_READ_ABORTED) {
     /* Well, the user decided to exit Wireshark.  Return CF_READ_ABORTED
        so that our caller can kill off the capture child process;
@@ -612,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))) {
@@ -628,7 +778,12 @@ 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();
@@ -754,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)
 {
@@ -767,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
@@ -780,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. */
@@ -797,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
 
@@ -807,23 +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);
@@ -832,9 +993,9 @@ 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;
@@ -844,15 +1005,15 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
     /* 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.
@@ -874,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 {
@@ -899,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);
@@ -909,6 +1076,7 @@ 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);
@@ -927,7 +1095,13 @@ read_packet(capture_file *cf, long offset)
   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) {
@@ -949,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
@@ -961,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
@@ -978,10 +1156,9 @@ cf_merge_files(char **out_filenamep, int in_file_count,
   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;
@@ -994,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;
@@ -1002,7 +1179,7 @@ cf_merge_files(char **out_filenamep, int in_file_count,
 
   if (*out_filenamep != NULL) {
     out_filename = *out_filenamep;
-    out_fd = eth_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 {
@@ -1015,7 +1192,7 @@ 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;
   }
@@ -1025,9 +1202,9 @@ cf_merge_files(char **out_filenamep, int in_file_count,
       merge_max_snapshot_length(in_file_count, in_files),
          FALSE /* compressed */, &open_err);
   if (pdh == NULL) {
-    eth_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;
@@ -1097,7 +1274,7 @@ cf_merge_files(char **out_filenamep, int in_file_count,
         }
         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, progbar_val, status_str);
         }
@@ -1170,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);
       }
     }
   }
@@ -1187,24 +1363,27 @@ cf_merge_files(char **out_filenamep, int in_file_count,
        have to. */
     return CF_ERROR;
   } else
-    return CF_READ_OK;
+    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),
@@ -1241,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. */
@@ -1252,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;
 }
 
@@ -1306,6 +1487,16 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item,
   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();
@@ -1325,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();
   }
@@ -1346,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;
@@ -1449,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
@@ -1471,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.
@@ -1523,6 +1724,10 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item,
            have to select the first displayed frame after the selected
            frame. */
         selected_row = following_row;
+      } else {
+        /* Frames before and after the selected frame passed the filter, so
+          we'll select the previous frame */
+        selected_row = preceding_row;
       }
     }
   }
@@ -1534,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 {
@@ -1701,7 +1915,7 @@ cf_retap_packets(capture_file *cf, gboolean do_columns)
                                     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.
@@ -1749,7 +1963,7 @@ print_packet(capture_file *cf, frame_data *fdata,
      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;
+      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
@@ -2033,7 +2247,7 @@ cf_write_pdml_packets(capture_file *cf, print_args_t *print_args)
   FILE        *fh;
   psp_return_t ret;
 
-  fh = eth_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 */
 
@@ -2084,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);
 
@@ -2104,7 +2321,7 @@ cf_write_psml_packets(capture_file *cf, print_args_t *print_args)
   FILE        *fh;
   psp_return_t ret;
 
-  fh = eth_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 */
 
@@ -2155,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);
 
@@ -2175,7 +2395,7 @@ cf_write_csv_packets(capture_file *cf, print_args_t *print_args)
   FILE        *fh;
   psp_return_t ret;
 
-  fh = eth_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 */
 
@@ -2219,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. */
@@ -2236,7 +2515,6 @@ cf_change_time_formats(capture_file *cf)
   gchar       status_str[100];
   int         progbar_nextstep;
   int         progbar_quantum;
-  int         first, last;
   gboolean    sorted_by_frame_column;
 
 
@@ -2249,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. */
@@ -2362,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]);
         }
       }
@@ -2381,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);
     }
   }
 
@@ -2577,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;
@@ -2596,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
@@ -2609,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;
@@ -2627,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
@@ -2639,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;
@@ -2658,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
@@ -2684,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
@@ -2995,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);
       }
@@ -3061,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) {
@@ -3073,6 +3362,8 @@ cf_select_packet(capture_file *cf, int row)
   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);
 }
 
@@ -3088,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);
 
@@ -3152,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;
@@ -3165,6 +3458,28 @@ 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, gboolean compressed)
 {
@@ -3198,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 (eth_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;
@@ -3486,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),
+    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:
@@ -3627,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 = eth_open(from_filename, O_RDONLY | O_BINARY, 0000 /* no creation so don't matter */);
+  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;
@@ -3638,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 = eth_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);
-    eth_close(from_fd);
+    ws_close(from_fd);
     goto done;
   }
 
-  while ((nread = eth_read(from_fd, pd, sizeof pd)) > 0) {
-    nwritten = eth_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);
-      eth_close(from_fd);
-      eth_close(to_fd);
+      ws_close(from_fd);
+      ws_close(to_fd);
       goto done;
     }
   }
@@ -3663,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));
-    eth_close(from_fd);
-    eth_close(to_fd);
+    ws_close(from_fd);
+    ws_close(to_fd);
     goto done;
   }
-  eth_close(from_fd);
-  if (eth_close(to_fd) < 0) {
+  ws_close(from_fd);
+  if (ws_close(to_fd) < 0) {
     write_failure_alert_box(to_filename, errno);
     goto done;
   }