sv: remove some unnecessary checks
[metze/wireshark/wip.git] / file.c
diff --git a/file.c b/file.c
index f722a929c1fe82731679e8efbea2dd4726ce8d3f..ce209ba466f49d88a47328e739d22551ccc17c81 100644 (file)
--- a/file.c
+++ b/file.c
@@ -1,8 +1,6 @@
 /* file.c
  * File I/O routines
  *
- * $Id$
- *
  * Wireshark - Network traffic analyzer
  * By Gerald Combs <gerald@wireshark.org>
  * Copyright 1998 Gerald Combs
@@ -22,7 +20,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#include "config.h"
+#include <config.h>
 
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
@@ -35,7 +33,6 @@
 #include <string.h>
 #include <ctype.h>
 #include <errno.h>
-#include <signal.h>
 
 #ifdef HAVE_FCNTL_H
 #include <fcntl.h>
 
 #include <wsutil/tempfile.h>
 #include <wsutil/file_util.h>
+#include <wsutil/filesystem.h>
+#include <wsutil/ws_version_info.h>
 
 #include <wiretap/merge.h>
 
+#include <epan/exceptions.h>
 #include <epan/epan-int.h>
 #include <epan/epan.h>
 #include <epan/column.h>
 #include <epan/packet.h>
 #include <epan/column-utils.h>
 #include <epan/expert.h>
-#include <epan/filesystem.h>
 #include <epan/prefs.h>
 #include <epan/dfilter/dfilter.h>
 #include <epan/epan_dissect.h>
 #include <epan/tap.h>
-#include <epan/dissectors/packet-data.h>
 #include <epan/dissectors/packet-ber.h>
 #include <epan/timestamp.h>
 #include <epan/dfilter/dfilter-macro.h>
@@ -77,8 +75,6 @@
 #include "ui/progress_dlg.h"
 #include "ui/ui_util.h"
 
-#include "version_info.h"
-
 /* Needed for addrinfo */
 #ifdef HAVE_SYS_TYPES_H
 # include <sys/types.h>
 #endif
 
 #ifdef HAVE_LIBPCAP
-gboolean auto_scroll_live;
+gboolean auto_scroll_live; /* GTK+ only? */
 #endif
 
-static guint32 cum_bytes;
-const static frame_data *ref;
-static frame_data *prev_dis;
-static frame_data *prev_cap;
-
-static gulong computed_elapsed;
-
-static void cf_reset_state(capture_file *cf);
-
-static int read_packet(capture_file *cf, dfilter_t *dfcode,
-    gboolean create_proto_tree, column_info *cinfo, gint64 offset);
+static int read_packet(capture_file *cf, dfilter_t *dfcode, epan_dissect_t *edt,
+    column_info *cinfo, gint64 offset);
 
 static void rescan_packets(capture_file *cf, const char *action, const char *action_item, gboolean redissect);
 
@@ -150,6 +137,8 @@ static gboolean find_packet(capture_file *cf,
     match_result (*match_function)(capture_file *, frame_data *, void *),
     void *criterion, search_direction dir);
 
+static const char *cf_get_user_packet_comment(capture_file *cf, const frame_data *fd);
+
 static void cf_open_failure_alert_box(const char *filename, int err,
                       gchar *err_info, gboolean for_writing,
                       int file_type);
@@ -200,18 +189,18 @@ cf_callback_add(cf_callback_t func, gpointer user_data)
   cb->cb_fct = func;
   cb->user_data = user_data;
 
-  cf_callbacks = g_list_append(cf_callbacks, cb);
+  cf_callbacks = g_list_prepend(cf_callbacks, cb);
 }
 
 void
-cf_callback_remove(cf_callback_t func)
+cf_callback_remove(cf_callback_t func, gpointer user_data)
 {
   cf_callback_data_t *cb;
   GList              *cb_item = cf_callbacks;
 
   while (cb_item != NULL) {
     cb = (cf_callback_data_t *)cb_item->data;
-    if (cb->cb_fct == func) {
+    if (cb->cb_fct == func && cb->user_data == user_data) {
       cf_callbacks = g_list_remove(cf_callbacks, cb);
       g_free(cb);
       return;
@@ -226,46 +215,12 @@ void
 cf_timestamp_auto_precision(capture_file *cf)
 {
   int i;
-  int prec = timestamp_get_precision();
-
 
   /* don't try to get the file's precision if none is opened */
   if (cf->state == FILE_CLOSED) {
     return;
   }
 
-  /* if we are in auto mode, set precision of current file */
-  if (prec == TS_PREC_AUTO ||
-     prec == TS_PREC_AUTO_SEC ||
-     prec == TS_PREC_AUTO_DSEC ||
-     prec == TS_PREC_AUTO_CSEC ||
-     prec == TS_PREC_AUTO_MSEC ||
-     prec == TS_PREC_AUTO_USEC ||
-     prec == TS_PREC_AUTO_NSEC)
-  {
-    switch(wtap_file_tsprecision(cf->wth)) {
-    case(WTAP_FILE_TSPREC_SEC):
-      timestamp_set_precision(TS_PREC_AUTO_SEC);
-      break;
-    case(WTAP_FILE_TSPREC_DSEC):
-      timestamp_set_precision(TS_PREC_AUTO_DSEC);
-      break;
-    case(WTAP_FILE_TSPREC_CSEC):
-      timestamp_set_precision(TS_PREC_AUTO_CSEC);
-      break;
-    case(WTAP_FILE_TSPREC_MSEC):
-      timestamp_set_precision(TS_PREC_AUTO_MSEC);
-      break;
-    case(WTAP_FILE_TSPREC_USEC):
-      timestamp_set_precision(TS_PREC_AUTO_USEC);
-      break;
-    case(WTAP_FILE_TSPREC_NSEC):
-      timestamp_set_precision(TS_PREC_AUTO_NSEC);
-      break;
-    default:
-      g_assert_not_reached();
-    }
-  }
   /* Set the column widths of those columns that show the time in
      "command-line-specified" format. */
   for (i = 0; i < cf->cinfo.num_cols; i++) {
@@ -276,21 +231,16 @@ cf_timestamp_auto_precision(capture_file *cf)
 }
 
 gulong
-cf_get_computed_elapsed(void)
+cf_get_computed_elapsed(capture_file *cf)
 {
-  return computed_elapsed;
-}
-
-static void reset_elapsed(void)
-{
-  computed_elapsed = 0;
+  return cf->computed_elapsed;
 }
 
 /*
  * GLIB_CHECK_VERSION(2,28,0) adds g_get_real_time which could minimize or
  * replace this
  */
-static void compute_elapsed(GTimeVal *start_time)
+static void compute_elapsed(capture_file *cf, GTimeVal *start_time)
 {
   gdouble  delta_time;
   GTimeVal time_now;
@@ -300,19 +250,19 @@ static void compute_elapsed(GTimeVal *start_time)
   delta_time = (time_now.tv_sec - start_time->tv_sec) * 1e6 +
     time_now.tv_usec - start_time->tv_usec;
 
-  computed_elapsed = (gulong) (delta_time / 1000); /* ms */
+  cf->computed_elapsed = (gulong) (delta_time / 1000); /* ms */
 }
 
-const nstime_t *
+static const nstime_t *
 ws_get_frame_ts(void *data, guint32 frame_num)
 {
   capture_file *cf = (capture_file *) data;
 
-  if (prev_dis && prev_dis->num == frame_num)
-    return &prev_dis->abs_ts;
+  if (cf->prev_dis && cf->prev_dis->num == frame_num)
+    return &cf->prev_dis->abs_ts;
 
-  if (prev_cap && prev_cap->num == frame_num)
-    return &prev_cap->abs_ts;
+  if (cf->prev_cap && cf->prev_cap->num == frame_num)
+    return &cf->prev_cap->abs_ts;
 
   if (cf->frames) {
     frame_data *fd = frame_data_sequence_find(cf->frames, frame_num);
@@ -323,24 +273,34 @@ ws_get_frame_ts(void *data, guint32 frame_num)
   return NULL;
 }
 
-epan_t *
+static const char *
+ws_get_user_comment(void *data, const frame_data *fd)
+{
+  capture_file *cf = (capture_file *) data;
+
+  return cf_get_user_packet_comment(cf, fd);
+}
+
+static epan_t *
 ws_epan_new(capture_file *cf)
 {
   epan_t *epan = epan_new();
 
   epan->data = cf;
   epan->get_frame_ts = ws_get_frame_ts;
+  epan->get_interface_name = cap_file_get_interface_name;
+  epan->get_user_comment = ws_get_user_comment;
 
   return epan;
 }
 
 cf_status_t
-cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
+cf_open(capture_file *cf, const char *fname, unsigned int type, gboolean is_tempfile, int *err)
 {
   wtap  *wth;
   gchar *err_info;
 
-  wth = wtap_open_offline(fname, err, &err_info, TRUE);
+  wth = wtap_open_offline(fname, type, err, &err_info, TRUE);
   if (wth == NULL)
     goto fail;
 
@@ -348,12 +308,16 @@ cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
      and fill in the information for this file. */
   cf_close(cf);
 
+  /* Initialize the packet header. */
+  wtap_phdr_init(&cf->phdr);
+
   /* XXX - we really want to initialize this after we've read all
      the packets, so we know how much we'll ultimately need. */
-  buffer_init(&cf->buf, 1500);
+  ws_buffer_init(&cf->buf, 1500);
 
-  /* Create new epan session for dissection. */
-  epan_free(cf->epan);
+  /* Create new epan session for dissection.
+   * (The old one was freed in cf_close().)
+   */
   cf->epan = ws_epan_new(cf);
 
   /* We're about to start reading the file. */
@@ -373,9 +337,10 @@ cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
   /* No user changes yet. */
   cf->unsaved_changes = FALSE;
 
-  reset_elapsed();
+  cf->computed_elapsed = 0;
 
-  cf->cd_t        = wtap_file_type(cf->wth);
+  cf->cd_t        = wtap_file_type_subtype(cf->wth);
+  cf->open_type   = type;
   cf->linktypes = g_array_sized_new(FALSE, FALSE, (guint) sizeof(int), 1);
   cf->count     = 0;
   cf->packet_comment_count = 0;
@@ -397,10 +362,10 @@ cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
   cf->frames = new_frame_data_sequence();
 
   nstime_set_zero(&cf->elapsed_time);
-  ref = NULL;
-  prev_dis = NULL;
-  prev_cap = NULL;
-  cum_bytes = 0;
+  cf->ref = NULL;
+  cf->prev_dis = NULL;
+  cf->prev_cap = NULL;
+  cf->cum_bytes = 0;
 
   /* Adjust timestamp precision if auto is selected, col width will be adjusted */
   cf_timestamp_auto_precision(cf);
@@ -408,7 +373,7 @@ cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
   packet_list_queue_draw();
   cf_callback_invoke(cf_cb_file_opened, cf);
 
-  if (cf->cd_t == WTAP_FILE_BER) {
+  if (cf->cd_t == WTAP_FILE_TYPE_SUBTYPE_BER) {
     /* tell the BER dissector the file name */
     ber_set_filename(cf->filename);
   }
@@ -439,22 +404,22 @@ cf_add_encapsulation_type(capture_file *cf, int encap)
   g_array_append_val(cf->linktypes, encap);
 }
 
-/*
- * Reset the state for the currently closed file, but don't do the
- * UI callbacks; this is for use in "cf_open()", where we don't
- * want the UI to go from "file open" to "file closed" back to
- * "file open", we want it to go from "old file open" to "new file
- * open and being read".
- *
- * XXX - currently, cf_open() calls cf_close(), rather than
- * cf_reset_state().
- */
-static void
-cf_reset_state(capture_file *cf)
+/* Reset everything to a pristine state */
+void
+cf_close(capture_file *cf)
 {
+  cf->stop_flag = FALSE;
+  if (cf->state == FILE_CLOSED)
+    return; /* Nothing to do */
+
   /* Die if we're in the middle of reading a file. */
   g_assert(cf->state != FILE_READ_IN_PROGRESS);
 
+  cf_callback_invoke(cf_cb_file_closing, cf);
+
+  /* close things, if not already closed before */
+  color_filters_cleanup();
+
   if (cf->wth) {
     wtap_close(cf->wth);
     cf->wth = NULL;
@@ -470,8 +435,14 @@ cf_reset_state(capture_file *cf)
   /* ...which means we have no changes to that file to save. */
   cf->unsaved_changes = FALSE;
 
+  /* no open_routine type */
+  cf->open_type = WTAP_TYPE_AUTO;
+
+  /* Clean up the packet header. */
+  wtap_phdr_cleanup(&cf->phdr);
+
   /* Free up the packet buffer. */
-  buffer_free(&cf->buf);
+  ws_buffer_free(&cf->buf);
 
   dfilter_free(cf->rfcode);
   cf->rfcode = NULL;
@@ -485,6 +456,10 @@ cf_reset_state(capture_file *cf)
     cf->edited_frames = NULL;
   }
 #endif
+  if (cf->frames_user_comments) {
+    g_tree_destroy(cf->frames_user_comments);
+    cf->frames_user_comments = NULL;
+  }
   cf_unselect_packet(cf);   /* nothing to select */
   cf->first_displayed = 0;
   cf->last_displayed = 0;
@@ -496,8 +471,10 @@ cf_reset_state(capture_file *cf)
   cf->finfo_selected = NULL;
 
   /* No frame link-layer types, either. */
-  g_array_free(cf->linktypes, TRUE);
-  cf->linktypes = NULL;
+  if (cf->linktypes != NULL) {
+    g_array_free(cf->linktypes, TRUE);
+    cf->linktypes = NULL;
+  }
 
   /* Clear the packet list. */
   packet_list_freeze();
@@ -509,25 +486,13 @@ cf_reset_state(capture_file *cf)
 
   reset_tap_listeners();
 
+  epan_free(cf->epan);
+  cf->epan = NULL;
+
   /* We have no file open. */
   cf->state = FILE_CLOSED;
-}
-
-/* Reset everything to a pristine state */
-void
-cf_close(capture_file *cf)
-{
-  if (cf->state != FILE_CLOSED) {
-    cf_callback_invoke(cf_cb_file_closing, cf);
 
-  /* close things, if not already closed before */
-    color_filters_cleanup();
-    cf_reset_state(cf);
-    epan_free(cf->epan);
-    cf->epan = NULL;
-
-    cf_callback_invoke(cf_cb_file_closed, cf);
-  }
+  cf_callback_invoke(cf_cb_file_closed, cf);
 }
 
 static float
@@ -569,8 +534,8 @@ cf_read(capture_file *cf, gboolean reloading)
   gchar               *err_info;
   gchar               *name_ptr;
   progdlg_t           *progbar        = NULL;
-  gboolean             stop_flag;
   GTimeVal             start_time;
+  epan_dissect_t       edt;
   dfilter_t           *dfcode;
   volatile gboolean    create_proto_tree;
   guint                tap_flags;
@@ -580,7 +545,7 @@ cf_read(capture_file *cf, gboolean reloading)
    * We assume this will not fail since cf->dfilter is only set in
    * cf_filter IFF the filter was valid.
    */
-  compiled = dfilter_compile(cf->dfilter, &dfcode);
+  compiled = dfilter_compile(cf->dfilter, &dfcode, NULL);
   g_assert(!cf->dfilter || (compiled && dfcode));
 
   /* Get the union of the flags for all tap listeners. */
@@ -604,9 +569,11 @@ cf_read(capture_file *cf, gboolean reloading)
   /* The packet list window will be empty until the file is completly loaded */
   packet_list_freeze();
 
-  stop_flag = FALSE;
+  cf->stop_flag = FALSE;
   g_get_current_time(&start_time);
 
+  epan_dissect_init(&edt, cf->epan, create_proto_tree, FALSE);
+
   TRY {
 #ifdef HAVE_LIBPCAP
     int     displayed_once    = 0;
@@ -652,10 +619,10 @@ cf_read(capture_file *cf, gboolean reloading)
           progbar_val = calc_progbar_val(cf, size, file_pos, status_str, sizeof(status_str));
           if (reloading)
             progbar = delayed_create_progress_dlg(cf->window, "Reloading", name_ptr,
-                TRUE, &stop_flag, &start_time, progbar_val);
+                TRUE, &cf->stop_flag, &start_time, progbar_val);
           else
             progbar = delayed_create_progress_dlg(cf->window, "Loading", name_ptr,
-                TRUE, &stop_flag, &start_time, progbar_val);
+                TRUE, &cf->stop_flag, &start_time, progbar_val);
         }
 
         /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
@@ -681,7 +648,7 @@ cf_read(capture_file *cf, gboolean reloading)
         }
       }
 
-      if (stop_flag) {
+      if (cf->stop_flag) {
         /* 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.
@@ -690,14 +657,14 @@ cf_read(capture_file *cf, gboolean reloading)
            hours even on fast machines) just to see that it was the wrong file. */
         break;
       }
-      read_packet(cf, dfcode, create_proto_tree, cinfo, data_offset);
+      read_packet(cf, dfcode, &edt, cinfo, data_offset);
     }
   }
   CATCH(OutOfMemoryError) {
     simple_message_box(ESD_TYPE_ERROR, NULL,
-                   "Some infos / workarounds can be found at:\n"
-                   "http://wiki.wireshark.org/KnownBugs/OutOfMemory",
-                   "Sorry, but Wireshark has run out of memory and has to terminate now!");
+                   "More information and workarounds can be found at\n"
+                   "https://wiki.wireshark.org/KnownBugs/OutOfMemory",
+                   "Sorry, but Wireshark has run out of memory and has to terminate now.");
 #if 0
     /* Could we close the current capture and free up memory from that? */
 #else
@@ -715,6 +682,8 @@ cf_read(capture_file *cf, gboolean reloading)
     dfilter_free(dfcode);
   }
 
+  epan_dissect_cleanup(&edt);
+
   /* We're done reading the file; destroy the progress bar if it was created. */
   if (progbar != NULL)
     destroy_progress_dlg(progbar);
@@ -730,7 +699,7 @@ cf_read(capture_file *cf, gboolean reloading)
   postseq_cleanup_all_protocols();
 
   /* compute the time it took to load the file */
-  compute_elapsed(&start_time);
+  compute_elapsed(cf, &start_time);
 
   /* Set the file encapsulation type now; we don't know what it is until
      we've looked at all the packets, as we don't know until then whether
@@ -753,13 +722,13 @@ cf_read(capture_file *cf, gboolean reloading)
     packet_list_select_first_row();
   }
 
-  if (stop_flag) {
+  if (cf->stop_flag) {
     simple_message_box(ESD_TYPE_WARN, NULL,
                   "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",
-                  "File loading was cancelled!");
+                  "File loading was cancelled.");
     return CF_READ_ERROR;
   }
 
@@ -772,23 +741,10 @@ cf_read(capture_file *cf, gboolean reloading)
     case WTAP_ERR_UNSUPPORTED:
       simple_error_message_box(
                  "The capture file contains record data that Wireshark doesn't support.\n(%s)",
-                 err_info);
-      g_free(err_info);
-      break;
-
-    case WTAP_ERR_UNSUPPORTED_ENCAP:
-      simple_error_message_box(
-                 "The capture file has a packet with a network type that Wireshark doesn't support.\n(%s)",
-                 err_info);
+                 err_info != NULL ? err_info : "no information supplied");
       g_free(err_info);
       break;
 
-    case WTAP_ERR_CANT_READ:
-      simple_error_message_box(
-                 "An attempt to read from the capture file failed for"
-                 " some unknown reason.");
-      break;
-
     case WTAP_ERR_SHORT_READ:
       simple_error_message_box(
                  "The capture file appears to have been cut short"
@@ -798,14 +754,14 @@ cf_read(capture_file *cf, gboolean reloading)
     case WTAP_ERR_BAD_FILE:
       simple_error_message_box(
                  "The capture file appears to be damaged or corrupt.\n(%s)",
-                 err_info);
+                 err_info != NULL ? err_info : "no information supplied");
       g_free(err_info);
       break;
 
     case WTAP_ERR_DECOMPRESS:
       simple_error_message_box(
-                 "The compressed capture file appears to be damaged or corrupt.\n"
-                 "(%s)", err_info);
+                 "The compressed capture file appears to be damaged or corrupt.\n(%s)",
+                 err_info != NULL ? err_info : "no information supplied");
       g_free(err_info);
       break;
 
@@ -821,22 +777,14 @@ cf_read(capture_file *cf, gboolean reloading)
 }
 
 #ifdef HAVE_LIBPCAP
-cf_status_t
-cf_start_tail(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
-{
-  cf_status_t cf_status;
-
-  cf_status = cf_open(cf, fname, is_tempfile, err);
-  return cf_status;
-}
-
 cf_read_status_t
 cf_continue_tail(capture_file *cf, volatile int to_read, int *err)
 {
   gchar            *err_info;
-  int               newly_displayed_packets = 0;
+  volatile int      newly_displayed_packets = 0;
   dfilter_t        *dfcode;
-  volatile gboolean create_proto_tree;
+  epan_dissect_t    edt;
+  gboolean          create_proto_tree;
   guint             tap_flags;
   gboolean          compiled;
 
@@ -844,7 +792,7 @@ cf_continue_tail(capture_file *cf, volatile int to_read, int *err)
    * We assume this will not fail since cf->dfilter is only set in
    * cf_filter IFF the filter was valid.
    */
-  compiled = dfilter_compile(cf->dfilter, &dfcode);
+  compiled = dfilter_compile(cf->dfilter, &dfcode, NULL);
   g_assert(!cf->dfilter || (compiled && dfcode));
 
   /* Get the union of the flags for all tap listeners. */
@@ -860,6 +808,8 @@ cf_continue_tail(capture_file *cf, volatile int to_read, int *err)
 
   /*g_log(NULL, G_LOG_LEVEL_MESSAGE, "cf_continue_tail: %u new: %u", cf->count, to_read);*/
 
+  epan_dissect_init(&edt, cf->epan, create_proto_tree, FALSE);
+
   TRY {
     gint64 data_offset = 0;
     column_info *cinfo;
@@ -877,7 +827,7 @@ cf_continue_tail(capture_file *cf, volatile int to_read, int *err)
            aren't any packets left to read) exit. */
         break;
       }
-      if (read_packet(cf, dfcode, create_proto_tree, (column_info *) cinfo, data_offset) != -1) {
+      if (read_packet(cf, dfcode, &edt, (column_info *) cinfo, data_offset) != -1) {
         newly_displayed_packets++;
       }
       to_read--;
@@ -885,9 +835,9 @@ cf_continue_tail(capture_file *cf, volatile int to_read, int *err)
   }
   CATCH(OutOfMemoryError) {
     simple_message_box(ESD_TYPE_ERROR, NULL,
-                   "Some infos / workarounds can be found at:\n"
-                   "http://wiki.wireshark.org/KnownBugs/OutOfMemory",
-                   "Sorry, but Wireshark has run out of memory and has to terminate now!");
+                   "More information and workarounds can be found at\n"
+                   "https://wiki.wireshark.org/KnownBugs/OutOfMemory",
+                   "Sorry, but Wireshark has run out of memory and has to terminate now.");
 #if 0
     /* Could we close the current capture and free up memory from that? */
     return CF_READ_ABORTED;
@@ -907,6 +857,8 @@ cf_continue_tail(capture_file *cf, volatile int to_read, int *err)
     dfilter_free(dfcode);
   }
 
+  epan_dissect_cleanup(&edt);
+
   /*g_log(NULL, G_LOG_LEVEL_MESSAGE, "cf_continue_tail: count %u state: %u err: %u",
     cf->count, cf->state, *err);*/
 
@@ -933,10 +885,14 @@ cf_continue_tail(capture_file *cf, volatile int to_read, int *err)
   } else if (*err != 0) {
     /* We got an error reading the capture file.
        XXX - pop up a dialog box instead? */
-    g_warning("Error \"%s\" while reading: \"%s\" (\"%s\")",
-        wtap_strerror(*err), err_info, cf->filename);
-    g_free(err_info);
-
+    if (err_info != NULL) {
+      g_warning("Error \"%s\" while reading \"%s\" (\"%s\")",
+                wtap_strerror(*err), cf->filename, err_info);
+      g_free(err_info);
+    } else {
+      g_warning("Error \"%s\" while reading \"%s\"",
+                wtap_strerror(*err), cf->filename);
+    }
     return CF_READ_ERROR;
   } else
     return CF_READ_OK;
@@ -954,6 +910,7 @@ cf_finish_tail(capture_file *cf, int *err)
   gint64     data_offset;
   dfilter_t *dfcode;
   column_info *cinfo;
+  epan_dissect_t edt;
   gboolean   create_proto_tree;
   guint      tap_flags;
   gboolean   compiled;
@@ -962,7 +919,7 @@ cf_finish_tail(capture_file *cf, int *err)
    * We assume this will not fail since cf->dfilter is only set in
    * cf_filter IFF the filter was valid.
    */
-  compiled = dfilter_compile(cf->dfilter, &dfcode);
+  compiled = dfilter_compile(cf->dfilter, &dfcode, NULL);
   g_assert(!cf->dfilter || (compiled && dfcode));
 
   /* Get the union of the flags for all tap listeners. */
@@ -980,6 +937,8 @@ cf_finish_tail(capture_file *cf, int *err)
   /* Don't freeze/thaw the list when doing live capture */
   /*packet_list_freeze();*/
 
+  epan_dissect_init(&edt, cf->epan, create_proto_tree, FALSE);
+
   while ((wtap_read(cf->wth, err, &err_info, &data_offset))) {
     if (cf->state == FILE_READ_ABORTED) {
       /* Well, the user decided to abort the read.  Break out of the
@@ -987,7 +946,7 @@ cf_finish_tail(capture_file *cf, int *err)
          aren't any packets left to read) exit. */
       break;
     }
-    read_packet(cf, dfcode, create_proto_tree, cinfo, data_offset);
+    read_packet(cf, dfcode, &edt, cinfo, data_offset);
   }
 
   /* Cleanup and release all dfilter resources */
@@ -995,6 +954,8 @@ cf_finish_tail(capture_file *cf, int *err)
     dfilter_free(dfcode);
   }
 
+  epan_dissect_cleanup(&edt);
+
   /* Don't freeze/thaw the list when doing live capture */
   /*packet_list_thaw();*/
 
@@ -1033,10 +994,14 @@ cf_finish_tail(capture_file *cf, int *err)
   if (*err != 0) {
     /* We got an error reading the capture file.
        XXX - pop up a dialog box? */
-
-    g_warning("Error \"%s\" while reading: \"%s\" (\"%s\")",
-        wtap_strerror(*err), err_info, cf->filename);
-    g_free(err_info);
+    if (err_info != NULL) {
+      g_warning("Error \"%s\" while reading \"%s\" (\"%s\")",
+                wtap_strerror(*err), cf->filename, err_info);
+      g_free(err_info);
+    } else {
+      g_warning("Error \"%s\" while reading \"%s\"",
+                wtap_strerror(*err), cf->filename);
+    }
     return CF_READ_ERROR;
   } else {
     return CF_READ_OK;
@@ -1097,13 +1062,6 @@ 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)
@@ -1148,35 +1106,32 @@ 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, gboolean create_proto_tree, column_info *cinfo,
+    epan_dissect_t *edt, dfilter_t *dfcode, column_info *cinfo,
     struct wtap_pkthdr *phdr, const guint8 *buf, gboolean add_to_packet_list)
 {
-  epan_dissect_t  edt;
   gint            row               = -1;
 
   frame_data_set_before_dissect(fdata, &cf->elapsed_time,
-                                &ref, prev_dis);
-  prev_cap = fdata;
-
-  /* Dissect the frame. */
-  epan_dissect_init(&edt, cf->epan, create_proto_tree, FALSE);
+                                &cf->ref, cf->prev_dis);
+  cf->prev_cap = fdata;
 
   if (dfcode != NULL) {
-      epan_dissect_prime_dfilter(&edt, dfcode);
+      epan_dissect_prime_dfilter(edt, dfcode);
   }
 
-  epan_dissect_run_with_taps(&edt, phdr, frame_tvbuff_new(fdata, buf), fdata, cinfo);
+  /* Dissect the frame. */
+  epan_dissect_run_with_taps(edt, cf->cd_t, phdr, frame_tvbuff_new(fdata, buf), fdata, cinfo);
 
   /* If we don't have a display filter, set "passed_dfilter" to 1. */
   if (dfcode != NULL) {
-    fdata->flags.passed_dfilter = dfilter_apply_edt(dfcode, &edt) ? 1 : 0;
+    fdata->flags.passed_dfilter = dfilter_apply_edt(dfcode, edt) ? 1 : 0;
 
     if (fdata->flags.passed_dfilter) {
       /* This frame passed the display filter but it may depend on other
        * (potentially not displayed) frames.  Find those frames and mark them
        * as depended upon.
        */
-      g_slist_foreach(edt.pi.dependent_frames, find_and_mark_frame_depended_upon, cf->frames);
+      g_slist_foreach(edt->pi.dependent_frames, find_and_mark_frame_depended_upon, cf->frames);
     }
   } else
     fdata->flags.passed_dfilter = 1;
@@ -1186,13 +1141,13 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
 
   if (add_to_packet_list) {
     /* We fill the needed columns from new_packet_list */
-      row = packet_list_append(cinfo, fdata, &edt.pi);
+      row = packet_list_append(cinfo, fdata);
   }
 
   if (fdata->flags.passed_dfilter || fdata->flags.ref_time)
   {
-    frame_data_set_after_dissect(fdata, &cum_bytes);
-    prev_dis = fdata;
+    frame_data_set_after_dissect(fdata, &cf->cum_bytes);
+    cf->prev_dis = fdata;
 
     /* If we haven't yet seen the first frame, this is it.
 
@@ -1214,22 +1169,22 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
     cf->last_displayed = fdata->num;
   }
 
-  epan_dissect_cleanup(&edt);
+  epan_dissect_reset(edt);
   return row;
 }
 
 /* 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,
-            gboolean create_proto_tree, column_info *cinfo, gint64 offset)
+read_packet(capture_file *cf, dfilter_t *dfcode, epan_dissect_t *edt,
+            column_info *cinfo, gint64 offset)
 {
   struct wtap_pkthdr *phdr = wtap_phdr(cf->wth);
   const guint8 *buf = wtap_buf_ptr(cf->wth);
   frame_data    fdlocal;
   guint32       framenum;
   frame_data   *fdata;
-  int           passed;
+  gboolean      passed;
   int           row = -1;
 
   /* Add this packet's link-layer encapsulation type to cf->linktypes, if
@@ -1244,16 +1199,17 @@ read_packet(capture_file *cf, dfilter_t *dfcode,
      frames in the file so far. */
   framenum = cf->count + 1;
 
-  frame_data_init(&fdlocal, framenum, phdr, offset, cum_bytes);
+  frame_data_init(&fdlocal, framenum, phdr, offset, cf->cum_bytes);
 
   passed = TRUE;
   if (cf->rfcode) {
-    epan_dissect_t edt;
-    epan_dissect_init(&edt, cf->epan, TRUE, FALSE);
-    epan_dissect_prime_dfilter(&edt, cf->rfcode);
-    epan_dissect_run(&edt, phdr, frame_tvbuff_new(&fdlocal, buf), &fdlocal, NULL);
-    passed = dfilter_apply_edt(cf->rfcode, &edt);
-    epan_dissect_cleanup(&edt);
+    epan_dissect_t rf_edt;
+
+    epan_dissect_init(&rf_edt, cf->epan, TRUE, FALSE);
+    epan_dissect_prime_dfilter(&rf_edt, cf->rfcode);
+    epan_dissect_run(&rf_edt, cf->cd_t, phdr, frame_tvbuff_new(&fdlocal, buf), &fdlocal, NULL);
+    passed = dfilter_apply_edt(cf->rfcode, &rf_edt);
+    epan_dissect_cleanup(&rf_edt);
   }
 
   if (passed) {
@@ -1261,379 +1217,199 @@ read_packet(capture_file *cf, dfilter_t *dfcode,
     fdata = frame_data_sequence_add(cf->frames, &fdlocal);
 
     cf->count++;
-    if (fdlocal.opt_comment != NULL)
+    if (phdr->opt_comment != NULL)
       cf->packet_comment_count++;
     cf->f_datalen = offset + fdlocal.cap_len;
 
     if (!cf->redissecting) {
-      row = add_packet_to_packet_list(fdata, cf, dfcode,
-                                      create_proto_tree, cinfo,
-                                      phdr, buf, TRUE);
+      row = add_packet_to_packet_list(fdata, cf, edt, dfcode,
+                                      cinfo, phdr, buf, TRUE);
     }
   }
 
   return row;
 }
 
-cf_status_t
-cf_merge_files(char **out_filenamep, int in_file_count,
-               char *const *in_filenames, int file_type, gboolean do_append)
-{
-  merge_in_file_t *in_files, *in_file;
-  char            *out_filename;
-  char            *tmpname;
-  int              out_fd;
-  wtap_dumper     *pdh;
-  int              open_err, read_err, write_err, close_err;
-  gchar           *err_info;
-  int              err_fileno;
-  int              i;
-  gboolean         got_read_error     = FALSE, got_write_error = FALSE;
-  gint64           data_offset;
-  progdlg_t       *progbar            = NULL;
-  gboolean         stop_flag;
-  gint64           f_len, file_pos;
-  float            progbar_val;
-  GTimeVal         start_time;
-  gchar            status_str[100];
+
+typedef struct _callback_data_t {
+  gint64           f_len;
   gint64           progbar_nextstep;
   gint64           progbar_quantum;
-  gchar           *display_basename;
-  int              selected_frame_type;
-  gboolean         fake_interface_ids = FALSE;
-
-  /* open the input files */
-  if (!merge_open_in_files(in_file_count, in_filenames, &in_files,
-                           &open_err, &err_info, &err_fileno)) {
-    g_free(in_files);
-    cf_open_failure_alert_box(in_filenames[err_fileno], open_err, err_info,
-                              FALSE, 0);
-    return CF_ERROR;
-  }
-
-  if (*out_filenamep != NULL) {
-    out_filename = *out_filenamep;
-    out_fd = ws_open(out_filename, O_CREAT|O_TRUNC|O_BINARY, 0600);
-    if (out_fd == -1)
-      open_err = errno;
-  } else {
-    out_fd = create_tempfile(&tmpname, "wireshark");
-    if (out_fd == -1)
-      open_err = errno;
-    out_filename = g_strdup(tmpname);
-    *out_filenamep = out_filename;
-  }
-  if (out_fd == -1) {
-    err_info = NULL;
-    merge_close_in_files(in_file_count, in_files);
-    g_free(in_files);
-    cf_open_failure_alert_box(out_filename, open_err, NULL, TRUE, file_type);
-    return CF_ERROR;
-  }
-
-  selected_frame_type = merge_select_frame_type(in_file_count, in_files);
-
-  /* If we are trying to merge a number of libpcap files with different encapsulation types
-   * change the output file type to pcapng and create SHB and IDB:s for the new file use the
-   * interface index stored in in_files per file to change the phdr before writing the datablock.
-   * XXX should it be an option to convert to pcapng?
-   *
-   * We need something similar when merging pcapng files possibly with an option to say
-   * the same interface(s) used in all in files. SHBs comments should be merged together.
-   */
-  if ((selected_frame_type == WTAP_ENCAP_PER_PACKET)&&(file_type == WTAP_FILE_PCAP)) {
-    /* Write output in pcapng format */
-    wtapng_section_t            *shb_hdr;
-    wtapng_iface_descriptions_t *idb_inf, *idb_inf_merge_file;
-    wtapng_if_descr_t            int_data, *file_int_data;
-    GString                     *comment_gstr;
-
-    fake_interface_ids = TRUE;
-    /* Create SHB info */
-    shb_hdr      = wtap_file_get_shb_info(in_files[0].wth);
-    comment_gstr = g_string_new("");
-    g_string_append_printf(comment_gstr, "%s \n",shb_hdr->opt_comment);
-    g_string_append_printf(comment_gstr, "File created by merging: \n");
-    file_type = WTAP_FILE_PCAPNG;
-
-    for (i = 0; i < in_file_count; i++) {
-        g_string_append_printf(comment_gstr, "File%d: %s \n",i+1,in_files[i].filename);
-    }
-    shb_hdr->section_length = -1;
-    /* options */
-    shb_hdr->opt_comment   = g_string_free(comment_gstr, FALSE);  /* NULL if not available */
-    shb_hdr->shb_hardware  = NULL;        /* NULL if not available, UTF-8 string containing the        */
-                                          /*  description of the hardware used to create this section. */
-    shb_hdr->shb_os        = NULL;        /* NULL if not available, UTF-8 string containing the name   */
-                                          /*  of the operating system used to create this section.     */
-    shb_hdr->shb_user_appl = "Wireshark"; /* NULL if not available, UTF-8 string containing the name   */
-                                          /*  of the application used to create this section.          */
-
-    /* create fake IDB info */
-    idb_inf = g_new(wtapng_iface_descriptions_t,1);
-    idb_inf->number_of_interfaces = in_file_count; /* TODO make this the number of DIFFERENT encapsulation types
-                                                    * check that snaplength is the same too?
-                                                    */
-    idb_inf->interface_data = g_array_new(FALSE, FALSE, sizeof(wtapng_if_descr_t));
-
-    for (i = 0; i < in_file_count; i++) {
-      idb_inf_merge_file               = wtap_file_get_idb_info(in_files[i].wth);
-      /* read the interface data from the in file to our combined interfca data */
-      file_int_data = &g_array_index (idb_inf_merge_file->interface_data, wtapng_if_descr_t, 0);
-      int_data.wtap_encap            = file_int_data->wtap_encap;
-      int_data.time_units_per_second = file_int_data->time_units_per_second;
-      int_data.link_type             = file_int_data->link_type;
-      int_data.snap_len              = file_int_data->snap_len;
-      int_data.if_name               = g_strdup(file_int_data->if_name);
-      int_data.opt_comment           = NULL;
-      int_data.if_description        = NULL;
-      int_data.if_speed              = 0;
-      int_data.if_tsresol            = 6;
-      int_data.if_filter_str         = NULL;
-      int_data.bpf_filter_len        = 0;
-      int_data.if_filter_bpf_bytes   = NULL;
-      int_data.if_os                 = NULL;
-      int_data.if_fcslen             = -1;
-      int_data.num_stat_entries      = 0;          /* Number of ISB:s */
-      int_data.interface_statistics  = NULL;
-
-      g_array_append_val(idb_inf->interface_data, int_data);
-      g_free(idb_inf_merge_file);
-
-      /* Set fake interface Id in per file data */
-      in_files[i].interface_id = i;
-    }
+  GTimeVal         start_time;
+  progdlg_t       *progbar;
+  gboolean         stop_flag;
+} callback_data_t;
 
-    pdh = wtap_dump_fdopen_ng(out_fd, file_type,
-                              selected_frame_type,
-                              merge_max_snapshot_length(in_file_count, in_files),
-                              FALSE /* compressed */, shb_hdr, idb_inf /* wtapng_iface_descriptions_t *idb_inf */, &open_err);
 
-    if (pdh == NULL) {
-      ws_close(out_fd);
-      merge_close_in_files(in_file_count, in_files);
-      g_free(in_files);
-      cf_open_failure_alert_box(out_filename, open_err, err_info, TRUE,
-                                file_type);
-      return CF_ERROR;
-    }
+static gboolean
+merge_callback(merge_event event, int num _U_,
+               const merge_in_file_t in_files[], const guint in_file_count,
+               void *data)
+{
+  guint i;
+  callback_data_t *cb_data = (callback_data_t*) data;
 
-  } else {
+  g_assert(cb_data != NULL);
 
-    pdh = wtap_dump_fdopen(out_fd, file_type,
-                           selected_frame_type,
-                           merge_max_snapshot_length(in_file_count, in_files),
-                           FALSE /* compressed */, &open_err);
-    if (pdh == NULL) {
-      ws_close(out_fd);
-      merge_close_in_files(in_file_count, in_files);
-      g_free(in_files);
-      cf_open_failure_alert_box(out_filename, open_err, err_info, TRUE,
-                                file_type);
-      return CF_ERROR;
-    }
-  }
+  switch (event) {
 
-  /* Get the sum of the sizes of all the files. */
-  f_len = 0;
-  for (i = 0; i < in_file_count; i++)
-    f_len += in_files[i].size;
+    case MERGE_EVENT_INPUT_FILES_OPENED:
+      /* do nothing */
+      break;
 
-  /* 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 = f_len/N_PROGBAR_UPDATES;
-  /* Progress so far. */
-  progbar_val = 0.0f;
+    case MERGE_EVENT_FRAME_TYPE_SELECTED:
+      /* do nothing */
+      break;
 
-  stop_flag = FALSE;
-  g_get_current_time(&start_time);
+    case MERGE_EVENT_READY_TO_MERGE:
+      /* Get the sum of the sizes of all the files. */
+      for (i = 0; i < in_file_count; i++)
+        cb_data->f_len += in_files[i].size;
 
-  /* do the merge (or append) */
-  for (;;) {
-    if (do_append)
-      in_file = merge_append_read_packet(in_file_count, in_files, &read_err,
-                                         &err_info);
-    else
-      in_file = merge_read_packet(in_file_count, in_files, &read_err,
-                                  &err_info);
-    if (in_file == NULL) {
-      /* EOF */
-      break;
-    }
+      /* When we reach the value that triggers a progress bar update,
+         bump that value by this amount. */
+      cb_data->progbar_quantum = cb_data->f_len / N_PROGBAR_UPDATES;
 
-    if (read_err != 0) {
-      /* I/O error reading from in_file */
-      got_read_error = TRUE;
+      g_get_current_time(&cb_data->start_time);
       break;
-    }
-
-    /* Get the sum of the data offsets in all of the files. */
-    data_offset = 0;
-    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(NULL, "Merging", "files",
-        FALSE, &stop_flag, &start_time, progbar_val);
-    }
+    case MERGE_EVENT_PACKET_WAS_READ:
+      {
+        gint64 data_offset = 0;
 
-    /* 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;
+        /* Get the sum of the data offsets in all of the files. */
+        data_offset = 0;
         for (i = 0; i < in_file_count; i++)
-          file_pos += wtap_read_so_far(in_files[i].wth);
-        progbar_val = (gfloat) file_pos / (gfloat) f_len;
-        if (progbar_val > 1.0f) {
-          /* Some file probably grew while we were reading it.
-             That "shouldn't happen", so we'll just clip the progress
-             value at 1.0. */
-          progbar_val = 1.0f;
-        }
-        if (progbar != NULL) {
-          g_snprintf(status_str, sizeof(status_str),
-                     "%" G_GINT64_MODIFIER "dKB of %" G_GINT64_MODIFIER "dKB",
-                     file_pos / 1024, f_len / 1024);
-          update_progress_dlg(progbar, progbar_val, status_str);
+          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 (cb_data->progbar == NULL) {
+          cb_data->progbar = delayed_create_progress_dlg(NULL, "Merging", "files",
+            FALSE, &cb_data->stop_flag, &cb_data->start_time, 0.0f);
         }
-        progbar_nextstep += progbar_quantum;
-    }
 
-    if (stop_flag) {
-      /* Well, the user decided to abort the merge. */
-      break;
-    }
+        /* 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 >= cb_data->progbar_nextstep) {
+            float  progbar_val;
+            gint64 file_pos = 0;
+            /* Get the sum of the seek positions in all of the files. */
+            for (i = 0; i < in_file_count; i++)
+              file_pos += wtap_read_so_far(in_files[i].wth);
+
+            progbar_val = (gfloat) file_pos / (gfloat) cb_data->f_len;
+            if (progbar_val > 1.0f) {
+              /* Some file probably grew while we were reading it.
+                 That "shouldn't happen", so we'll just clip the progress
+                 value at 1.0. */
+              progbar_val = 1.0f;
+            }
 
-    /* If we have WTAP_ENCAP_PER_PACKETend the infiles are of type WTAP_FILE_PCAP
-     * we need to set the interface id in the paket header = the interface index we used
-     * in the IDBs interface description for this file(encapsulation type).
-     */
-    if (fake_interface_ids) {
-      struct wtap_pkthdr *phdr;
+            if (cb_data->progbar != NULL) {
+              gchar status_str[100];
+              g_snprintf(status_str, sizeof(status_str),
+                         "%" G_GINT64_MODIFIER "dKB of %" G_GINT64_MODIFIER "dKB",
+                         file_pos / 1024, cb_data->f_len / 1024);
+              update_progress_dlg(cb_data->progbar, progbar_val, status_str);
+            }
+            cb_data->progbar_nextstep += cb_data->progbar_quantum;
+        }
+      }
+      break;
 
-      phdr = wtap_phdr(in_file->wth);
-      phdr->interface_id = in_file->interface_id;
-      phdr->presence_flags = phdr->presence_flags | WTAP_HAS_INTERFACE_ID;
-    }
-    if (!wtap_dump(pdh, wtap_phdr(in_file->wth),
-                   wtap_buf_ptr(in_file->wth), &write_err)) {
-      got_write_error = TRUE;
+    case MERGE_EVENT_DONE:
+      /* We're done merging the files; destroy the progress bar if it was created. */
+      if (cb_data->progbar != NULL)
+        destroy_progress_dlg(cb_data->progbar);
       break;
-    }
   }
 
-  /* We're done merging the files; destroy the progress bar if it was created. */
-  if (progbar != NULL)
-    destroy_progress_dlg(progbar);
+  return cb_data->stop_flag;
+}
 
-  merge_close_in_files(in_file_count, in_files);
-  if (!got_read_error && !got_write_error) {
-    if (!wtap_dump_close(pdh, &write_err))
-      got_write_error = TRUE;
-  } else
-    wtap_dump_close(pdh, &close_err);
 
-  if (got_read_error) {
-    /*
-     * Find the file on which we got the error, and report the error.
-     */
-    for (i = 0; i < in_file_count; i++) {
-      if (in_files[i].state == GOT_ERROR) {
-        /* Put up a message box noting that a read failed somewhere along
-           the line. */
-        display_basename = g_filename_display_basename(in_files[i].filename);
-        switch (read_err) {
-
-        case WTAP_ERR_UNSUPPORTED_ENCAP:
-          simple_error_message_box(
-                     "The capture file %s has a packet with a network type that Wireshark doesn't support.\n(%s)",
-                     display_basename, err_info);
-          g_free(err_info);
-          break;
 
-        case WTAP_ERR_CANT_READ:
-          simple_error_message_box(
-                     "An attempt to read from the capture file %s failed for"
-                     " some unknown reason.", display_basename);
-          break;
+cf_status_t
+cf_merge_files(char **out_filenamep, int in_file_count,
+               char *const *in_filenames, int file_type, gboolean do_append)
+{
+  char                      *out_filename;
+  char                      *tmpname;
+  int                        out_fd;
+  int                        err      = 0;
+  gchar                     *err_info = NULL;
+  int                        err_fileno;
+  merge_result               status;
+  merge_progress_callback_t  cb;
 
-        case WTAP_ERR_SHORT_READ:
-          simple_error_message_box(
-                     "The capture file %s appears to have been cut short"
-                      " in the middle of a packet.", display_basename);
-          break;
 
-        case WTAP_ERR_BAD_FILE:
-          simple_error_message_box(
-                     "The capture file %s appears to be damaged or corrupt.\n(%s)",
-                     display_basename, err_info);
-          g_free(err_info);
-          break;
+  if (*out_filenamep != NULL) {
+    out_filename = *out_filenamep;
+    out_fd = ws_open(out_filename, O_CREAT|O_TRUNC|O_BINARY, 0600);
+    if (out_fd == -1)
+      err = errno;
+  } else {
+    out_fd = create_tempfile(&tmpname, "wireshark");
+    if (out_fd == -1)
+      err = errno;
+    out_filename = g_strdup(tmpname);
+    *out_filenamep = out_filename;
+  }
+  if (out_fd == -1) {
+    cf_open_failure_alert_box(out_filename, err, NULL, TRUE, file_type);
+    return CF_ERROR;
+  }
 
-        case WTAP_ERR_DECOMPRESS:
-          simple_error_message_box(
-                     "The compressed capture file %s appears to be damaged or corrupt.\n"
-                     "(%s)", display_basename, err_info);
-          g_free(err_info);
-          break;
+  /* prepare our callback routine */
+  cb.callback_func = merge_callback;
+  cb.data = g_malloc0(sizeof(callback_data_t));
 
-        default:
-          simple_error_message_box(
-                     "An error occurred while reading the"
-                     " capture file %s: %s.",
-                     display_basename,  wtap_strerror(read_err));
-          break;
-        }
-        g_free(display_basename);
-      }
-    }
-  }
+  /* merge the files */
+  status = merge_files(out_fd, out_filename, file_type,
+                       (const char *const *) in_filenames, in_file_count,
+                       do_append, IDB_MERGE_MODE_ALL_SAME, 0 /* snaplen */,
+                       "Wireshark", &cb, &err, &err_info, &err_fileno);
 
-  if (got_write_error) {
-    /* Put up an alert box for the write error. */
-    if (write_err < 0) {
-      /* Wiretap error. */
-      switch (write_err) {
+  g_free(cb.data);
 
-      case WTAP_ERR_UNSUPPORTED_ENCAP:
-        /*
-         * This is a problem with the particular frame we're writing;
-         * note that, and give the frame number.
-         */
-        display_basename = g_filename_display_basename(in_file->filename);
-        simple_error_message_box(
-                      "Frame %u of \"%s\" has a network type that can't be saved in a \"%s\" file.",
-                      in_file->packet_num, display_basename,
-                      wtap_file_type_string(file_type));
-        g_free(display_basename);
-        break;
+  switch (status) {
+    case MERGE_OK:
+      break;
 
-      default:
-        display_basename = g_filename_display_basename(out_filename);
-        simple_error_message_box(
-                      "An error occurred while writing to the file \"%s\": %s.",
-                      out_filename, wtap_strerror(write_err));
-        g_free(display_basename);
-        break;
-      }
-    } else {
-      /* OS error. */
-      write_failure_alert_box(out_filename, write_err);
-    }
+    case MERGE_USER_ABORTED:
+      /* this isn't really an error, though we will return CF_ERROR later */
+      break;
+
+    case MERGE_ERR_CANT_OPEN_INFILE:
+      cf_open_failure_alert_box(in_filenames[err_fileno], err, err_info,
+                                FALSE, 0);
+      break;
+
+    case MERGE_ERR_CANT_OPEN_OUTFILE:
+      cf_open_failure_alert_box(out_filename, err, err_info, TRUE,
+                                file_type);
+      ws_close(out_fd);
+      break;
+
+    case MERGE_ERR_CANT_READ_INFILE:      /* fall through */
+    case MERGE_ERR_BAD_PHDR_INTERFACE_ID:
+    case MERGE_ERR_CANT_WRITE_OUTFILE:
+    case MERGE_ERR_CANT_CLOSE_OUTFILE:
+    default:
+      simple_error_message_box("%s", err_info ? err_info : "unknown error");
+      break;
   }
 
-  if (got_read_error || got_write_error || stop_flag) {
+  g_free(err_info);
+
+  if (status != MERGE_OK) {
     /* 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. */
@@ -1648,6 +1424,7 @@ cf_filter_packets(capture_file *cf, gchar *dftext, gboolean force)
   const char *filter_new = dftext ? dftext : "";
   const char *filter_old = cf->dfilter ? cf->dfilter : "";
   dfilter_t  *dfcode;
+  gchar      *err_msg;
   GTimeVal    start_time;
 
   /* if new filter equals old one, do nothing unless told to do so */
@@ -1667,12 +1444,13 @@ cf_filter_packets(capture_file *cf, gchar *dftext, gboolean force)
      * and try to compile it.
      */
     dftext = g_strdup(dftext);
-    if (!dfilter_compile(dftext, &dfcode)) {
+    if (!dfilter_compile(dftext, &dfcode, &err_msg)) {
       /* The attempt failed; report an error. */
       simple_message_box(ESD_TYPE_ERROR, NULL,
           "See the help for a description of the display filter syntax.",
           "\"%s\" isn't a valid display filter: %s",
-          dftext, dfilter_error_msg);
+          dftext, err_msg);
+      g_free(err_msg);
       g_free(dftext);
       return CF_ERROR;
     }
@@ -1714,12 +1492,14 @@ cf_reftime_packets(capture_file *cf)
 void
 cf_redissect_packets(capture_file *cf)
 {
-  rescan_packets(cf, "Reprocessing", "all packets", TRUE);
+  if (cf->state != FILE_CLOSED) {
+    rescan_packets(cf, "Reprocessing", "all packets", TRUE);
+  }
 }
 
 gboolean
-cf_read_frame_r(capture_file *cf, frame_data *fdata,
-                struct wtap_pkthdr *phdr, Buffer *buf)
+cf_read_record_r(capture_file *cf, const frame_data *fdata,
+                 struct wtap_pkthdr *phdr, Buffer *buf)
 {
   int    err;
   gchar *err_info;
@@ -1731,31 +1511,25 @@ cf_read_frame_r(capture_file *cf, frame_data *fdata,
     const modified_frame_data *frame = (const modified_frame_data *) g_tree_lookup(cf->edited_frames, GINT_TO_POINTER(fdata->num));
 
     if (!frame) {
-      simple_error_message_box("fdata->file_off == -1, but can't find modified frame!");
+      simple_error_message_box("fdata->file_off == -1, but can't find modified frame.");
       return FALSE;
     }
 
     *phdr = frame->phdr;
-    buffer_assure_space(buf, frame->phdr.caplen);
-    memcpy(buffer_start_ptr(buf), frame->pd, frame->phdr.caplen);
+    ws_buffer_assure_space(buf, frame->phdr.caplen);
+    memcpy(ws_buffer_start_ptr(buf), frame->pd, frame->phdr.caplen);
     return TRUE;
   }
 #endif
 
-  if (!wtap_seek_read(cf->wth, fdata->file_off, phdr, buf,
-                      fdata->cap_len, &err, &err_info)) {
+  if (!wtap_seek_read(cf->wth, fdata->file_off, phdr, buf, &err, &err_info)) {
     display_basename = g_filename_display_basename(cf->filename);
     switch (err) {
 
-    case WTAP_ERR_UNSUPPORTED_ENCAP:
-      simple_error_message_box("The file \"%s\" has a packet with a network type that Wireshark doesn't support.\n(%s)",
-                 display_basename, err_info);
-      g_free(err_info);
-      break;
-
     case WTAP_ERR_BAD_FILE:
       simple_error_message_box("An error occurred while reading from the file \"%s\": %s.\n(%s)",
-                 display_basename, wtap_strerror(err), err_info);
+                 display_basename, wtap_strerror(err),
+                 err_info != NULL ? err_info : "no information supplied");
       g_free(err_info);
       break;
 
@@ -1772,9 +1546,9 @@ cf_read_frame_r(capture_file *cf, frame_data *fdata,
 }
 
 gboolean
-cf_read_frame(capture_file *cf, frame_data *fdata)
+cf_read_record(capture_file *cf, frame_data *fdata)
 {
-  return cf_read_frame_r(cf, fdata, &cf->phdr, &cf->buf);
+  return cf_read_record_r(cf, fdata, &cf->phdr, &cf->buf);
 }
 
 /* Rescan the list of packets, reconstructing the CList.
@@ -1796,7 +1570,6 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item, gb
   guint32     framenum;
   frame_data *fdata;
   progdlg_t  *progbar = NULL;
-  gboolean    stop_flag;
   int         count;
   frame_data *selected_frame, *preceding_frame, *following_frame, *prev_frame;
   int         selected_frame_num, preceding_frame_num, following_frame_num, prev_frame_num;
@@ -1806,6 +1579,7 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item, gb
   gchar       status_str[100];
   int         progbar_nextstep;
   int         progbar_quantum;
+  epan_dissect_t  edt;
   dfilter_t  *dfcode;
   column_info *cinfo;
   gboolean    create_proto_tree;
@@ -1818,7 +1592,7 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item, gb
    * We assume this will not fail since cf->dfilter is only set in
    * cf_filter IFF the filter was valid.
    */
-  compiled = dfilter_compile(cf->dfilter, &dfcode);
+  compiled = dfilter_compile(cf->dfilter, &dfcode, NULL);
   g_assert(!cf->dfilter || (compiled && dfcode));
 
   /* Get the union of the flags for all tap listeners. */
@@ -1854,6 +1628,7 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item, gb
     /* 'reset' dissection session */
     epan_free(cf->epan);
     cf->epan = ws_epan_new(cf);
+    cf->cinfo.epan = cf->epan;
 
     /* We need to redissect the packets so we have to discard our old
      * packet list store. */
@@ -1871,10 +1646,10 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item, gb
   /* 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. */
-  ref = NULL;
-  prev_dis = NULL;
-  prev_cap = NULL;
-  cum_bytes = 0;
+  cf->ref = NULL;
+  cf->prev_dis = NULL;
+  cf->prev_cap = NULL;
+  cf->cum_bytes = 0;
 
   /* Update the progress bar when it gets to this value. */
   progbar_nextstep = 0;
@@ -1886,7 +1661,7 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item, gb
   /* Progress so far. */
   progbar_val = 0.0f;
 
-  stop_flag = FALSE;
+  cf->stop_flag = FALSE;
   g_get_current_time(&start_time);
 
   /* no previous row yet */
@@ -1901,6 +1676,9 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item, gb
   selected_frame_seen = FALSE;
 
   frames_count = cf->count;
+
+  epan_dissect_init(&edt, cf->epan, create_proto_tree, FALSE);
+
   for (framenum = 1; framenum <= frames_count; framenum++) {
     fdata = frame_data_sequence_find(cf->frames, framenum);
 
@@ -1911,7 +1689,8 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item, gb
        time in order to get to the next progress bar step). */
     if (progbar == NULL)
       progbar = delayed_create_progress_dlg(cf->window, action, action_item, TRUE,
-                                            &stop_flag, &start_time,
+                                            &cf->stop_flag,
+                                            &start_time,
                                             progbar_val);
 
     /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
@@ -1935,7 +1714,7 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item, gb
       progbar_nextstep += progbar_quantum;
     }
 
-    if (stop_flag) {
+    if (cf->stop_flag) {
       /* Well, the user decided to abort the filtering.  Just stop.
 
          XXX - go back to the previous filter?  Users probably just
@@ -1965,7 +1744,7 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item, gb
     /* Frame dependencies from the previous dissection/filtering are no longer valid. */
     fdata->flags.dependent_of_displayed = 0;
 
-    if (!cf_read_frame(cf, fdata))
+    if (!cf_read_record(cf, fdata))
       break; /* error reading the frame */
 
     /* If the previous frame is displayed, and we haven't yet seen the
@@ -1975,9 +1754,10 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item, gb
       preceding_frame_num = prev_frame_num;
       preceding_frame = prev_frame;
     }
-    add_packet_to_packet_list(fdata, cf, dfcode, create_proto_tree,
+
+    add_packet_to_packet_list(fdata, cf, &edt, dfcode,
                                     cinfo, &cf->phdr,
-                                    buffer_start_ptr(&cf->buf),
+                                    ws_buffer_start_ptr(&cf->buf),
                                     add_to_packet_list);
 
     /* If this frame is displayed, and this is the first frame we've
@@ -2000,6 +1780,8 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item, gb
     prev_frame = fdata;
   }
 
+  epan_dissect_cleanup(&edt);
+
   /* We are done redissecting the packet list. */
   cf->redissecting = FALSE;
 
@@ -2030,7 +1812,7 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item, gb
     packet_list_recreate_visible_rows();
 
   /* Compute the time it took to filter the file */
-  compute_elapsed(&start_time);
+  compute_elapsed(cf, &start_time);
 
   packet_list_thaw();
 
@@ -2088,7 +1870,7 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item, gb
            so we can't select it. */
         simple_message_box(ESD_TYPE_INFO, NULL,
                            "The capture file is probably not fully dissected.",
-                           "End of capture exceeded!");
+                           "End of capture exceeded.");
       }
     }
   }
@@ -2110,15 +1892,15 @@ ref_time_packets(capture_file *cf)
   frame_data *fdata;
   nstime_t rel_ts;
 
-  ref = NULL;
-  prev_dis = NULL;
-  cum_bytes = 0;
+  cf->ref = NULL;
+  cf->prev_dis = NULL;
+  cf->cum_bytes = 0;
 
   for (framenum = 1; framenum <= cf->count; framenum++) {
     fdata = frame_data_sequence_find(cf->frames, framenum);
 
     /* just add some value here until we know if it is being displayed or not */
-    fdata->cum_bytes = cum_bytes + fdata->pkt_len;
+    fdata->cum_bytes = cf->cum_bytes + fdata->pkt_len;
 
     /*
      *Timestamps
@@ -2127,24 +1909,24 @@ ref_time_packets(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 (ref == NULL)
-        ref = fdata;
+    if (cf->ref == NULL)
+        cf->ref = fdata;
       /* if this frames is marked as a reference time frame, reset
         firstsec and firstusec to this frame */
     if (fdata->flags.ref_time)
-        ref = fdata;
+        cf->ref = fdata;
 
     /* If we don't have the time stamp of the previous displayed packet,
      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 (prev_dis == NULL) {
-        prev_dis = fdata;
+    if (cf->prev_dis == NULL) {
+        cf->prev_dis = fdata;
     }
 
     /* Get the time elapsed between the first packet and this packet. */
-    fdata->frame_ref_num = (fdata != ref) ? ref->num : 0;
-    nstime_delta(&rel_ts, &fdata->abs_ts, &ref->abs_ts);
+    fdata->frame_ref_num = (fdata != cf->ref) ? cf->ref->num : 0;
+    nstime_delta(&rel_ts, &fdata->abs_ts, &cf->ref->abs_ts);
 
     /* If it's greater than the current elapsed time, set the elapsed time
      to it (we check for "greater than" so as not to be confused by
@@ -2157,8 +1939,8 @@ ref_time_packets(capture_file *cf)
     /* If this frame is displayed, get the time elapsed between the
      previous displayed packet and this packet. */
     if ( fdata->flags.passed_dfilter ) {
-        fdata->prev_dis_num = prev_dis->num;
-        prev_dis = fdata;
+        fdata->prev_dis_num = cf->prev_dis->num;
+        cf->prev_dis = fdata;
     }
 
     /*
@@ -2167,14 +1949,14 @@ ref_time_packets(capture_file *cf)
     if ( (fdata->flags.passed_dfilter) || (fdata->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 */
+        even if they don't pass the display filter */
         if (fdata->flags.ref_time) {
             /* if this was a TIME REF frame we should reset the cum_bytes field */
-            cum_bytes = fdata->pkt_len;
-            fdata->cum_bytes =  cum_bytes;
+            cf->cum_bytes = fdata->pkt_len;
+            fdata->cum_bytes = cf->cum_bytes;
         } else {
             /* increase cum_bytes with this packets length */
-            cum_bytes += fdata->pkt_len;
+            cf->cum_bytes += fdata->pkt_len;
         }
     }
   }
@@ -2187,7 +1969,7 @@ typedef enum {
 } psp_return_t;
 
 static psp_return_t
-process_specified_packets(capture_file *cf, packet_range_t *range,
+process_specified_records(capture_file *cf, packet_range_t *range,
     const char *string1, const char *string2, gboolean terminate_is_stop,
     gboolean (*callback)(capture_file *, frame_data *,
                          struct wtap_pkthdr *, const guint8 *, void *),
@@ -2201,7 +1983,6 @@ process_specified_packets(capture_file *cf, packet_range_t *range,
   progdlg_t       *progbar = NULL;
   int              progbar_count;
   float            progbar_val;
-  gboolean         progbar_stop_flag;
   GTimeVal         progbar_start_time;
   gchar            progbar_status_str[100];
   int              progbar_nextstep;
@@ -2209,7 +1990,8 @@ process_specified_packets(capture_file *cf, packet_range_t *range,
   range_process_e  process_this;
   struct wtap_pkthdr phdr;
 
-  buffer_init(&buf, 1500);
+  wtap_phdr_init(&phdr);
+  ws_buffer_init(&buf, 1500);
 
   /* Update the progress bar when it gets to this value. */
   progbar_nextstep = 0;
@@ -2221,7 +2003,7 @@ process_specified_packets(capture_file *cf, packet_range_t *range,
   /* Progress so far. */
   progbar_val = 0.0f;
 
-  progbar_stop_flag = FALSE;
+  cf->stop_flag = FALSE;
   g_get_current_time(&progbar_start_time);
 
   if (range != NULL)
@@ -2240,7 +2022,7 @@ process_specified_packets(capture_file *cf, packet_range_t *range,
     if (progbar == NULL)
       progbar = delayed_create_progress_dlg(cf->window, string1, string2,
                                             terminate_is_stop,
-                                            &progbar_stop_flag,
+                                            &cf->stop_flag,
                                             &progbar_start_time,
                                             progbar_val);
 
@@ -2265,7 +2047,7 @@ process_specified_packets(capture_file *cf, packet_range_t *range,
       progbar_nextstep += progbar_quantum;
     }
 
-    if (progbar_stop_flag) {
+    if (cf->stop_flag) {
       /* Well, the user decided to abort the operation.  Just stop,
          and arrange to return PSP_STOPPED to our caller, so they know
          it was stopped explicitly. */
@@ -2288,13 +2070,13 @@ process_specified_packets(capture_file *cf, packet_range_t *range,
     }
 
     /* Get the packet */
-    if (!cf_read_frame_r(cf, fdata, &phdr, &buf)) {
+    if (!cf_read_record_r(cf, fdata, &phdr, &buf)) {
       /* Attempt to get the packet failed. */
       ret = PSP_FAILED;
       break;
     }
     /* Process the packet */
-    if (!callback(cf, fdata, &phdr, buffer_start_ptr(&buf), callback_args)) {
+    if (!callback(cf, fdata, &phdr, ws_buffer_start_ptr(&buf), callback_args)) {
       /* Callback failed.  We assume it reported the error appropriately. */
       ret = PSP_FAILED;
       break;
@@ -2306,27 +2088,26 @@ process_specified_packets(capture_file *cf, packet_range_t *range,
   if (progbar != NULL)
     destroy_progress_dlg(progbar);
 
-  buffer_free(&buf);
+  wtap_phdr_cleanup(&phdr);
+  ws_buffer_free(&buf);
 
   return ret;
 }
 
 typedef struct {
-  gboolean     construct_protocol_tree;
+  epan_dissect_t edt;
   column_info *cinfo;
 } retap_callback_args_t;
 
 static gboolean
-retap_packet(capture_file *cf _U_, frame_data *fdata,
+retap_packet(capture_file *cf, frame_data *fdata,
              struct wtap_pkthdr *phdr, const guint8 *pd,
              void *argsp)
 {
   retap_callback_args_t *args = (retap_callback_args_t *)argsp;
-  epan_dissect_t         edt;
 
-  epan_dissect_init(&edt, cf->epan, args->construct_protocol_tree, FALSE);
-  epan_dissect_run_with_taps(&edt, phdr, frame_tvbuff_new(fdata, pd), fdata, args->cinfo);
-  epan_dissect_cleanup(&edt);
+  epan_dissect_run_with_taps(&args->edt, cf->cd_t, phdr, frame_tvbuff_new(fdata, pd), fdata, args->cinfo);
+  epan_dissect_reset(&args->edt);
 
   return TRUE;
 }
@@ -2336,8 +2117,17 @@ cf_retap_packets(capture_file *cf)
 {
   packet_range_t        range;
   retap_callback_args_t callback_args;
+  gboolean              construct_protocol_tree;
   gboolean              filtering_tap_listeners;
   guint                 tap_flags;
+  psp_return_t          ret;
+
+  /* Presumably the user closed the capture file. */
+  if (cf == NULL) {
+    return CF_READ_ABORTED;
+  }
+
+  cf_callback_invoke(cf_cb_file_retap_started, cf);
 
   /* Do we have any tap listeners with filters? */
   filtering_tap_listeners = have_filtering_tap_listeners();
@@ -2346,8 +2136,8 @@ cf_retap_packets(capture_file *cf)
 
   /* If any tap listeners have filters, or require the protocol tree,
      construct the protocol tree. */
-  callback_args.construct_protocol_tree = filtering_tap_listeners ||
-                                          (tap_flags & TL_REQUIRES_PROTO_TREE);
+  construct_protocol_tree = filtering_tap_listeners ||
+                            (tap_flags & TL_REQUIRES_PROTO_TREE);
 
   /* If any tap listeners require the columns, construct them. */
   callback_args.cinfo = (tap_flags & TL_REQUIRES_COLUMNS) ? &cf->cinfo : NULL;
@@ -2355,13 +2145,22 @@ cf_retap_packets(capture_file *cf)
   /* Reset the tap listeners. */
   reset_tap_listeners();
 
+  epan_dissect_init(&callback_args.edt, cf->epan, construct_protocol_tree, FALSE);
+
   /* Iterate through the list of packets, dissecting all packets and
      re-running the taps. */
   packet_range_init(&range, cf);
   packet_range_process_init(&range);
-  switch (process_specified_packets(cf, &range, "Recalculating statistics on",
-                                    "all packets", TRUE, retap_packet,
-                                    &callback_args)) {
+
+  ret = process_specified_records(cf, &range, "Recalculating statistics on",
+                                  "all packets", TRUE, retap_packet,
+                                  &callback_args);
+
+  epan_dissect_cleanup(&callback_args.edt);
+
+  cf_callback_invoke(cf_cb_file_retap_finished, cf);
+
+  switch (ret) {
   case PSP_FINISHED:
     /* Completed successfully. */
     return CF_READ_OK;
@@ -2392,6 +2191,7 @@ typedef struct {
   gint         *col_widths;
   int           num_visible_cols;
   gint         *visible_cols;
+  epan_dissect_t edt;
 } print_callback_args_t;
 
 static gboolean
@@ -2400,31 +2200,23 @@ print_packet(capture_file *cf, frame_data *fdata,
              void *argsp)
 {
   print_callback_args_t *args = (print_callback_args_t *)argsp;
-  epan_dissect_t  edt;
   int             i;
   char           *cp;
   int             line_len;
   int             column_len;
   int             cp_off;
-  gboolean        proto_tree_needed;
   char            bookmark_name[9+10+1];  /* "__frameNNNNNNNNNN__\0" */
   char            bookmark_title[6+10+1]; /* "Frame NNNNNNNNNN__\0"  */
-
-  /* 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 || have_custom_cols(&cf->cinfo);
-  epan_dissect_init(&edt, cf->epan, proto_tree_needed, proto_tree_needed);
+  col_item_t*     col_item;
 
   /* Fill in the column information if we're printing the summary
      information. */
   if (args->print_args->print_summary) {
-    col_custom_prime_edt(&edt, &cf->cinfo);
-    epan_dissect_run(&edt, phdr, frame_tvbuff_new(fdata, pd), fdata, &cf->cinfo);
-    epan_dissect_fill_in_columns(&edt, FALSE, TRUE);
+    col_custom_prime_edt(&args->edt, &cf->cinfo);
+    epan_dissect_run(&args->edt, cf->cd_t, phdr, frame_tvbuff_new(fdata, pd), fdata, &cf->cinfo);
+    epan_dissect_fill_in_columns(&args->edt, FALSE, TRUE);
   } else
-    epan_dissect_run(&edt, phdr, frame_tvbuff_new(fdata, pd), fdata, NULL);
+    epan_dissect_run(&args->edt, cf->cd_t, phdr, frame_tvbuff_new(fdata, pd), fdata, NULL);
 
   if (args->print_formfeed) {
     if (!new_page(args->print_args->stream))
@@ -2453,8 +2245,9 @@ print_packet(capture_file *cf, frame_data *fdata,
     cp = &args->line_buf[0];
     line_len = 0;
     for (i = 0; i < args->num_visible_cols; i++) {
+      col_item = &cf->cinfo.columns[args->visible_cols[i]];
       /* Find the length of the string for this column. */
-      column_len = (int) strlen(cf->cinfo.col_data[args->visible_cols[i]]);
+      column_len = (int) strlen(col_item->col_data);
       if (args->col_widths[i] > column_len)
          column_len = args->col_widths[i];
 
@@ -2469,10 +2262,10 @@ print_packet(capture_file *cf, frame_data *fdata,
       }
 
       /* Right-justify the packet number column. */
-      if (cf->cinfo.col_fmt[args->visible_cols[i]] == COL_NUMBER)
-        g_snprintf(cp, column_len+1, "%*s", args->col_widths[i], cf->cinfo.col_data[args->visible_cols[i]]);
+      if (col_item->col_fmt == COL_NUMBER)
+        g_snprintf(cp, column_len+1, "%*s", args->col_widths[i], col_item->col_data);
       else
-        g_snprintf(cp, column_len+1, "%-*s", args->col_widths[i], cf->cinfo.col_data[args->visible_cols[i]]);
+        g_snprintf(cp, column_len+1, "%-*s", args->col_widths[i], col_item->col_data);
       cp += column_len;
       if (i != args->num_visible_cols - 1)
         *cp++ = ' ';
@@ -2507,7 +2300,7 @@ print_packet(capture_file *cf, frame_data *fdata,
     }
 
     /* Print the information in that tree. */
-    if (!proto_tree_print(args->print_args, &edt, args->print_args->stream))
+    if (!proto_tree_print(args->print_args, &args->edt, NULL, args->print_args->stream))
       goto fail;
 
     /* Print a blank line if we print anything after this (aka more than one packet). */
@@ -2524,7 +2317,7 @@ print_packet(capture_file *cf, frame_data *fdata,
         goto fail;
     }
     /* Print the full packet data as hex. */
-    if (!print_hex_data(args->print_args->stream, &edt))
+    if (!print_hex_data(args->print_args->stream, &args->edt))
       goto fail;
 
     /* Print a blank line if we print anything after this (aka more than one packet). */
@@ -2535,7 +2328,7 @@ print_packet(capture_file *cf, frame_data *fdata,
         args->print_header_line = TRUE;
   } /* if (args->print_args->print_dissections != print_dissections_none) */
 
-  epan_dissect_cleanup(&edt);
+  epan_dissect_reset(&args->edt);
 
   /* do we want to have a formfeed between each packet from now on? */
   if (args->print_args->print_formfeed) {
@@ -2545,7 +2338,7 @@ print_packet(capture_file *cf, frame_data *fdata,
   return TRUE;
 
 fail:
-  epan_dissect_cleanup(&edt);
+  epan_dissect_reset(&args->edt);
   return FALSE;
 }
 
@@ -2560,6 +2353,7 @@ cf_print_packets(capture_file *cf, print_args_t *print_args)
   psp_return_t  ret;
   GList        *clp;
   fmt_data     *cfmt;
+  gboolean      proto_tree_needed;
 
   callback_args.print_args = print_args;
   callback_args.print_header_line = print_args->print_col_headings;
@@ -2573,7 +2367,7 @@ cf_print_packets(capture_file *cf, print_args_t *print_args)
   callback_args.num_visible_cols = 0;
   callback_args.visible_cols = NULL;
 
-  if (!print_preamble(print_args->stream, cf->filename, wireshark_svnversion)) {
+  if (!print_preamble(print_args->stream, cf->filename, get_ws_vcs_version_info())) {
     destroy_print_stream(print_args->stream);
     return CF_PRINT_WRITE_ERROR;
   }
@@ -2623,14 +2417,14 @@ cf_print_packets(capture_file *cf, print_args_t *print_args)
       if (i == last_visible_col)
         callback_args.col_widths[visible_col_count] = 0;
       else {
-        callback_args.col_widths[visible_col_count] = (gint) strlen(cf->cinfo.col_title[i]);
+        callback_args.col_widths[visible_col_count] = (gint) strlen(cf->cinfo.columns[i].col_title);
         data_width = get_column_char_width(get_column_format(i));
         if (data_width > callback_args.col_widths[visible_col_count])
           callback_args.col_widths[visible_col_count] = data_width;
       }
 
       /* Find the length of the string for this column. */
-      column_len = (int) strlen(cf->cinfo.col_title[i]);
+      column_len = (int) strlen(cf->cinfo.columns[i].col_title);
       if (callback_args.col_widths[i] > column_len)
         column_len = callback_args.col_widths[visible_col_count];
 
@@ -2647,9 +2441,9 @@ cf_print_packets(capture_file *cf, print_args_t *print_args)
 
       /* Right-justify the packet number column. */
 /*      if (cf->cinfo.col_fmt[i] == COL_NUMBER)
-        g_snprintf(cp, column_len+1, "%*s", callback_args.col_widths[visible_col_count], cf->cinfo.col_title[i]);
+        g_snprintf(cp, column_len+1, "%*s", callback_args.col_widths[visible_col_count], cf->cinfo.columns[i].col_title);
       else*/
-      g_snprintf(cp, column_len+1, "%-*s", callback_args.col_widths[visible_col_count], cf->cinfo.col_title[i]);
+      g_snprintf(cp, column_len+1, "%-*s", callback_args.col_widths[visible_col_count], cf->cinfo.columns[i].col_title);
       cp += column_len;
       if (i != cf->cinfo.num_cols - 1)
         *cp++ = ' ';
@@ -2664,12 +2458,21 @@ cf_print_packets(capture_file *cf, print_args_t *print_args)
     callback_args.line_buf = (char *)g_malloc(callback_args.line_buf_len + 1);
   } /* if (print_summary) */
 
+  /* 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 =
+      callback_args.print_args->print_dissections != print_dissections_none ||
+      callback_args.print_args->print_hex ||
+      have_custom_cols(&cf->cinfo);
+  epan_dissect_init(&callback_args.edt, cf->epan, proto_tree_needed, proto_tree_needed);
+
   /* Iterate through the list of packets, printing the packets we were
      told to print. */
-  ret = process_specified_packets(cf, &print_args->range, "Printing",
+  ret = process_specified_records(cf, &print_args->range, "Printing",
                                   "selected packets", TRUE, print_packet,
                                   &callback_args);
-
+  epan_dissect_cleanup(&callback_args.edt);
   g_free(callback_args.header_line_buf);
   g_free(callback_args.line_buf);
   g_free(callback_args.col_widths);
@@ -2712,29 +2515,33 @@ cf_print_packets(capture_file *cf, print_args_t *print_args)
   return CF_PRINT_OK;
 }
 
+typedef struct {
+  FILE *fh;
+  epan_dissect_t edt;
+} write_packet_callback_args_t;
+
 static gboolean
-write_pdml_packet(capture_file *cf _U_, frame_data *fdata,
+write_pdml_packet(capture_file *cf, frame_data *fdata,
                   struct wtap_pkthdr *phdr, const guint8 *pd,
           void *argsp)
 {
-  FILE           *fh = (FILE *)argsp;
-  epan_dissect_t  edt;
+  write_packet_callback_args_t *args = (write_packet_callback_args_t *)argsp;
 
   /* Create the protocol tree, but don't fill in the column information. */
-  epan_dissect_init(&edt, cf->epan, TRUE, TRUE);
-  epan_dissect_run(&edt, phdr, frame_tvbuff_new(fdata, pd), fdata, NULL);
+  epan_dissect_run(&args->edt, cf->cd_t, phdr, frame_tvbuff_new(fdata, pd), fdata, NULL);
 
   /* Write out the information in that tree. */
-  proto_tree_write_pdml(&edt, fh);
+  write_pdml_proto_tree(&args->edt, args->fh);
 
-  epan_dissect_cleanup(&edt);
+  epan_dissect_reset(&args->edt);
 
-  return !ferror(fh);
+  return !ferror(args->fh);
 }
 
 cf_print_status_t
 cf_write_pdml_packets(capture_file *cf, print_args_t *print_args)
 {
+  write_packet_callback_args_t callback_args;
   FILE         *fh;
   psp_return_t  ret;
 
@@ -2748,11 +2555,16 @@ cf_write_pdml_packets(capture_file *cf, print_args_t *print_args)
     return CF_PRINT_WRITE_ERROR;
   }
 
+  callback_args.fh = fh;
+  epan_dissect_init(&callback_args.edt, cf->epan, TRUE, TRUE);
+
   /* Iterate through the list of packets, printing the packets we were
      told to print. */
-  ret = process_specified_packets(cf, &print_args->range, "Writing PDML",
+  ret = process_specified_records(cf, &print_args->range, "Writing PDML",
                                   "selected packets", TRUE,
-                                  write_pdml_packet, fh);
+                                  write_pdml_packet, &callback_args);
+
+  epan_dissect_cleanup(&callback_args.edt);
 
   switch (ret) {
 
@@ -2787,47 +2599,54 @@ write_psml_packet(capture_file *cf, frame_data *fdata,
                   struct wtap_pkthdr *phdr, const guint8 *pd,
           void *argsp)
 {
-  FILE           *fh = (FILE *)argsp;
-  epan_dissect_t  edt;
-  gboolean        proto_tree_needed;
+  write_packet_callback_args_t *args = (write_packet_callback_args_t *)argsp;
 
-  /* Fill in the column information, only create the protocol tree
-     if having custom columns. */
-  proto_tree_needed = have_custom_cols(&cf->cinfo);
-  epan_dissect_init(&edt, cf->epan, proto_tree_needed, proto_tree_needed);
-  col_custom_prime_edt(&edt, &cf->cinfo);
-  epan_dissect_run(&edt, phdr, frame_tvbuff_new(fdata, pd), fdata, &cf->cinfo);
-  epan_dissect_fill_in_columns(&edt, FALSE, TRUE);
+  /* Fill in the column information */
+  col_custom_prime_edt(&args->edt, &cf->cinfo);
+  epan_dissect_run(&args->edt, cf->cd_t, phdr, frame_tvbuff_new(fdata, pd), fdata, &cf->cinfo);
+  epan_dissect_fill_in_columns(&args->edt, FALSE, TRUE);
 
-  /* Write out the information in that tree. */
-  proto_tree_write_psml(&edt, fh);
+  /* Write out the column information. */
+  write_psml_columns(&args->edt, args->fh);
 
-  epan_dissect_cleanup(&edt);
+  epan_dissect_reset(&args->edt);
 
-  return !ferror(fh);
+  return !ferror(args->fh);
 }
 
 cf_print_status_t
 cf_write_psml_packets(capture_file *cf, print_args_t *print_args)
 {
+  write_packet_callback_args_t callback_args;
   FILE         *fh;
   psp_return_t  ret;
 
+  gboolean proto_tree_needed;
+
   fh = ws_fopen(print_args->file, "w");
   if (fh == NULL)
     return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
 
-  write_psml_preamble(fh);
+  write_psml_preamble(&cf->cinfo, fh);
   if (ferror(fh)) {
     fclose(fh);
     return CF_PRINT_WRITE_ERROR;
   }
 
+  callback_args.fh = fh;
+
+  /* Fill in the column information, only create the protocol tree
+     if having custom columns. */
+  proto_tree_needed = have_custom_cols(&cf->cinfo);
+  epan_dissect_init(&callback_args.edt, cf->epan, proto_tree_needed, proto_tree_needed);
+
   /* Iterate through the list of packets, printing the packets we were
      told to print. */
-  ret = process_specified_packets(cf, &print_args->range, "Writing PSML",
+  ret = process_specified_records(cf, &print_args->range, "Writing PSML",
                                   "selected packets", TRUE,
-                                  write_psml_packet, fh);
+                                  write_psml_packet, &callback_args);
+
+  epan_dissect_cleanup(&callback_args.edt);
 
   switch (ret) {
 
@@ -2862,29 +2681,26 @@ write_csv_packet(capture_file *cf, frame_data *fdata,
                  struct wtap_pkthdr *phdr, const guint8 *pd,
                  void *argsp)
 {
-  FILE           *fh = (FILE *)argsp;
-  epan_dissect_t  edt;
-  gboolean        proto_tree_needed;
+  write_packet_callback_args_t *args = (write_packet_callback_args_t *)argsp;
 
-  /* Fill in the column information, only create the protocol tree
-     if having custom columns. */
-  proto_tree_needed = have_custom_cols(&cf->cinfo);
-  epan_dissect_init(&edt, cf->epan, proto_tree_needed, proto_tree_needed);
-  col_custom_prime_edt(&edt, &cf->cinfo);
-  epan_dissect_run(&edt, phdr, frame_tvbuff_new(fdata, pd), fdata, &cf->cinfo);
-  epan_dissect_fill_in_columns(&edt, FALSE, TRUE);
+  /* Fill in the column information */
+  col_custom_prime_edt(&args->edt, &cf->cinfo);
+  epan_dissect_run(&args->edt, cf->cd_t, phdr, frame_tvbuff_new(fdata, pd), fdata, &cf->cinfo);
+  epan_dissect_fill_in_columns(&args->edt, FALSE, TRUE);
 
-  /* Write out the information in that tree. */
-  proto_tree_write_csv(&edt, fh);
+  /* Write out the column information. */
+  write_csv_columns(&args->edt, args->fh);
 
-  epan_dissect_cleanup(&edt);
+  epan_dissect_reset(&args->edt);
 
-  return !ferror(fh);
+  return !ferror(args->fh);
 }
 
 cf_print_status_t
 cf_write_csv_packets(capture_file *cf, print_args_t *print_args)
 {
+  write_packet_callback_args_t callback_args;
+  gboolean        proto_tree_needed;
   FILE         *fh;
   psp_return_t  ret;
 
@@ -2892,17 +2708,25 @@ cf_write_csv_packets(capture_file *cf, print_args_t *print_args)
   if (fh == NULL)
     return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
 
-  write_csv_preamble(fh);
+  write_csv_column_titles(&cf->cinfo, fh);
   if (ferror(fh)) {
     fclose(fh);
     return CF_PRINT_WRITE_ERROR;
   }
 
+  callback_args.fh = fh;
+
+  /* only create the protocol tree if having custom columns. */
+  proto_tree_needed = have_custom_cols(&cf->cinfo);
+  epan_dissect_init(&callback_args.edt, cf->epan, proto_tree_needed, proto_tree_needed);
+
   /* Iterate through the list of packets, printing the packets we were
      told to print. */
-  ret = process_specified_packets(cf, &print_args->range, "Writing CSV",
+  ret = process_specified_records(cf, &print_args->range, "Writing CSV",
                                   "selected packets", TRUE,
-                                  write_csv_packet, fh);
+                                  write_csv_packet, &callback_args);
+
+  epan_dissect_cleanup(&callback_args.edt);
 
   switch (ret) {
 
@@ -2920,12 +2744,6 @@ cf_write_csv_packets(capture_file *cf, print_args_t *print_args)
     return CF_PRINT_WRITE_ERROR;
   }
 
-  write_csv_finale(fh);
-  if (ferror(fh)) {
-    fclose(fh);
-    return CF_PRINT_WRITE_ERROR;
-  }
-
   /* XXX - check for an error */
   fclose(fh);
 
@@ -2933,24 +2751,23 @@ cf_write_csv_packets(capture_file *cf, print_args_t *print_args)
 }
 
 static gboolean
-write_carrays_packet(capture_file *cf, frame_data *fdata,
+carrays_write_packet(capture_file *cf, frame_data *fdata,
              struct wtap_pkthdr *phdr,
              const guint8 *pd, void *argsp)
 {
-  FILE           *fh = (FILE *)argsp;
-  epan_dissect_t  edt;
+  write_packet_callback_args_t *args = (write_packet_callback_args_t *)argsp;
 
-  epan_dissect_init(&edt, cf->epan, TRUE, TRUE);
-  epan_dissect_run(&edt, phdr, frame_tvbuff_new(fdata, pd), fdata, NULL);
-  proto_tree_write_carrays(fdata->num, fh, &edt);
-  epan_dissect_cleanup(&edt);
+  epan_dissect_run(&args->edt, cf->cd_t, phdr, frame_tvbuff_new(fdata, pd), fdata, NULL);
+  write_carrays_hex_data(fdata->num, args->fh, &args->edt);
+  epan_dissect_reset(&args->edt);
 
-  return !ferror(fh);
+  return !ferror(args->fh);
 }
 
 cf_print_status_t
 cf_write_carrays_packets(capture_file *cf, print_args_t *print_args)
 {
+  write_packet_callback_args_t callback_args;
   FILE         *fh;
   psp_return_t  ret;
 
@@ -2959,19 +2776,23 @@ cf_write_carrays_packets(capture_file *cf, print_args_t *print_args)
   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;
   }
 
+  callback_args.fh = fh;
+  epan_dissect_init(&callback_args.edt, cf->epan, TRUE, TRUE);
+
   /* Iterate through the list of packets, printing the packets we were
      told to print. */
-  ret = process_specified_packets(cf, &print_args->range,
+  ret = process_specified_records(cf, &print_args->range,
                   "Writing C Arrays",
                   "selected packets", TRUE,
-                                  write_carrays_packet, fh);
+                                  carrays_write_packet, &callback_args);
+
+  epan_dissect_cleanup(&callback_args.edt);
+
   switch (ret) {
   case PSP_FINISHED:
     /* Completed successfully. */
@@ -2985,13 +2806,6 @@ cf_write_carrays_packets(capture_file *cf, print_args_t *print_args)
     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;
 }
@@ -3026,7 +2840,7 @@ match_protocol_tree(capture_file *cf, frame_data *fdata, void *criterion)
   epan_dissect_t  edt;
 
   /* Load the frame's data. */
-  if (!cf_read_frame(cf, fdata)) {
+  if (!cf_read_record(cf, fdata)) {
     /* Attempt to get the packet failed. */
     return MR_ERROR;
   }
@@ -3034,7 +2848,7 @@ match_protocol_tree(capture_file *cf, frame_data *fdata, void *criterion)
   /* Construct the protocol tree, including the displayed text */
   epan_dissect_init(&edt, cf->epan, TRUE, TRUE);
   /* We don't need the column information */
-  epan_dissect_run(&edt, &cf->phdr, frame_tvbuff_new_buffer(fdata, &cf->buf), fdata, NULL);
+  epan_dissect_run(&edt, cf->cd_t, &cf->phdr, frame_tvbuff_new_buffer(fdata, &cf->buf), fdata, NULL);
 
   /* Iterate through all the nodes, seeing if they have text that matches. */
   mdata->cf = cf;
@@ -3085,7 +2899,7 @@ match_subtree_text(proto_node *node, gpointer data)
   for (i = 0; i < label_len; i++) {
     c_char = label_ptr[i];
     if (cf->case_type)
-      c_char = toupper(c_char);
+      c_char = g_ascii_toupper(c_char);
     if (c_char == string[c_match]) {
       c_match++;
       if (c_match == string_len) {
@@ -3130,7 +2944,7 @@ match_summary_line(capture_file *cf, frame_data *fdata, void *criterion)
   size_t          c_match    = 0;
 
   /* Load the frame's data. */
-  if (!cf_read_frame(cf, fdata)) {
+  if (!cf_read_record(cf, fdata)) {
     /* Attempt to get the packet failed. */
     return MR_ERROR;
   }
@@ -3138,19 +2952,19 @@ match_summary_line(capture_file *cf, frame_data *fdata, void *criterion)
   /* Don't bother constructing the protocol tree */
   epan_dissect_init(&edt, cf->epan, FALSE, FALSE);
   /* Get the column information */
-  epan_dissect_run(&edt, &cf->phdr, frame_tvbuff_new_buffer(fdata, &cf->buf), fdata,
+  epan_dissect_run(&edt, cf->cd_t, &cf->phdr, frame_tvbuff_new_buffer(fdata, &cf->buf), fdata,
                    &cf->cinfo);
 
   /* Find the Info column */
   for (colx = 0; colx < cf->cinfo.num_cols; colx++) {
-    if (cf->cinfo.fmt_matx[colx][COL_INFO]) {
+    if (cf->cinfo.columns[colx].fmt_matx[COL_INFO]) {
       /* Found it.  See if we match. */
-      info_column = edt.pi.cinfo->col_data[colx];
+      info_column = edt.pi.cinfo->columns[colx].col_data;
       info_column_len = strlen(info_column);
       for (i = 0; i < info_column_len; i++) {
         c_char = info_column[i];
         if (cf->case_type)
-          c_char = toupper(c_char);
+          c_char = g_ascii_toupper(c_char);
         if (c_char == string[c_match]) {
           c_match++;
           if (c_match == string_len) {
@@ -3228,19 +3042,19 @@ match_narrow_and_wide(capture_file *cf, frame_data *fdata, void *criterion)
   size_t        c_match    = 0;
 
   /* Load the frame's data. */
-  if (!cf_read_frame(cf, fdata)) {
+  if (!cf_read_record(cf, fdata)) {
     /* Attempt to get the packet failed. */
     return MR_ERROR;
   }
 
   result = MR_NOTMATCHED;
   buf_len = fdata->cap_len;
-  pd = buffer_start_ptr(&cf->buf);
+  pd = ws_buffer_start_ptr(&cf->buf);
   i = 0;
   while (i < buf_len) {
     c_char = pd[i];
     if (cf->case_type)
-      c_char = toupper(c_char);
+      c_char = g_ascii_toupper(c_char);
     if (c_char != '\0') {
       if (c_char == ascii_text[c_match]) {
         c_match += 1;
@@ -3276,19 +3090,19 @@ match_narrow(capture_file *cf, frame_data *fdata, void *criterion)
   size_t        c_match    = 0;
 
   /* Load the frame's data. */
-  if (!cf_read_frame(cf, fdata)) {
+  if (!cf_read_record(cf, fdata)) {
     /* Attempt to get the packet failed. */
     return MR_ERROR;
   }
 
   result = MR_NOTMATCHED;
   buf_len = fdata->cap_len;
-  pd = buffer_start_ptr(&cf->buf);
+  pd = ws_buffer_start_ptr(&cf->buf);
   i = 0;
   while (i < buf_len) {
     c_char = pd[i];
     if (cf->case_type)
-      c_char = toupper(c_char);
+      c_char = g_ascii_toupper(c_char);
     if (c_char == ascii_text[c_match]) {
       c_match += 1;
       if (c_match == textlen) {
@@ -3323,19 +3137,19 @@ match_wide(capture_file *cf, frame_data *fdata, void *criterion)
   size_t        c_match    = 0;
 
   /* Load the frame's data. */
-  if (!cf_read_frame(cf, fdata)) {
+  if (!cf_read_record(cf, fdata)) {
     /* Attempt to get the packet failed. */
     return MR_ERROR;
   }
 
   result = MR_NOTMATCHED;
   buf_len = fdata->cap_len;
-  pd = buffer_start_ptr(&cf->buf);
+  pd = ws_buffer_start_ptr(&cf->buf);
   i = 0;
   while (i < buf_len) {
     c_char = pd[i];
     if (cf->case_type)
-      c_char = toupper(c_char);
+      c_char = g_ascii_toupper(c_char);
     if (c_char == ascii_text[c_match]) {
       c_match += 1;
       if (c_match == textlen) {
@@ -3369,14 +3183,14 @@ match_binary(capture_file *cf, frame_data *fdata, void *criterion)
   size_t        c_match     = 0;
 
   /* Load the frame's data. */
-  if (!cf_read_frame(cf, fdata)) {
+  if (!cf_read_record(cf, fdata)) {
     /* Attempt to get the packet failed. */
     return MR_ERROR;
   }
 
   result = MR_NOTMATCHED;
   buf_len = fdata->cap_len;
-  pd = buffer_start_ptr(&cf->buf);
+  pd = ws_buffer_start_ptr(&cf->buf);
   i = 0;
   while (i < buf_len) {
     if (pd[i] == binary_data[c_match]) {
@@ -3412,7 +3226,7 @@ cf_find_packet_dfilter_string(capture_file *cf, const char *filter,
   dfilter_t *sfcode;
   gboolean   result;
 
-  if (!dfilter_compile(filter, &sfcode)) {
+  if (!dfilter_compile(filter, &sfcode, NULL)) {
      /*
       * XXX - this shouldn't happen, as the filter string is machine
       * generated
@@ -3439,14 +3253,14 @@ match_dfilter(capture_file *cf, frame_data *fdata, void *criterion)
   match_result    result;
 
   /* Load the frame's data. */
-  if (!cf_read_frame(cf, fdata)) {
+  if (!cf_read_record(cf, fdata)) {
     /* Attempt to get the packet failed. */
     return MR_ERROR;
   }
 
   epan_dissect_init(&edt, cf->epan, TRUE, FALSE);
   epan_dissect_prime_dfilter(&edt, sfcode);
-  epan_dissect_run(&edt, &cf->phdr, frame_tvbuff_new_buffer(fdata, &cf->buf), fdata, NULL);
+  epan_dissect_run(&edt, cf->cd_t, &cf->phdr, frame_tvbuff_new_buffer(fdata, &cf->buf), fdata, NULL);
   result = dfilter_apply_edt(sfcode, &edt) ? MR_MATCHED : MR_NOTMATCHED;
   epan_dissect_cleanup(&edt);
   return result;
@@ -3486,7 +3300,6 @@ find_packet(capture_file *cf,
   frame_data  *fdata;
   frame_data  *new_fd = NULL;
   progdlg_t   *progbar = NULL;
-  gboolean     stop_flag;
   int          count;
   gboolean     found;
   float        progbar_val;
@@ -3513,7 +3326,7 @@ find_packet(capture_file *cf,
     /* Progress so far. */
     progbar_val = 0.0f;
 
-    stop_flag = FALSE;
+    cf->stop_flag = FALSE;
     g_get_current_time(&start_time);
 
     title = cf->sfilter?cf->sfilter:"";
@@ -3525,7 +3338,7 @@ find_packet(capture_file *cf,
          time in order to get to the next progress bar step). */
       if (progbar == NULL)
          progbar = delayed_create_progress_dlg(cf->window, "Searching", title,
-           FALSE, &stop_flag, &start_time, progbar_val);
+           FALSE, &cf->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
@@ -3549,7 +3362,7 @@ find_packet(capture_file *cf,
         progbar_nextstep += progbar_quantum;
       }
 
-      if (stop_flag) {
+      if (cf->stop_flag) {
         /* Well, the user decided to abort the search.  Go back to the
            frame where we started. */
         new_fd = start_fd;
@@ -3641,7 +3454,7 @@ find_packet(capture_file *cf,
          so we can't select it. */
       simple_message_box(ESD_TYPE_INFO, NULL,
                          "The capture file is probably not fully dissected.",
-                         "End of capture exceeded!");
+                         "End of capture exceeded.");
       return FALSE;
     }
     return TRUE;    /* success */
@@ -3674,7 +3487,7 @@ cf_goto_frame(capture_file *cf, guint fnumber)
        so we can't select it. */
     simple_message_box(ESD_TYPE_INFO, NULL,
                        "The capture file is probably not fully dissected.",
-                       "End of capture exceeded!");
+                       "End of capture exceeded.");
     return FALSE;
   }
   return TRUE;  /* we got to that packet */
@@ -3765,7 +3578,7 @@ cf_select_packet(capture_file *cf, int row)
   }
 
   /* Get the data in that frame. */
-  if (!cf_read_frame (cf, fdata)) {
+  if (!cf_read_record (cf, fdata)) {
     return;
   }
 
@@ -3779,7 +3592,7 @@ cf_select_packet(capture_file *cf, int row)
   cf->edt = epan_dissect_new(cf->epan, TRUE, TRUE);
 
   tap_build_interesting(cf->edt);
-  epan_dissect_run(cf->edt, &cf->phdr, frame_tvbuff_new_buffer(cf->current_frame, &cf->buf),
+  epan_dissect_run(cf->edt, cf->cd_t, &cf->phdr, frame_tvbuff_new_buffer(cf->current_frame, &cf->buf),
                    cf->current_frame, NULL);
 
   dfilter_macro_build_ftv_cache(cf->edt->tree);
@@ -3881,64 +3694,112 @@ cf_unignore_frame(capture_file *cf, frame_data *frame)
 const gchar *
 cf_read_shb_comment(capture_file *cf)
 {
-  wtapng_section_t *shb_inf;
-  const gchar      *temp_str;
-
   /* Get info from SHB */
-  shb_inf = wtap_file_get_shb_info(cf->wth);
-  if (shb_inf == NULL)
-        return NULL;
-  temp_str = shb_inf->opt_comment;
-  g_free(shb_inf);
-
-  return temp_str;
-
+  return wtap_file_get_shb_comment(cf->wth);
 }
 
 void
 cf_update_capture_comment(capture_file *cf, gchar *comment)
 {
-  wtapng_section_t *shb_inf;
+  const gchar *shb_comment;
 
   /* Get info from SHB */
-  shb_inf = wtap_file_get_shb_info(cf->wth);
+  shb_comment = wtap_file_get_shb_comment(cf->wth);
 
   /* See if the comment has changed or not */
-  if (shb_inf && shb_inf->opt_comment) {
-    if (strcmp(shb_inf->opt_comment, comment) == 0) {
+  if (shb_comment) {
+    if (strcmp(shb_comment, comment) == 0) {
       g_free(comment);
-      g_free(shb_inf);
       return;
     }
   }
 
-  g_free(shb_inf);
-
   /* The comment has changed, let's update it */
   wtap_write_shb_comment(cf->wth, comment);
   /* Mark the file as having unsaved changes */
   cf->unsaved_changes = TRUE;
 }
 
-void
-cf_update_packet_comment(capture_file *cf, frame_data *fdata, gchar *comment)
+static const char *
+cf_get_user_packet_comment(capture_file *cf, const frame_data *fd)
 {
-  if (fdata->opt_comment != NULL) {
-    /* OK, remove the old comment. */
-    g_free(fdata->opt_comment);
-    fdata->opt_comment = NULL;
-    cf->packet_comment_count--;
+  if (cf->frames_user_comments)
+     return (const char *)g_tree_lookup(cf->frames_user_comments, fd);
+
+  /* g_warning? */
+  return NULL;
+}
+
+char *
+cf_get_comment(capture_file *cf, const frame_data *fd)
+{
+  char *comment;
+
+  /* fetch user comment */
+  if (fd->flags.has_user_comment)
+    return g_strdup(cf_get_user_packet_comment(cf, fd));
+
+  /* fetch phdr comment */
+  if (fd->flags.has_phdr_comment) {
+    struct wtap_pkthdr phdr; /* Packet header */
+    Buffer buf; /* Packet data */
+
+    wtap_phdr_init(&phdr);
+    ws_buffer_init(&buf, 1500);
+
+    if (!cf_read_record_r(cf, fd, &phdr, &buf))
+      { /* XXX, what we can do here? */ }
+
+    comment = phdr.opt_comment;
+    wtap_phdr_cleanup(&phdr);
+    ws_buffer_free(&buf);
+    return comment;
   }
-  if (comment != NULL) {
-    /* Add the new comment. */
-    fdata->opt_comment = comment;
-    cf->packet_comment_count++;
+  return NULL;
+}
+
+static int
+frame_cmp(gconstpointer a, gconstpointer b, gpointer user_data _U_)
+{
+  const frame_data *fdata1 = (const frame_data *) a;
+  const frame_data *fdata2 = (const frame_data *) b;
+
+  return (fdata1->num < fdata2->num) ? -1 :
+    (fdata1->num > fdata2->num) ? 1 :
+    0;
+}
+
+gboolean
+cf_set_user_packet_comment(capture_file *cf, frame_data *fd, const gchar *new_comment)
+{
+  char *pkt_comment = cf_get_comment(cf, fd);
+
+  /* Check if the comment has changed */
+  if (!g_strcmp0(pkt_comment, new_comment)) {
+    g_free(pkt_comment);
+    return FALSE;
   }
+  g_free(pkt_comment);
+
+  if (pkt_comment)
+    cf->packet_comment_count--;
+
+  if (new_comment)
+    cf->packet_comment_count++;
+
+  fd->flags.has_user_comment = TRUE;
+
+  if (!cf->frames_user_comments)
+    cf->frames_user_comments = g_tree_new_full(frame_cmp, NULL, NULL, g_free);
+
+  /* insert new packet comment */
+  g_tree_replace(cf->frames_user_comments, fd, g_strdup(new_comment));
 
   expert_update_comment_count(cf->packet_comment_count);
 
   /* OK, we have unsaved changes. */
   cf->unsaved_changes = TRUE;
+  return TRUE;
 }
 
 /*
@@ -3956,6 +3817,50 @@ cf_comment_types(capture_file *cf)
   return comment_types;
 }
 
+#ifdef WANT_PACKET_EDITOR
+static gint
+g_direct_compare_func(gconstpointer a, gconstpointer b, gpointer user_data _U_)
+{
+  if (a > b)
+    return 1;
+  else if (a < b)
+    return -1;
+  else
+    return 0;
+}
+
+static void
+modified_frame_data_free(gpointer data)
+{
+  modified_frame_data *mfd = (modified_frame_data *)data;
+
+  g_free(mfd->pd);
+  g_free(mfd);
+}
+
+/*
+ * Give a frame new, edited data.
+ */
+void
+cf_set_frame_edited(capture_file *cf, frame_data *fd,
+                    struct wtap_pkthdr *phdr, guint8 *pd)
+{
+  modified_frame_data *mfd = (modified_frame_data *)g_malloc(sizeof(modified_frame_data));
+
+  mfd->phdr = *phdr;
+  mfd->pd = pd;
+
+  if (cf->edited_frames == NULL)
+    cf->edited_frames = g_tree_new_full(g_direct_compare_func, NULL, NULL,
+                                        modified_frame_data_free);
+  g_tree_insert(cf->edited_frames, GINT_TO_POINTER(fd->num), mfd);
+  fd->file_off = -1;
+
+  /* Mark the file as having unsaved changes */
+  cf->unsaved_changes = TRUE;
+}
+#endif
+
 typedef struct {
   wtap_dumper *pdh;
   const char  *fname;
@@ -3970,14 +3875,21 @@ typedef struct {
  * up a message box for the failure.
  */
 static gboolean
-save_packet(capture_file *cf _U_, frame_data *fdata,
+save_record(capture_file *cf, frame_data *fdata,
             struct wtap_pkthdr *phdr, const guint8 *pd,
             void *argsp)
 {
   save_callback_args_t *args = (save_callback_args_t *)argsp;
   struct wtap_pkthdr    hdr;
   int           err;
+  gchar        *err_info;
   gchar        *display_basename;
+  const char   *pkt_comment;
+
+  if (fdata->flags.has_user_comment)
+    pkt_comment = cf_get_user_packet_comment(cf, fdata);
+  else
+    pkt_comment = phdr->opt_comment;
 
   /* init the wtap header for saving */
   /* TODO: reuse phdr */
@@ -3992,23 +3904,25 @@ save_packet(capture_file *cf _U_, frame_data *fdata,
 
      For WTAP_HAS_PACK_FLAGS, we currently don't save the FCS length
      from the packet flags. */
+  hdr.rec_type = phdr->rec_type;
   hdr.presence_flags = 0;
   if (fdata->flags.has_ts)
     hdr.presence_flags |= WTAP_HAS_TS;
-  if (fdata->flags.has_if_id)
+  if (phdr->presence_flags & WTAP_HAS_INTERFACE_ID)
     hdr.presence_flags |= WTAP_HAS_INTERFACE_ID;
-  if (fdata->flags.has_pack_flags)
+  if (phdr->presence_flags & WTAP_HAS_PACK_FLAGS)
     hdr.presence_flags |= WTAP_HAS_PACK_FLAGS;
   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.caplen       = phdr->caplen;
+  hdr.len          = phdr->len;
   hdr.pkt_encap    = fdata->lnk_t;
   /* pcapng */
-  hdr.interface_id = fdata->interface_id;   /* identifier of the interface. */
+  hdr.interface_id = phdr->interface_id;   /* identifier of the interface. */
   /* options */
-  hdr.pack_flags   = fdata->pack_flags;
-  hdr.opt_comment  = fdata->opt_comment; /* NULL if not available */
+  hdr.pack_flags   = phdr->pack_flags;
+  hdr.opt_comment  = g_strdup(pkt_comment);
+
   /* pseudo */
   hdr.pseudo_header = phdr->pseudo_header;
 #if 0
@@ -4016,19 +3930,55 @@ save_packet(capture_file *cf _U_, frame_data *fdata,
   hdr.pack_flags   =     /* XXX - 0 for now (any value for "we don't have it"?) */
 #endif
   /* and save the packet */
-  if (!wtap_dump(args->pdh, &hdr, pd, &err)) {
+  if (!wtap_dump(args->pdh, &hdr, pd, &err, &err_info)) {
     if (err < 0) {
       /* Wiretap error. */
       switch (err) {
 
-      case WTAP_ERR_UNSUPPORTED_ENCAP:
+      case WTAP_ERR_UNWRITABLE_ENCAP:
         /*
-         * This is a problem with the particular frame we're writing;
-         * note that, and give the frame number.
+         * This is a problem with the particular frame we're writing and
+         * the file type and subtype we're writing; note that, and report
+         * the frame number and file type/subtype.
          */
         simple_error_message_box(
                       "Frame %u has a network type that can't be saved in a \"%s\" file.",
-                      fdata->num, wtap_file_type_string(args->file_type));
+                      fdata->num, wtap_file_type_subtype_string(args->file_type));
+        break;
+
+      case WTAP_ERR_PACKET_TOO_LARGE:
+        /*
+         * This is a problem with the particular frame we're writing and
+         * the file type and subtype we're writing; note that, and report
+         * the frame number and file type/subtype.
+         */
+        simple_error_message_box(
+                      "Frame %u is larger than Wireshark supports in a \"%s\" file.",
+                      fdata->num, wtap_file_type_subtype_string(args->file_type));
+        break;
+
+      case WTAP_ERR_UNWRITABLE_REC_TYPE:
+        /*
+         * This is a problem with the particular record we're writing and
+         * the file type and subtype we're writing; note that, and report
+         * the record number and file type/subtype.
+         */
+        simple_error_message_box(
+                      "Record %u has a record type that can't be saved in a \"%s\" file.",
+                      fdata->num, wtap_file_type_subtype_string(args->file_type));
+        break;
+
+      case WTAP_ERR_UNWRITABLE_REC_DATA:
+        /*
+         * This is a problem with the particular frame we're writing and
+         * the file type and subtype we're writing; note that, and report
+         * the frame number and file type/subtype.
+         */
+        simple_error_message_box(
+                      "Record %u has data that can't be saved in a \"%s\" file.\n(%s)",
+                      fdata->num, wtap_file_type_subtype_string(args->file_type),
+                      err_info != NULL ? err_info : "no information supplied");
+        g_free(err_info);
         break;
 
       default:
@@ -4045,6 +3995,8 @@ save_packet(capture_file *cf _U_, frame_data *fdata,
     }
     return FALSE;
   }
+
+  g_free(hdr.opt_comment);
   return TRUE;
 }
 
@@ -4150,7 +4102,7 @@ cf_has_unsaved_data(capture_file *cf)
    * If this is a temporary file, or a file with unsaved changes, it
    * has unsaved data.
    */
-  return cf->is_tempfile || cf->unsaved_changes;
+  return (cf->is_tempfile && cf->count>0) || cf->unsaved_changes;
 }
 
 /*
@@ -4163,9 +4115,7 @@ rescan_file(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
   gchar               *err_info;
   gchar               *name_ptr;
   gint64               data_offset;
-  gint64               file_pos;
   progdlg_t           *progbar        = NULL;
-  gboolean             stop_flag;
   gint64               size;
   float                progbar_val;
   GTimeVal             start_time;
@@ -4183,7 +4133,12 @@ rescan_file(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
   wtap_close(cf->wth);
 
   /* Open the new file. */
-  cf->wth = wtap_open_offline(fname, err, &err_info, TRUE);
+  /* XXX: this will go through all open_routines for a matching one. But right
+     now rescan_file() is only used when a file is being saved to a different
+     format than the original, and the user is not given a choice of which
+     reader to use (only which format to save it in), so doing this makes
+     sense for now. */
+  cf->wth = wtap_open_offline(fname, WTAP_TYPE_AUTO, err, &err_info, TRUE);
   if (cf->wth == NULL) {
     cf_open_failure_alert_box(fname, *err, err_info, FALSE, 0);
     return CF_READ_ERROR;
@@ -4204,7 +4159,7 @@ rescan_file(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
   /* No user changes yet. */
   cf->unsaved_changes = FALSE;
 
-  cf->cd_t        = wtap_file_type(cf->wth);
+  cf->cd_t        = wtap_file_type_subtype(cf->wth);
   cf->linktypes = g_array_sized_new(FALSE, FALSE, (guint) sizeof(int), 1);
 
   cf->snap      = wtap_snapshot_length(cf->wth);
@@ -4237,7 +4192,7 @@ rescan_file(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
   }else
     progbar_quantum = 0;
 
-  stop_flag = FALSE;
+  cf->stop_flag = FALSE;
   g_get_current_time(&start_time);
 
   framenum = 0;
@@ -4248,15 +4203,15 @@ rescan_file(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
     fdata->file_off = data_offset;
     if (size >= 0) {
       count++;
-      file_pos = wtap_read_so_far(cf->wth);
+      cf->f_datalen = wtap_read_so_far(cf->wth);
 
       /* Create the progress bar if necessary.
        * Check whether it should be created or not every MIN_NUMBER_OF_PACKET
        */
       if ((progbar == NULL) && !(count % MIN_NUMBER_OF_PACKET)) {
-        progbar_val = calc_progbar_val(cf, size, file_pos, status_str, sizeof(status_str));
+        progbar_val = calc_progbar_val(cf, size, cf->f_datalen, status_str, sizeof(status_str));
         progbar = delayed_create_progress_dlg(cf->window, "Rescanning", name_ptr,
-                                              TRUE, &stop_flag, &start_time, progbar_val);
+                                              TRUE, &cf->stop_flag, &start_time, progbar_val);
       }
 
       /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
@@ -4264,9 +4219,9 @@ rescan_file(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
          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 (file_pos >= progbar_nextstep) {
+      if (cf->f_datalen >= progbar_nextstep) {
         if (progbar != NULL) {
-          progbar_val = calc_progbar_val(cf, size, file_pos, status_str, sizeof(status_str));
+          progbar_val = calc_progbar_val(cf, size, cf->f_datalen, status_str, sizeof(status_str));
           /* update the packet bar content on the first run or frequently on very large files */
 #ifdef HAVE_LIBPCAP
           if (progbar_quantum > 500000 || displayed_once == 0) {
@@ -4282,7 +4237,7 @@ rescan_file(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
       }
     }
 
-    if (stop_flag) {
+    if (cf->stop_flag) {
       /* Well, the user decided to abort the rescan.  Sadly, as this
          isn't a reread, recovering is difficult, so we'll just
          close the current capture. */
@@ -4312,7 +4267,7 @@ rescan_file(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
   wtap_sequential_close(cf->wth);
 
   /* compute the time it took to load the file */
-  compute_elapsed(&start_time);
+  compute_elapsed(cf, &start_time);
 
   /* Set the file encapsulation type now; we don't know what it is until
      we've looked at all the packets, as we don't know until then whether
@@ -4322,7 +4277,7 @@ rescan_file(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
 
   cf_callback_invoke(cf_cb_file_rescan_finished, cf);
 
-  if (stop_flag) {
+  if (cf->stop_flag) {
     /* Our caller will give up at this point. */
     return CF_READ_ABORTED;
   }
@@ -4336,23 +4291,10 @@ rescan_file(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
     case WTAP_ERR_UNSUPPORTED:
       simple_error_message_box(
                  "The capture file contains record data that Wireshark doesn't support.\n(%s)",
-                 err_info);
+                 err_info != NULL ? err_info : "no information supplied");
       g_free(err_info);
       break;
 
-    case WTAP_ERR_UNSUPPORTED_ENCAP:
-      simple_error_message_box(
-                 "The capture file has a packet with a network type that Wireshark doesn't support.\n(%s)",
-                 err_info);
-      g_free(err_info);
-      break;
-
-    case WTAP_ERR_CANT_READ:
-      simple_error_message_box(
-                 "An attempt to read from the capture file failed for"
-                 " some unknown reason.");
-      break;
-
     case WTAP_ERR_SHORT_READ:
       simple_error_message_box(
                  "The capture file appears to have been cut short"
@@ -4362,14 +4304,15 @@ rescan_file(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
     case WTAP_ERR_BAD_FILE:
       simple_error_message_box(
                  "The capture file appears to be damaged or corrupt.\n(%s)",
-                 err_info);
+                 err_info != NULL ? err_info : "no information supplied");
       g_free(err_info);
       break;
 
     case WTAP_ERR_DECOMPRESS:
       simple_error_message_box(
                  "The compressed capture file appears to be damaged or corrupt.\n"
-                 "(%s)", err_info);
+                 "(%s)",
+                 err_info != NULL ? err_info : "no information supplied");
       g_free(err_info);
       break;
 
@@ -4385,7 +4328,7 @@ rescan_file(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
 }
 
 cf_write_status_t
-cf_save_packets(capture_file *cf, const char *fname, guint save_format,
+cf_save_records(capture_file *cf, const char *fname, guint save_format,
                 gboolean compressed, gboolean discard_comments,
                 gboolean dont_reopen)
 {
@@ -4393,7 +4336,7 @@ cf_save_packets(capture_file *cf, const char *fname, guint save_format,
   gchar           *fname_new = NULL;
   wtap_dumper     *pdh;
   frame_data      *fdata;
-  struct addrinfo *addrs;
+  addrinfo_lists_t *addr_lists;
   guint            framenum;
   int              err;
 #ifdef _WIN32
@@ -4408,12 +4351,11 @@ cf_save_packets(capture_file *cf, const char *fname, guint save_format,
 
   cf_callback_invoke(cf_cb_file_save_started, (gpointer)fname);
 
-  addrs = get_addrinfo_list();
+  addr_lists = get_addrinfo_list();
 
   if (save_format == cf->cd_t && compressed == cf->iscompressed
       && !discard_comments && !cf->unsaved_changes
-      && !(addrs && addrs->ai_next &&
-           wtap_dump_has_name_resolution(save_format))) {
+      && !(addr_lists && wtap_dump_has_name_resolution(save_format))) {
     /* We're saving in the format it's already in, and we're
        not discarding comments, and there are no changes we have
        in memory that aren't saved to the file, and we have no name
@@ -4493,12 +4435,15 @@ cf_save_packets(capture_file *cf, const char *fname, guint save_format,
        or moving the capture file, we have to do it by writing the packets
        out in Wiretap. */
 
-    wtapng_section_t *shb_hdr = NULL;
+    wtapng_section_t            *shb_hdr = NULL;
     wtapng_iface_descriptions_t *idb_inf = NULL;
+    wtapng_name_res_t           *nrb_hdr = NULL;
     int encap;
 
-    shb_hdr = wtap_file_get_shb_info(cf->wth);
+    /* XXX: what free's this shb_hdr? */
+    shb_hdr = wtap_file_get_shb_for_new_file(cf->wth);
     idb_inf = wtap_file_get_idb_info(cf->wth);
+    nrb_hdr = wtap_file_get_nrb_for_new_file(cf->wth);
 
     /* Determine what file encapsulation type we should use. */
     encap = wtap_dump_file_encap_type(cf->linktypes);
@@ -4513,10 +4458,10 @@ cf_save_packets(capture_file *cf, const char *fname, guint save_format,
          from which we're reading the packets that we're writing!) */
       fname_new = g_strdup_printf("%s~", fname);
       pdh = wtap_dump_open_ng(fname_new, save_format, encap, cf->snap,
-                              compressed, shb_hdr, idb_inf, &err);
+                              compressed, shb_hdr, idb_inf, nrb_hdr, &err);
     } else {
       pdh = wtap_dump_open_ng(fname, save_format, encap, cf->snap,
-                              compressed, shb_hdr, idb_inf, &err);
+                              compressed, shb_hdr, idb_inf, nrb_hdr, &err);
     }
     g_free(idb_inf);
     idb_inf = NULL;
@@ -4527,14 +4472,14 @@ cf_save_packets(capture_file *cf, const char *fname, guint save_format,
     }
 
     /* Add address resolution */
-    wtap_dump_set_addrinfo_list(pdh, addrs);
+    wtap_dump_set_addrinfo_list(pdh, addr_lists);
 
     /* Iterate through the list of packets, processing all the packets. */
     callback_args.pdh = pdh;
     callback_args.fname = fname;
     callback_args.file_type = save_format;
-    switch (process_specified_packets(cf, NULL, "Saving", "packets",
-                                      TRUE, save_packet, &callback_args)) {
+    switch (process_specified_records(cf, NULL, "Saving", "packets",
+                                      TRUE, save_record, &callback_args)) {
 
     case PSP_FINISHED:
       /* Completed successfully. */
@@ -4618,7 +4563,11 @@ cf_save_packets(capture_file *cf, const char *fname, guint save_format,
          the wtap structure, the filename, and the "is temporary"
          status applies to the new file; just update that. */
       wtap_close(cf->wth);
-      cf->wth = wtap_open_offline(fname, &err, &err_info, TRUE);
+      /* Although we're just "copying" and then opening the copy, it will
+         try all open_routine readers to open the copy, so we need to
+         reset the cfile's open_type. */
+      cf->open_type = WTAP_TYPE_AUTO;
+      cf->wth = wtap_open_offline(fname, WTAP_TYPE_AUTO, &err, &err_info, TRUE);
       if (cf->wth == NULL) {
         cf_open_failure_alert_box(fname, err, err_info, FALSE, 0);
         cf_close(cf);
@@ -4649,6 +4598,9 @@ cf_save_packets(capture_file *cf, const char *fname, guint save_format,
          ...as long as, for gzipped files, the process of writing
          out the file *also* generates the information needed to
          support fast random access to the compressed file. */
+      /* rescan_file will cause us to try all open_routines, so
+         reset cfile's open_type */
+      cf->open_type = WTAP_TYPE_AUTO;
       if (rescan_file(cf, fname, FALSE, &err) != CF_READ_OK) {
         /* The rescan failed; just close the file.  Either
            a dialog was popped up for the failure, so the
@@ -4664,15 +4616,20 @@ cf_save_packets(capture_file *cf, const char *fname, guint save_format,
       /* Remove SHB comment, if any. */
       wtap_write_shb_comment(cf->wth, NULL);
 
-      /* Remove packet comments. */
+      /* remove all user comments */
       for (framenum = 1; framenum <= cf->count; framenum++) {
         fdata = frame_data_sequence_find(cf->frames, framenum);
-        if (fdata->opt_comment) {
-          g_free(fdata->opt_comment);
-          fdata->opt_comment = NULL;
-          cf->packet_comment_count--;
-        }
+
+        fdata->flags.has_phdr_comment = FALSE;
+        fdata->flags.has_user_comment = FALSE;
       }
+
+      if (cf->frames_user_comments) {
+        g_tree_destroy(cf->frames_user_comments);
+        cf->frames_user_comments = NULL;
+      }
+
+      cf->packet_comment_count = 0;
     }
   }
   return CF_WRITE_OK;
@@ -4701,8 +4658,9 @@ cf_export_specified_packets(capture_file *cf, const char *fname,
   int                          err;
   wtap_dumper                 *pdh;
   save_callback_args_t         callback_args;
-  wtapng_section_t            *shb_hdr;
-  wtapng_iface_descriptions_t *idb_inf;
+  wtapng_section_t            *shb_hdr = NULL;
+  wtapng_iface_descriptions_t *idb_inf = NULL;
+  wtapng_name_res_t           *nrb_hdr = NULL;
   int                          encap;
 
   cf_callback_invoke(cf_cb_file_export_specified_packets_started, (gpointer)fname);
@@ -4714,8 +4672,10 @@ cf_export_specified_packets(capture_file *cf, const char *fname,
      written, don't special-case the operation - read each packet
      and then write it out if it's one of the specified ones. */
 
-  shb_hdr = wtap_file_get_shb_info(cf->wth);
+  /* XXX: what free's this shb_hdr? */
+  shb_hdr = wtap_file_get_shb_for_new_file(cf->wth);
   idb_inf = wtap_file_get_idb_info(cf->wth);
+  nrb_hdr = wtap_file_get_nrb_for_new_file(cf->wth);
 
   /* Determine what file encapsulation type we should use. */
   encap = wtap_dump_file_encap_type(cf->linktypes);
@@ -4730,10 +4690,10 @@ cf_export_specified_packets(capture_file *cf, const char *fname,
        from which we're reading the packets that we're writing!) */
     fname_new = g_strdup_printf("%s~", fname);
     pdh = wtap_dump_open_ng(fname_new, save_format, encap, cf->snap,
-                            compressed, shb_hdr, idb_inf, &err);
+                            compressed, shb_hdr, idb_inf, nrb_hdr, &err);
   } else {
     pdh = wtap_dump_open_ng(fname, save_format, encap, cf->snap,
-                            compressed, shb_hdr, idb_inf, &err);
+                            compressed, shb_hdr, idb_inf, nrb_hdr, &err);
   }
   g_free(idb_inf);
   idb_inf = NULL;
@@ -4750,14 +4710,14 @@ cf_export_specified_packets(capture_file *cf, const char *fname,
      told to process.
 
      XXX - we've already called "packet_range_process_init(range)", but
-     "process_specified_packets()" will do it again.  Fortunately,
+     "process_specified_records()" will do it again.  Fortunately,
      that's harmless in this case, as we haven't done anything to
      "range" since we initialized it. */
   callback_args.pdh = pdh;
   callback_args.fname = fname;
   callback_args.file_type = save_format;
-  switch (process_specified_packets(cf, range, "Writing", "specified packets",
-                                    TRUE, save_packet, &callback_args)) {
+  switch (process_specified_records(cf, range, "Writing", "specified records",
+                                    TRUE, save_record, &callback_args)) {
 
   case PSP_FINISHED:
     /* Completed successfully. */
@@ -4853,9 +4813,10 @@ cf_open_failure_alert_box(const char *filename, int err, gchar *err_info,
     case WTAP_ERR_UNSUPPORTED:
       /* Seen only when opening a capture file for reading. */
       simple_error_message_box(
-            "The file \"%s\" isn't a capture file in a format Wireshark understands.\n"
+            "The file \"%s\" contains record data that Wireshark doesn't support.\n"
             "(%s)",
-            display_basename, err_info);
+            display_basename,
+            err_info != NULL ? err_info : "no information supplied");
       g_free(err_info);
       break;
 
@@ -4864,25 +4825,18 @@ cf_open_failure_alert_box(const char *filename, int err, gchar *err_info,
       simple_error_message_box(
             "The file \"%s\" is a pipe, and %s capture files can't be "
             "written to a pipe.",
-            display_basename, wtap_file_type_string(file_type));
+            display_basename, wtap_file_type_subtype_string(file_type));
       break;
 
-    case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
+    case WTAP_ERR_UNWRITABLE_FILE_TYPE:
       /* Seen only when opening a capture file for writing. */
       simple_error_message_box(
             "Wireshark doesn't support writing capture files in that format.");
       break;
 
-    case WTAP_ERR_UNSUPPORTED_ENCAP:
-      if (for_writing) {
-        simple_error_message_box("Wireshark can't save this capture in that format.");
-      } else {
-        simple_error_message_box(
-              "The file \"%s\" is a capture for a network type that Wireshark doesn't support.\n"
-              "(%s)",
-              display_basename, err_info);
-        g_free(err_info);
-      }
+    case WTAP_ERR_UNWRITABLE_ENCAP:
+      /* Seen only when opening a capture file for writing. */
+      simple_error_message_box("Wireshark can't save this capture in that format.");
       break;
 
     case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
@@ -4901,7 +4855,8 @@ cf_open_failure_alert_box(const char *filename, int err, gchar *err_info,
       simple_error_message_box(
             "The file \"%s\" appears to be damaged or corrupt.\n"
             "(%s)",
-            display_basename, err_info);
+            display_basename,
+            err_info != NULL ? err_info : "no information supplied");
       g_free(err_info);
       break;
 
@@ -4938,7 +4893,8 @@ cf_open_failure_alert_box(const char *filename, int err, gchar *err_info,
     case WTAP_ERR_DECOMPRESS:
       simple_error_message_box(
             "The compressed file \"%s\" appears to be damaged or corrupt.\n"
-            "(%s)", display_basename, err_info);
+            "(%s)", display_basename,
+            err_info != NULL ? err_info : "no information supplied");
       g_free(err_info);
       break;
 
@@ -5055,7 +5011,7 @@ cf_reload(capture_file *cf) {
   filename = g_strdup(cf->filename);
   is_tempfile = cf->is_tempfile;
   cf->is_tempfile = FALSE;
-  if (cf_open(cf, filename, is_tempfile, &err) == CF_OK) {
+  if (cf_open(cf, filename, cf->open_type, is_tempfile, &err) == CF_OK) {
     switch (cf_read(cf, TRUE)) {
 
     case CF_READ_OK: