Don't assign to a proto_item * if the value won't be used: Coverity 823 & 824;
[obnox/wireshark/wip.git] / file.c
diff --git a/file.c b/file.c
index 46143eefe4da384c8eea4111289b68d0a5b890fe..075d688f042e96024b3c36567349674a387c21ed 100644 (file)
--- a/file.c
+++ b/file.c
@@ -60,6 +60,7 @@
 #include "merge.h"
 #include "alert_box.h"
 #include "simple_dialog.h"
+#include "main_statusbar.h"
 #include "progress_dlg.h"
 #include "ui_util.h"
 #include <epan/prefs.h>
 #include <epan/dfilter/dfilter-macro.h>
 #include <wsutil/file_util.h>
 #include <epan/strutil.h>
+#include <epan/addr_resolv.h>
 
 #ifdef HAVE_LIBPCAP
 gboolean auto_scroll_live;
 #endif
 
+static guint32 cum_bytes;
 static nstime_t first_ts;
 static nstime_t prev_dis_ts;
-static guint32 cum_bytes;
+static nstime_t prev_cap_ts;
+
 static gulong computed_elapsed;
 
 static void cf_reset_state(capture_file *cf);
@@ -90,24 +94,33 @@ static int read_packet(capture_file *cf, dfilter_t *dfcode,
 static void rescan_packets(capture_file *cf, const char *action, const char *action_item,
     gboolean refilter, gboolean redissect);
 
-static gboolean match_protocol_tree(capture_file *cf, frame_data *fdata,
+typedef enum {
+  MR_NOTMATCHED,
+  MR_MATCHED,
+  MR_ERROR
+} match_result;
+static match_result match_protocol_tree(capture_file *cf, frame_data *fdata,
     void *criterion);
 static void match_subtree_text(proto_node *node, gpointer data);
-static gboolean match_summary_line(capture_file *cf, frame_data *fdata,
+static match_result match_summary_line(capture_file *cf, frame_data *fdata,
     void *criterion);
-static gboolean match_ascii_and_unicode(capture_file *cf, frame_data *fdata,
+static match_result match_ascii_and_unicode(capture_file *cf, frame_data *fdata,
     void *criterion);
-static gboolean match_ascii(capture_file *cf, frame_data *fdata,
+static match_result match_ascii(capture_file *cf, frame_data *fdata,
     void *criterion);
-static gboolean match_unicode(capture_file *cf, frame_data *fdata,
+static match_result match_unicode(capture_file *cf, frame_data *fdata,
     void *criterion);
-static gboolean match_binary(capture_file *cf, frame_data *fdata,
+static match_result match_binary(capture_file *cf, frame_data *fdata,
     void *criterion);
-static gboolean match_dfilter(capture_file *cf, frame_data *fdata,
+static match_result match_dfilter(capture_file *cf, frame_data *fdata,
     void *criterion);
-static gboolean find_packet(capture_file *cf,
-    gboolean (*match_function)(capture_file *, frame_data *, void *),
+static match_result match_marked(capture_file *cf, frame_data *fdata,
+    void *criterion);
+static match_result match_time_reference(capture_file *cf, frame_data *fdata,
     void *criterion);
+static gboolean find_packet(capture_file *cf,
+    match_result (*match_function)(capture_file *, frame_data *, void *),
+    void *criterion, search_direction dir);
 
 static void cf_open_failure_alert_box(const char *filename, int err,
                       gchar *err_info, gboolean for_writing,
@@ -115,12 +128,10 @@ static void cf_open_failure_alert_box(const char *filename, int err,
 static const char *file_rename_error_message(int err);
 static void cf_write_failure_alert_box(const char *filename, int err);
 static void cf_close_failure_alert_box(const char *filename, int err);
-#ifdef NEW_PACKET_LIST
 static void ref_time_packets(capture_file *cf);
-#endif
 /* Update the progress bar this many times when reading a file. */
 #define N_PROGBAR_UPDATES   100
-/* We read around 200k/100ms domt update the progress bar more often than that */
+/* We read around 200k/100ms don't update the progress bar more often than that */
 #define MIN_QUANTUM         200000
 #define MIN_NUMBER_OF_PACKET 1500
 
@@ -129,10 +140,14 @@ static void ref_time_packets(capture_file *cf);
 #define FRAME_DATA_CHUNK_SIZE   1024
 
 
-/* this callback mechanism should possibly be replaced by the g_signal_...() stuff (if I only would know how :-) */
+/*
+ * We could probably use g_signal_...() instead of the callbacks below but that
+ * would require linking our CLI programs to libgobject and creating an object
+ * instance for the signals.
+ */
 typedef struct {
-    cf_callback_t cb_fct;
-    gpointer user_data;
+  cf_callback_t cb_fct;
+  gpointer user_data;
 } cf_callback_data_t;
 
 static GList *cf_callbacks = NULL;
@@ -140,98 +155,95 @@ static GList *cf_callbacks = NULL;
 static void
 cf_callback_invoke(int event, gpointer data)
 {
-    cf_callback_data_t *cb;
-    GList *cb_item = cf_callbacks;
+  cf_callback_data_t *cb;
+  GList *cb_item = cf_callbacks;
 
-    /* there should be at least one interested */
-    g_assert(cb_item != NULL);
+  /* there should be at least one interested */
+  g_assert(cb_item != NULL);
 
-    while(cb_item != NULL) {
-        cb = cb_item->data;
-        cb->cb_fct(event, data, cb->user_data);
-        cb_item = g_list_next(cb_item);
-    }
+  while(cb_item != NULL) {
+    cb = cb_item->data;
+    cb->cb_fct(event, data, cb->user_data);
+    cb_item = g_list_next(cb_item);
+  }
 }
 
 
 void
 cf_callback_add(cf_callback_t func, gpointer user_data)
 {
-    cf_callback_data_t *cb;
+  cf_callback_data_t *cb;
 
-    cb = g_malloc(sizeof(cf_callback_data_t));
-    cb->cb_fct = func;
-    cb->user_data = user_data;
+  cb = g_malloc(sizeof(cf_callback_data_t));
+  cb->cb_fct = func;
+  cb->user_data = user_data;
 
-    cf_callbacks = g_list_append(cf_callbacks, cb);
+  cf_callbacks = g_list_append(cf_callbacks, cb);
 }
 
 void
 cf_callback_remove(cf_callback_t func)
 {
-    cf_callback_data_t *cb;
-    GList *cb_item = cf_callbacks;
-
-    while(cb_item != NULL) {
-        cb = cb_item->data;
-        if(cb->cb_fct == func) {
-            cf_callbacks = g_list_remove(cf_callbacks, cb);
-            g_free(cb);
-            return;
-        }
-        cb_item = g_list_next(cb_item);
+  cf_callback_data_t *cb;
+  GList *cb_item = cf_callbacks;
+
+  while(cb_item != NULL) {
+    cb = cb_item->data;
+    if(cb->cb_fct == func) {
+      cf_callbacks = g_list_remove(cf_callbacks, cb);
+      g_free(cb);
+      return;
     }
+    cb_item = g_list_next(cb_item);
+  }
 
-    g_assert_not_reached();
+  g_assert_not_reached();
 }
 
 void
 cf_timestamp_auto_precision(capture_file *cf)
 {
-#ifdef NEW_PACKET_LIST
-    int i;
-#endif
-    int prec = timestamp_get_precision();
+  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;
-    }
+  /* 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();
-        }
+  /* 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();
     }
-#ifdef NEW_PACKET_LIST
+  }
   /* 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++) {
@@ -239,31 +251,30 @@ cf_timestamp_auto_precision(capture_file *cf)
       new_packet_list_resize_column(i);
     }
   }
-#endif
 }
 
 gulong
 cf_get_computed_elapsed(void)
 {
-    return computed_elapsed;
+  return computed_elapsed;
 }
 
 static void reset_elapsed(void)
 {
-    computed_elapsed = 0;
+  computed_elapsed = 0;
 }
 
 static void compute_elapsed(GTimeVal *start_time)
 {
-    gdouble    delta_time;
-    GTimeVal   time_now;
+  gdouble    delta_time;
+  GTimeVal   time_now;
 
-    g_get_current_time(&time_now);
+  g_get_current_time(&time_now);
 
-    delta_time = (time_now.tv_sec - start_time->tv_sec) * 1e6 +
+  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*/
+  computed_elapsed = (gulong) (delta_time / 1000); /* ms*/
 }
 
 cf_status_t
@@ -308,6 +319,8 @@ cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
   cf->count     = 0;
   cf->displayed_count = 0;
   cf->marked_count = 0;
+  cf->ignored_count = 0;
+  cf->ref_time_count = 0;
   cf->drops_known = FALSE;
   cf->drops     = 0;
   cf->snap      = wtap_snapshot_length(cf->wth);
@@ -321,6 +334,7 @@ cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
   nstime_set_zero(&cf->elapsed_time);
   nstime_set_unset(&first_ts);
   nstime_set_unset(&prev_dis_ts);
+  nstime_set_unset(&prev_cap_ts);
   cum_bytes = 0;
 
 #if GLIB_CHECK_VERSION(2,10,0)
@@ -335,15 +349,10 @@ cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
   g_assert(cf->plist_chunk);
 #endif
 
-#ifdef NEW_PACKET_LIST
   /* Adjust timestamp precision if auto is selected, col width will be adjusted */
   cf_timestamp_auto_precision(cf);
   /* XXX needed ? */
   new_packet_list_queue_draw();
-#else
-  /* change the time formats now, as we might have a new precision */
-  cf_change_time_formats(cf);
-#endif
   fileset_file_opened(fname);
 
   if(cf->cd_t == WTAP_FILE_BER) {
@@ -351,6 +360,9 @@ cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
     ber_set_filename(cf->filename);
   }
 
+  wtap_set_cb_new_ipv4(cf->wth, add_ipv4_name);
+  wtap_set_cb_new_ipv6(cf->wth, (wtap_new_ipv6_callback_t) add_ipv6_name);
+
   return CF_OK;
 
 fail:
@@ -388,8 +400,8 @@ cf_reset_state(capture_file *cf)
   cf->user_saved = FALSE;
 
 #if GLIB_CHECK_VERSION(2,10,0)
-  if (cf->plist != NULL)
-    g_slice_free_chain(frame_data, cf->plist, next);
+  if (cf->plist_start != NULL)
+    g_slice_free_chain(frame_data, cf->plist_start, next);
 #else
   /* memory chunks have been deprecated in favor of the slice allocator,
    * which has been added in 2.10
@@ -399,11 +411,9 @@ cf_reset_state(capture_file *cf)
     cf->plist_chunk = NULL;
   }
 #endif
-  if (cf->rfcode != NULL) {
-    dfilter_free(cf->rfcode);
-    cf->rfcode = NULL;
-  }
-  cf->plist = NULL;
+  dfilter_free(cf->rfcode);
+  cf->rfcode = NULL;
+  cf->plist_start = NULL;
   cf->plist_end = NULL;
   cf_unselect_packet(cf);   /* nothing to select */
   cf->first_displayed = NULL;
@@ -415,15 +425,9 @@ cf_reset_state(capture_file *cf)
   cf->finfo_selected = NULL;
 
   /* Clear the packet list. */
-#ifdef NEW_PACKET_LIST
   new_packet_list_freeze();
   new_packet_list_clear();
   new_packet_list_thaw();
-#else
-  packet_list_freeze();
-  packet_list_clear();
-  packet_list_thaw();
-#endif
 
   cf->f_datalen = 0;
   cf->count = 0;
@@ -456,34 +460,56 @@ cf_close(capture_file *cf)
 }
 
 /* an out of memory exception occured, wait for a user button press to exit */
-void outofmemory_cb(gpointer dialog _U_, gint btn _U_, gpointer data _U_)
+static void outofmemory_cb(gpointer dialog _U_, gint btn _U_, gpointer data _U_)
 {
     main_window_exit();
 }
 
-static float calc_progbar_val(capture_file *cf, gint64 size, gint64 file_pos){
-
-    float   progbar_val;
-
-    progbar_val = (gfloat) file_pos / (gfloat) size;
-    if (progbar_val > 1.0) {
-    /* The file probably grew while we were reading it.
-       Update file size, and try again. */
-      size = wtap_file_size(cf->wth, NULL);
-      if (size >= 0)
-        progbar_val = (gfloat) file_pos / (gfloat) size;
-       /* If it's still > 1, either "wtap_file_size()" failed (in which
-          case there's not much we can do about it), or the file
-          *shrank* (in which case there's not much we can do about
-          it); just clip the progress value at 1.0. */
-      if (progbar_val > 1.0f)
-        progbar_val = 1.0f;
-    }
-    return progbar_val;
+static float
+calc_progbar_val(capture_file *cf, gint64 size, gint64 file_pos, gchar *status_str, gulong status_size)
+{
+  float   progbar_val;
+
+  progbar_val = (gfloat) file_pos / (gfloat) size;
+  if (progbar_val > 1.0) {
+
+    /*  The file probably grew while we were reading it.
+     *  Update file size, and try again.
+     */
+    size = wtap_file_size(cf->wth, NULL);
+
+    /*  Another possibility is that we're reading a compressed file and we've
+     *  read more (uncompressed) data from the file than exists in the
+     *  (compressed) file.  So check how much data we've actually read.
+     *
+     *  This is inside this "if val > 1.0" check to avoid the lseek() when
+     *  reading uncompressed files.  Testing has (thus far) shown no progress
+     *  bar weirdness resulting from switching from the data offset (when
+     *  reading the first part of the file) to the real file position.
+     */
+    file_pos = wtap_read_so_far(cf->wth, NULL);
+
+    if (size >= 0)
+      progbar_val = (gfloat) file_pos / (gfloat) size;
+
+    /*  If it's still > 1, either "wtap_file_size()" failed (in which
+     *  case there's not much we can do about it), or the file
+     *  *shrank* (in which case there's not much we can do about
+     *  it); just clip the progress value at 1.0.
+     */
+    if (progbar_val > 1.0f)
+      progbar_val = 1.0f;
+  }
+
+  g_snprintf(status_str, status_size,
+            "%" G_GINT64_MODIFIER "dKB of %" G_GINT64_MODIFIER "dKB",
+            file_pos / 1024, size / 1024);
+
+  return progbar_val;
 }
 
 cf_read_status_t
-cf_read(capture_file *cf)
+cf_read(capture_file *cf, gboolean from_save)
 {
   int         err;
   gchar       *err_info;
@@ -523,10 +549,13 @@ cf_read(capture_file *cf)
 
   reset_tap_listeners();
 
-  cf_callback_invoke(cf_cb_file_read_start, cf);
-
   name_ptr = get_basename(cf->filename);
 
+  if (from_save == FALSE)
+    cf_callback_invoke(cf_cb_file_read_started, cf);
+  else
+    cf_callback_invoke(cf_cb_file_save_started, (gpointer)name_ptr);
+
   /* Find the size of the file. */
   size = wtap_file_size(cf->wth, NULL);
 
@@ -537,31 +566,31 @@ cf_read(capture_file *cf)
   if (size >= 0){
     progbar_quantum = size/N_PROGBAR_UPDATES;
     if (progbar_quantum < MIN_QUANTUM)
-        progbar_quantum = MIN_QUANTUM;
+      progbar_quantum = MIN_QUANTUM;
   }else
     progbar_quantum = 0;
   /* Progress so far. */
   progbar_val = 0.0f;
 
-#ifdef NEW_PACKET_LIST
   new_packet_list_freeze();
-#else
-  packet_list_freeze();
-#endif
 
   stop_flag = FALSE;
   g_get_current_time(&start_time);
 
   while ((wtap_read(cf->wth, &err, &err_info, &data_offset))) {
     if (size >= 0) {
-        count++;
+      count++;
       /* Create the progress bar if necessary.
-       * Check wether it should be created or not every MIN_NUMBER_OF_PACKET
+       * 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, data_offset);
-        progbar = delayed_create_progress_dlg("Loading", name_ptr,
-          TRUE, &stop_flag, &start_time, progbar_val);
+        progbar_val = calc_progbar_val(cf, size, data_offset, status_str, sizeof(status_str));
+        if (from_save == FALSE)
+          progbar = delayed_create_progress_dlg("Loading", name_ptr,
+                                                TRUE, &stop_flag, &start_time, progbar_val);
+        else
+          progbar = delayed_create_progress_dlg("Saving", name_ptr,
+                                                TRUE, &stop_flag, &start_time, progbar_val);
       }
 
       /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
@@ -570,34 +599,24 @@ cf_read(capture_file *cf)
          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) {
-          if (progbar != NULL) {
-              progbar_val = calc_progbar_val( cf, size, data_offset);
-              /* update the packet lists content on the first run or frequently on very large files */
-              /* (on smaller files the display update takes longer than reading the file) */
+        if (progbar != NULL) {
+          progbar_val = calc_progbar_val(cf, size, data_offset, status_str, sizeof(status_str));
+          /* update the packet lists content on the first run or frequently on very large files */
+          /* (on smaller files the display update takes longer than reading the file) */
 #ifdef HAVE_LIBPCAP
-              if (progbar_quantum > 500000 || displayed_once == 0) {
-                  if ((auto_scroll_live || displayed_once == 0 || cf->displayed_count < 1000) && cf->plist_end != NULL) {
-                      displayed_once = 1;
-#ifdef NEW_PACKET_LIST
-                  new_packet_list_thaw();
-                  if (auto_scroll_live)
-                      new_packet_list_moveto_end();
-                  new_packet_list_freeze();
-#else
-                  packet_list_thaw();
-                  if (auto_scroll_live)
-                      packet_list_moveto_end();
-                  packet_list_freeze();
-#endif /* NEW_PACKET_LIST */
-                  }
+          if (progbar_quantum > 500000 || displayed_once == 0) {
+            if ((auto_scroll_live || displayed_once == 0 || cf->displayed_count < 1000) && cf->plist_end != NULL) {
+              displayed_once = 1;
+              new_packet_list_thaw();
+              if (auto_scroll_live)
+                new_packet_list_moveto_end();
+              new_packet_list_freeze();
+            }
           }
 #endif /* HAVE_LIBPCAP */
-            g_snprintf(status_str, sizeof(status_str),
-                       "%" G_GINT64_MODIFIER "dKB of %" G_GINT64_MODIFIER "dKB",
-                       data_offset / 1024, size / 1024);
-            update_progress_dlg(progbar, progbar_val, status_str);
-          }
-         progbar_nextstep += progbar_quantum;
+          update_progress_dlg(progbar, progbar_val, status_str);
+        }
+        progbar_nextstep += progbar_quantum;
       }
     }
 
@@ -611,27 +630,27 @@ cf_read(capture_file *cf)
       break;
     }
     TRY {
-        read_packet(cf, dfcode, filtering_tap_listeners, tap_flags, data_offset);
+      read_packet(cf, dfcode, filtering_tap_listeners, tap_flags, data_offset);
     }
     CATCH(OutOfMemoryError) {
-        gpointer dialog;
-
-        dialog = simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
-              "%sOut Of Memory!%s\n"
-              "\n"
-              "Sorry, but Wireshark has to terminate now!\n"
-              "\n"
-              "Some infos / workarounds can be found at:\n"
-              "http://wiki.wireshark.org/KnownBugs/OutOfMemory",
-              simple_dialog_primary_start(), simple_dialog_primary_end());
-        /* we have to terminate, as we cannot recover from the memory error */
-        simple_dialog_set_cb(dialog, outofmemory_cb, NULL);
-        while(1) {
-            main_window_update();
-            /* XXX - how to avoid a busy wait? */
-            /* Sleep(100); */
-        };
-        break;
+      gpointer dialog;
+
+      dialog = simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+                             "%sOut Of Memory!%s\n"
+                             "\n"
+                             "Sorry, but Wireshark has to terminate now!\n"
+                             "\n"
+                             "Some infos / workarounds can be found at:\n"
+                             "http://wiki.wireshark.org/KnownBugs/OutOfMemory",
+                             simple_dialog_primary_start(), simple_dialog_primary_end());
+      /* we have to terminate, as we cannot recover from the memory error */
+      simple_dialog_set_cb(dialog, outofmemory_cb, NULL);
+      while(1) {
+        main_window_update();
+        /* XXX - how to avoid a busy wait? */
+        /* Sleep(100); */
+      };
+      break;
     }
     ENDTRY;
   }
@@ -667,33 +686,27 @@ cf_read(capture_file *cf)
   cf->current_frame = cf->first_displayed;
   cf->current_row = 0;
 
-#ifdef NEW_PACKET_LIST
   new_packet_list_thaw();
-#else
-  packet_list_thaw();
-#endif
-
-  cf_callback_invoke(cf_cb_file_read_finished, cf);
+  if (from_save == FALSE)
+    cf_callback_invoke(cf_cb_file_read_finished, cf);
+  else
+    cf_callback_invoke(cf_cb_file_save_finished, cf);
 
   /* If we have any displayed packets to select, select the first of those
      packets by making the first row the selected row. */
   if (cf->first_displayed != NULL){
-#ifdef NEW_PACKET_LIST
     new_packet_list_select_first_row();
-#else
-    packet_list_select_row(0);
-#endif /* NEW_PACKET_LIST */
   }
 
   if(stop_flag) {
     simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
-          "%sFile loading was cancelled!%s\n"
-          "\n"
-          "The remaining packets in the file were discarded.\n"
-          "\n"
-          "As a lot of packets from the original file will be missing,\n"
-          "remember to be careful when saving the current content to a file.\n",
-          simple_dialog_primary_start(), simple_dialog_primary_end());
+                  "%sFile loading was cancelled!%s\n"
+                  "\n"
+                  "The remaining packets in the file were discarded.\n"
+                  "\n"
+                  "As a lot of packets from the original file will be missing,\n"
+                  "remember to be careful when saving the current content to a file.\n",
+                  simple_dialog_primary_start(), simple_dialog_primary_end());
     return CF_READ_ERROR;
   }
 
@@ -705,34 +718,34 @@ cf_read(capture_file *cf)
 
     case WTAP_ERR_UNSUPPORTED_ENCAP:
       g_snprintf(errmsg_errno, sizeof(errmsg_errno),
-               "The capture file has a packet with a network type that Wireshark doesn't support.\n(%s)",
-               err_info);
+                 "The capture file has a packet with a network type that Wireshark doesn't support.\n(%s)",
+                 err_info);
       g_free(err_info);
       errmsg = errmsg_errno;
       break;
 
     case WTAP_ERR_CANT_READ:
       errmsg = "An attempt to read from the capture file failed for"
-               " some unknown reason.";
+        " some unknown reason.";
       break;
 
     case WTAP_ERR_SHORT_READ:
       errmsg = "The capture file appears to have been cut short"
-               " in the middle of a packet.";
+        " in the middle of a packet.";
       break;
 
     case WTAP_ERR_BAD_RECORD:
       g_snprintf(errmsg_errno, sizeof(errmsg_errno),
-               "The capture file appears to be damaged or corrupt.\n(%s)",
-               err_info);
+                 "The capture file appears to be damaged or corrupt.\n(%s)",
+                 err_info);
       g_free(err_info);
       errmsg = errmsg_errno;
       break;
 
     default:
       g_snprintf(errmsg_errno, sizeof(errmsg_errno),
-           "An error occurred while reading the"
-           " capture file: %s.", wtap_strerror(err));
+                 "An error occurred while reading the"
+                 " capture file: %s.", wtap_strerror(err));
       errmsg = errmsg_errno;
       break;
     }
@@ -761,7 +774,6 @@ cf_continue_tail(capture_file *cf, volatile int to_read, int *err)
   dfilter_t   *dfcode;
   gboolean filtering_tap_listeners;
   guint tap_flags;
-  volatile gboolean visible = FALSE;
   gboolean compiled;
 
   /* Compile the current display filter.
@@ -779,59 +791,53 @@ cf_continue_tail(capture_file *cf, volatile int to_read, int *err)
 
   *err = 0;
 
-#ifdef NEW_PACKET_LIST
   new_packet_list_check_end();
-  new_packet_list_freeze();
-#else
-  packet_list_check_end();
-  packet_list_freeze();
-#endif
+  /* Don't freeze/thaw the list when doing live capture */
+  /*new_packet_list_freeze();*/
 
   /*g_log(NULL, G_LOG_LEVEL_MESSAGE, "cf_continue_tail: %u new: %u", cf->count, to_read);*/
 
-  while (to_read != 0 && (wtap_read(cf->wth, err, &err_info, &data_offset))) {
+  while (to_read != 0) {
+    wtap_cleareof(cf->wth);
+    if (!wtap_read(cf->wth, err, &err_info, &data_offset)) {
+      break;
+    }
     if (cf->state == FILE_READ_ABORTED) {
       /* Well, the user decided to exit Wireshark.  Break out of the
          loop, and let the code below (which is called even if there
-     aren't any packets left to read) exit. */
+         aren't any packets left to read) exit. */
       break;
     }
     TRY{
-        if (read_packet(cf, dfcode, filtering_tap_listeners, tap_flags,
-                        data_offset) != -1) {
-            visible = TRUE;
-            newly_displayed_packets++;
-        }else{
-            visible = FALSE;
-        }
+      if (read_packet(cf, dfcode, filtering_tap_listeners, tap_flags,
+                      data_offset) != -1) {
+        newly_displayed_packets++;
+      }
     }
     CATCH(OutOfMemoryError) {
-        gpointer dialog;
-
-        dialog = simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
-              "%sOut Of Memory!%s\n"
-              "\n"
-              "Sorry, but Wireshark has to terminate now!\n"
-              "\n"
-              "The capture file is not lost, it can be found at:\n"
-              "%s\n"
-              "\n"
-              "Some infos / workarounds can be found at:\n"
-              "http://wiki.wireshark.org/KnownBugs/OutOfMemory",
-              simple_dialog_primary_start(), simple_dialog_primary_end(), cf->filename);
-        /* we have to terminate, as we cannot recover from the memory error */
-        simple_dialog_set_cb(dialog, outofmemory_cb, NULL);
-        while(1) {
-            main_window_update();
-            /* XXX - how to avoid a busy wait? */
-            /* Sleep(100); */
-        };
-#ifdef NEW_PACKET_LIST
-        new_packet_list_thaw();
-#else
-        packet_list_thaw();
-#endif
-        return CF_READ_ABORTED;
+      gpointer dialog;
+
+      dialog = simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+                             "%sOut Of Memory!%s\n"
+                             "\n"
+                             "Sorry, but Wireshark has to terminate now!\n"
+                             "\n"
+                             "The capture file is not lost, it can be found at:\n"
+                             "%s\n"
+                             "\n"
+                             "Some infos / workarounds can be found at:\n"
+                             "http://wiki.wireshark.org/KnownBugs/OutOfMemory",
+                             simple_dialog_primary_start(), simple_dialog_primary_end(), cf->filename);
+      /* we have to terminate, as we cannot recover from the memory error */
+      simple_dialog_set_cb(dialog, outofmemory_cb, NULL);
+      while(1) {
+        main_window_update();
+        /* XXX - how to avoid a busy wait? */
+        /* Sleep(100); */
+      };
+      /* Don't freeze/thaw the list when doing live capture */
+      /*new_packet_list_thaw();*/
+      return CF_READ_ABORTED;
     }
     ENDTRY;
     to_read--;
@@ -843,28 +849,20 @@ cf_continue_tail(capture_file *cf, volatile int to_read, int *err)
   }
 
   /*g_log(NULL, G_LOG_LEVEL_MESSAGE, "cf_continue_tail: count %u state: %u err: %u",
-      cf->count, cf->state, *err);*/
+    cf->count, cf->state, *err);*/
 
-#ifdef NEW_PACKET_LIST
-  new_packet_list_thaw();
-#else
-  /* XXX - this causes "flickering" of the list */
-  packet_list_thaw();
-#endif
+  /* Don't freeze/thaw the list when doing live capture */
+  /*new_packet_list_thaw();*/
+  /* With the new packet list the first packet
+   * isn't automatically selected.
+   */
+  if(!cf->current_frame)
+    new_packet_list_select_first_row();
 
   /* moving to the end of the packet list - if the user requested so and
      we have some new packets. */
   if (newly_displayed_packets && auto_scroll_live && cf->plist_end != NULL)
-#ifdef NEW_PACKET_LIST
-    if(visible)
       new_packet_list_moveto_end();
-#else
-    /* this doesn't seem to work well with a frozen GTK_Clist, so do this after
-       packet_list_thaw() is done, see bugzilla 1188 */
-    /* XXX - this cheats and looks inside the packet list to find the final
-       row number. */
-    packet_list_moveto_end();
-#endif /* NEW_PACKET_LIST */
 
   if (cf->state == FILE_READ_ABORTED) {
     /* Well, the user decided to exit Wireshark.  Return CF_READ_ABORTED
@@ -884,6 +882,11 @@ cf_continue_tail(capture_file *cf, volatile int to_read, int *err)
     return CF_READ_OK;
 }
 
+void
+cf_fake_continue_tail(capture_file *cf) {
+  cf->state = FILE_READ_DONE;
+}
+
 cf_read_status_t
 cf_finish_tail(capture_file *cf, int *err)
 {
@@ -912,13 +915,9 @@ cf_finish_tail(capture_file *cf, int *err)
     return CF_READ_ERROR;
   }
 
-#ifdef NEW_PACKET_LIST
   new_packet_list_check_end();
-  new_packet_list_freeze();
-#else
-  packet_list_check_end();
-  packet_list_freeze();
-#endif
+  /* Don't freeze/thaw the list when doing live capture */
+  /*new_packet_list_freeze();*/
 
   while ((wtap_read(cf->wth, err, &err_info, &data_offset))) {
     if (cf->state == FILE_READ_ABORTED) {
@@ -935,11 +934,8 @@ cf_finish_tail(capture_file *cf, int *err)
     dfilter_free(dfcode);
   }
 
-#ifdef NEW_PACKET_LIST
-  new_packet_list_thaw();
-#else
-  packet_list_thaw();
-#endif
+  /* Don't freeze/thaw the list when doing live capture */
+  /*new_packet_list_thaw();*/
 
   if (cf->state == FILE_READ_ABORTED) {
     /* Well, the user decided to abort the read.  We're only called
@@ -952,13 +948,7 @@ cf_finish_tail(capture_file *cf, int *err)
   }
 
   if (auto_scroll_live && cf->plist_end != NULL)
-#ifdef NEW_PACKET_LIST
     new_packet_list_moveto_end();
-#else
-    /* XXX - this cheats and looks inside the packet list to find the final
-       row number. */
-    packet_list_moveto_end();
-#endif
 
   /* We're done reading sequentially through the file. */
   cf->state = FILE_READ_DONE;
@@ -1003,68 +993,91 @@ cf_get_display_name(capture_file *cf)
   } else {
     /* The file we read is a temporary file from a live capture;
        we don't mention its name. */
-    displayname = "(Untitled)";
+    if (cf->source) {
+      displayname = cf->source;
+    } else {
+      displayname = "(Untitled)";
+    }
   }
   return displayname;
 }
 
+void cf_set_tempfile_source(capture_file *cf, gchar *source) {
+  if (cf->source) {
+    g_free(cf->source);
+  }
+
+  if (source) {
+    cf->source = g_strdup(source);
+  } else {
+    cf->source = g_strdup("");
+  }
+}
+
+const gchar *cf_get_tempfile_source(capture_file *cf) {
+  if (!cf->source) {
+    return "";
+  }
+
+  return cf->source;
+}
+
 /* XXX - use a macro instead? */
 int
 cf_get_packet_count(capture_file *cf)
 {
-    return cf->count;
+  return cf->count;
 }
 
 /* XXX - use a macro instead? */
 void
 cf_set_packet_count(capture_file *cf, int packet_count)
 {
-    cf->count = packet_count;
+  cf->count = packet_count;
 }
 
 /* XXX - use a macro instead? */
 gboolean
 cf_is_tempfile(capture_file *cf)
 {
-    return cf->is_tempfile;
+  return cf->is_tempfile;
 }
 
 void cf_set_tempfile(capture_file *cf, gboolean is_tempfile)
 {
-    cf->is_tempfile = is_tempfile;
+  cf->is_tempfile = is_tempfile;
 }
 
 
 /* XXX - use a macro instead? */
 void cf_set_drops_known(capture_file *cf, gboolean drops_known)
 {
-    cf->drops_known = drops_known;
+  cf->drops_known = drops_known;
 }
 
 /* XXX - use a macro instead? */
 void cf_set_drops(capture_file *cf, guint32 drops)
 {
-    cf->drops = drops;
+  cf->drops = drops;
 }
 
 /* XXX - use a macro instead? */
 gboolean cf_get_drops_known(capture_file *cf)
 {
-    return cf->drops_known;
+  return cf->drops_known;
 }
 
 /* XXX - use a macro instead? */
 guint32 cf_get_drops(capture_file *cf)
 {
-    return cf->drops;
+  return cf->drops;
 }
 
 void cf_set_rfcode(capture_file *cf, dfilter_t *rfcode)
 {
-    cf->rfcode = rfcode;
+  cf->rfcode = rfcode;
 }
 
-#ifdef NEW_PACKET_LIST
 static int
 add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
     dfilter_t *dfcode, gboolean filtering_tap_listeners,
@@ -1080,43 +1093,8 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
 
   cinfo = (tap_flags & TL_REQUIRES_COLUMNS) ? &cf->cinfo : NULL;
 
-  /* just add some value here until we know if it is being displayed or not */
-  fdata->cum_bytes = cum_bytes + fdata->pkt_len;
-
-  /* If we don't have the time stamp of the first packet in the
-     capture, it's because this is the first packet.  Save the time
-     stamp of this packet as the time stamp of the first packet. */
-  if (nstime_is_unset(&first_ts)) {
-    first_ts  = fdata->abs_ts;
-  }
-  /* if this frames is marked as a reference time frame, reset
-     firstsec and firstusec to this frame */
-  if(fdata->flags.ref_time){
-    first_ts = fdata->abs_ts;
-  }
-
-  /* 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 (nstime_is_unset(&prev_dis_ts)) {
-    prev_dis_ts = fdata->abs_ts;
-  }
-
-  /* Get the time elapsed between the first packet and this packet. */
-  nstime_delta(&fdata->rel_ts, &fdata->abs_ts, &first_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
-     time moving backwards). */
-  if ((gint32)cf->elapsed_time.secs < fdata->rel_ts.secs
-  || ((gint32)cf->elapsed_time.secs == fdata->rel_ts.secs && (gint32)cf->elapsed_time.nsecs < fdata->rel_ts.nsecs)) {
-    cf->elapsed_time = fdata->rel_ts;
-  }
-
-  /* Get the time elapsed between the previous displayed packet and
-     this packet. */
-  nstime_delta(&fdata->del_dis_ts, &fdata->abs_ts, &prev_dis_ts);
+  frame_data_set_before_dissect(fdata, &cf->elapsed_time,
+                                &first_ts, &prev_dis_ts, &prev_cap_ts);
 
   /* If either
     + we have a display filter and are re-applying it;
@@ -1152,24 +1130,17 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
   } else
     fdata->flags.passed_dfilter = 1;
 
+  if(fdata->flags.passed_dfilter || fdata->flags.ref_time)
+    cf->displayed_count++;
+
   if (add_to_packet_list) {
     /* We fill the needed columns from new_packet_list */
       row = new_packet_list_append(cinfo, fdata, &edt.pi);
   }
 
-  if( (fdata->flags.passed_dfilter) || (fdata->flags.ref_time) )
+  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 */
-    if(fdata->flags.ref_time){
-      /* if this was a TIME REF frame we should reset the cul bytes field */
-      cum_bytes = fdata->pkt_len;
-      fdata->cum_bytes = cum_bytes;
-    } else {
-      /* increase cum_bytes with this packets length */
-      cum_bytes += fdata->pkt_len;
-    }
+    frame_data_set_after_dissect(fdata, &cum_bytes, &prev_dis_ts);
 
     /* If we haven't yet seen the first frame, this is it.
 
@@ -1189,178 +1160,21 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
 
     /* This is the last frame we've seen so far. */
     cf->last_displayed = fdata;
-
-    /* Set the time of the previous displayed frame to the time of this
-       frame. */
-    prev_dis_ts = fdata->abs_ts;
-
-    cf->displayed_count++;
   }
 
   epan_dissect_cleanup(&edt);
   return row;
 }
 
-#else
-
-static int
-add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
-    dfilter_t *dfcode, gboolean filtering_tap_listeners,
-    guint tap_flags,
-    union wtap_pseudo_header *pseudo_header, const guchar *buf,
-    gboolean refilter,
-    gboolean add_to_packet_list _U_)
+/*
+ * Initialize the col_text and col_text_len arrays.
+ */
+static void
+init_col_text(frame_data *fdata, gint num_cols)
 {
-  gboolean  create_proto_tree = FALSE;
-  epan_dissect_t edt;
-  column_info *cinfo;
-  gint row = -1;
-
-  cinfo = &cf->cinfo;
-
-  /* just add some value here until we know if it is being displayed or not */
-  fdata->cum_bytes  = cum_bytes + fdata->pkt_len;
-
-  /* If we don't have the time stamp of the first packet in the
-     capture, it's because this is the first packet.  Save the time
-     stamp of this packet as the time stamp of the first packet. */
-  if (nstime_is_unset(&first_ts)) {
-    first_ts  = fdata->abs_ts;
-  }
-  /* if this frames is marked as a reference time frame, reset
-     firstsec and firstusec to this frame */
-  if(fdata->flags.ref_time){
-    first_ts = fdata->abs_ts;
-  }
-
-  /* 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 (nstime_is_unset(&prev_dis_ts)) {
-    prev_dis_ts = fdata->abs_ts;
-  }
-
-  /* Get the time elapsed between the first packet and this packet. */
-  nstime_delta(&fdata->rel_ts, &fdata->abs_ts, &first_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
-     time moving backwards). */
-  if ((gint32)cf->elapsed_time.secs < fdata->rel_ts.secs
-  || ((gint32)cf->elapsed_time.secs == fdata->rel_ts.secs && (gint32)cf->elapsed_time.nsecs < fdata->rel_ts.nsecs)) {
-    cf->elapsed_time = fdata->rel_ts;
-  }
-
-  /* Get the time elapsed between the previous displayed packet and
-     this packet. */
-  nstime_delta(&fdata->del_dis_ts, &fdata->abs_ts, &prev_dis_ts);
-
-  /* If either
-
-    we have a display filter and are re-applying it;
-
-    we have a list of color filters;
-
-    we have tap listeners with filters;
-
-    we have tap listeners that require a protocol tree;
-
-    we have custom columns;
-
-     allocate a protocol tree root node, so that we'll construct
-     a protocol tree against which a filter expression can be
-     evaluated. */
-  if ((dfcode != NULL && refilter) ||
-      color_filters_used() ||
-      have_custom_cols(cinfo) ||
-      filtering_tap_listeners || (tap_flags & TL_REQUIRES_PROTO_TREE))
-      create_proto_tree = TRUE;
-
-  /* Dissect the frame. */
-  epan_dissect_init(&edt, create_proto_tree, FALSE);
-
-  if (dfcode != NULL && refilter) {
-      epan_dissect_prime_dfilter(&edt, dfcode);
-  }
-
-  /* prepare color filters */
-  color_filters_prime_edt(&edt);
-  col_custom_prime_edt(&edt, cinfo);
-
-  tap_queue_init(&edt);
-  epan_dissect_run(&edt, pseudo_header, buf, fdata, cinfo);
-  tap_push_tapped_queue(&edt);
-
-  /* If we have a display filter, apply it if we're refiltering, otherwise
-     leave the "passed_dfilter" flag alone.
-
-     If we don't have a display filter, set "passed_dfilter" to 1. */
-  if (dfcode != NULL) {
-    if (refilter) {
-      fdata->flags.passed_dfilter = dfilter_apply_edt(dfcode, &edt) ? 1 : 0;
-    }
-  } else
-    fdata->flags.passed_dfilter = 1;
-
-  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 */
-    if(fdata->flags.ref_time){
-      /* if this was a TIME REF frame we should reset the cul bytes field */
-      cum_bytes = fdata->pkt_len;
-      fdata->cum_bytes =  cum_bytes;
-    } else {
-      /* increase cum_bytes with this packets length */
-      cum_bytes += fdata->pkt_len;
-    }
-
-    epan_dissect_fill_in_columns(&edt, FALSE, TRUE);
-
-    /* If we haven't yet seen the first frame, this is it.
-
-       XXX - we must do this before we add the row to the display,
-       as, if the display's GtkCList's selection mode is
-       GTK_SELECTION_BROWSE, when the first entry is added to it,
-       "cf_select_packet()" will be called, and it will fetch the row
-       data for the 0th row, and will get a null pointer rather than
-       "fdata", as "gtk_clist_append()" won't yet have returned and
-       thus "gtk_clist_set_row_data()" won't yet have been called.
-
-       We thus need to leave behind bread crumbs so that
-       "cf_select_packet()" can find this frame.  See the comment
-       in "cf_select_packet()". */
-    if (cf->first_displayed == NULL)
-      cf->first_displayed = fdata;
-
-    /* This is the last frame we've seen so far. */
-    cf->last_displayed = fdata;
-
-    row = packet_list_append(cinfo->col_data, fdata);
-
-    /* colorize packet: first apply color filters
-     * then if packet is marked, use preferences to overwrite color
-     * we do both to make sure that when a packet gets un-marked, the
-     * color will be correctly set (fixes bug 2038)
-     */
-     fdata->color_filter = color_filters_colorize_packet(row, &edt);
-     if (fdata->flags.marked) {
-       packet_list_set_colors(row, &prefs.gui_marked_fg, &prefs.gui_marked_bg);
-     }
-
-    /* Set the time of the previous displayed frame to the time of this
-       frame. */
-    prev_dis_ts = fdata->abs_ts;
-
-    cf->displayed_count++;
-  }
-
-  epan_dissect_cleanup(&edt);
-  return row;
+  fdata->col_text_len = se_alloc0(sizeof(*fdata->col_text_len) * num_cols);
+  fdata->col_text = se_alloc0(sizeof(*fdata->col_text) * num_cols);
 }
-#endif
 
 /* read in a new packet */
 /* returns the row of the new packet in the packet list or -1 if not displayed */
@@ -1373,8 +1187,7 @@ read_packet(capture_file *cf, dfilter_t *dfcode,
   const guchar *buf = wtap_buf_ptr(cf->wth);
   frame_data   *fdata;
   int           passed;
-  frame_data   *plist_end;
-  int row = -1;
+  int           row = -1;
 
   cf->count++;
 
@@ -1387,32 +1200,9 @@ read_packet(capture_file *cf, dfilter_t *dfcode,
 #else
   fdata = g_mem_chunk_alloc(cf->plist_chunk);
 #endif
-  fdata->num = cf->count;
-  fdata->next = NULL;
-  fdata->prev = NULL;
-  fdata->pfd  = NULL;
-  fdata->pkt_len  = phdr->len;
-  fdata->cap_len  = phdr->caplen;
-  fdata->file_off = offset;
-  /* To save some memory, we coarcese it into a gint8 */
-  g_assert(phdr->pkt_encap <= G_MAXINT8);
-  fdata->lnk_t = (gint8) phdr->pkt_encap;
-  fdata->abs_ts.secs = phdr->ts.secs;
-  fdata->abs_ts.nsecs = phdr->ts.nsecs;
-  fdata->flags.encoding = CHAR_ASCII;
-  fdata->flags.visited = 0;
-  fdata->flags.marked = 0;
-  fdata->flags.ref_time = 0;
-  fdata->color_filter = NULL;
-#ifdef NEW_PACKET_LIST
-  fdata->col_text_len = se_alloc0(sizeof(fdata->col_text_len) * (cf->cinfo.num_cols));
-  fdata->col_text = se_alloc0(sizeof(fdata->col_text) * (cf->cinfo.num_cols));
-#endif
 
-  if (cf->plist_end != NULL)
-    nstime_delta(&fdata->del_cap_ts, &fdata->abs_ts, &cf->plist_end->abs_ts);
-  else
-    nstime_set_zero(&fdata->del_cap_ts);
+  frame_data_init(fdata, cf->count, phdr, offset, cum_bytes);
+  init_col_text(fdata, cf->cinfo.num_cols);
 
   passed = TRUE;
   if (cf->rfcode) {
@@ -1425,15 +1215,9 @@ read_packet(capture_file *cf, dfilter_t *dfcode,
   }
 
   if (passed) {
-    plist_end = cf->plist_end;
-    fdata->prev = plist_end;
-    if (plist_end != NULL)
-      plist_end->next = fdata;
-    else
-      cf->plist = fdata;
-    cf->plist_end = fdata;
+    cap_file_add_fdata(cf, fdata);
 
-    cf->f_datalen = offset + phdr->caplen;
+    cf->f_datalen = offset + fdata->cap_len;
 
     if (!cf->redissecting) {
       row = add_packet_to_packet_list(fdata, cf, dfcode,
@@ -1696,6 +1480,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;
+  GTimeVal     start_time;
 
   /* if new filter equals old one, do nothing unless told to do so */
   if (!force && strcmp(filter_new, filter_old) == 0) {
@@ -1743,355 +1528,94 @@ cf_filter_packets(capture_file *cf, gchar *dftext, gboolean force)
   /* We have a valid filter.  Replace the current filter. */
   g_free(cf->dfilter);
   cf->dfilter = dftext;
-
-  /* Now rescan the packet list, applying the new filter, but not
-     throwing away information constructed on a previous pass. */
-  if (dftext == NULL) {
-    rescan_packets(cf, "Resetting", "Filter", TRUE, FALSE);
-  } else {
-    rescan_packets(cf, "Filtering", dftext, TRUE, FALSE);
-  }
-
-  /* Cleanup and release all dfilter resources */
-  if (dfcode != NULL){
-    dfilter_free(dfcode);
-  }
-  return CF_OK;
-}
-
-void
-cf_colorize_packets(capture_file *cf)
-{
-  rescan_packets(cf, "Colorizing", "all packets", FALSE, FALSE);
-}
-
-void
-cf_reftime_packets(capture_file *cf)
-{
-
-#ifdef NEW_PACKET_LIST
-  ref_time_packets(cf);
-#else
-  rescan_packets(cf, "Reprocessing", "all packets", TRUE, TRUE);
-#endif
-}
-
-void
-cf_redissect_packets(capture_file *cf)
-{
-  rescan_packets(cf, "Reprocessing", "all packets", TRUE, TRUE);
-}
-
-/* Rescan the list of packets, reconstructing the CList.
-
-   "action" describes why we're doing this; it's used in the progress
-   dialog box.
-
-   "action_item" describes what we're doing; it's used in the progress
-   dialog box.
-
-   "refilter" is TRUE if we need to re-evaluate the filter expression.
-
-   "redissect" is TRUE if we need to make the dissectors reconstruct
-   any state information they have (because a preference that affects
-   some dissector has changed, meaning some dissector might construct
-   its state differently from the way it was constructed the last time). */
-
-/* Rescan packets with "old" packet list */
-#ifndef NEW_PACKET_LIST
-static void
-rescan_packets(capture_file *cf, const char *action, const char *action_item,
-        gboolean refilter, gboolean redissect)
-{
-  frame_data *fdata;
-  progdlg_t  *progbar = NULL;
-  gboolean    stop_flag;
-  int         count;
-  int         err;
-  gchar      *err_info;
-  frame_data *selected_frame, *preceding_frame, *following_frame, *prev_frame;
-  int         selected_row, prev_row, preceding_row, following_row;
-  gboolean    selected_frame_seen;
-  int         row;
-  float       progbar_val;
-  GTimeVal    start_time;
-  gchar       status_str[100];
-  int         progbar_nextstep;
-  int         progbar_quantum;
-  dfilter_t   *dfcode;
-  gboolean    filtering_tap_listeners;
-  guint       tap_flags;
-  gboolean    add_to_packet_list = TRUE;
-  gboolean compiled;
-
-  /* Compile the current display filter.
-   * We assume this will not fail since cf->dfilter is only set in
-   * cf_filter IFF the filter was valid.
-   */
-  compiled = dfilter_compile(cf->dfilter, &dfcode);
-  g_assert(!cf->dfilter || (compiled && dfcode));
-
-  /* Do we have any tap listeners with filters? */
-  filtering_tap_listeners = have_filtering_tap_listeners();
-
-  /* Get the union of the flags for all tap listeners. */
-  tap_flags = union_of_tap_listener_flags();
-
-  reset_tap_listeners();
-  /* Which frame, if any, is the currently selected frame?
-     XXX - should the selected frame or the focus frame be the "current"
-     frame, that frame being the one from which "Find Frame" searches
-     start? */
-  selected_frame = cf->current_frame;
-
-  /* We don't yet know what row that frame will be on, if any, after we
-     rebuild the clist, however. */
-  selected_row = -1;
-
-  /* Freeze the packet list while we redo it, so we don't get any
-     screen updates while it happens. */
-  packet_list_freeze();
-
-  /* Clear it out. */
-  packet_list_clear();
-
-  if (redissect) {
-    /* We need to re-initialize all the state information that protocols
-       keep, because some preference that controls a dissector has changed,
-       which might cause the state information to be constructed differently
-       by that dissector. */
-
-    /* We might receive new packets while redissecting, and we don't
-       want to dissect those before their time. */
-    cf->redissecting = TRUE;
-
-    /* Cleanup all data structures used for dissection. */
-    cleanup_dissection();
-    /* Initialize all data structures used for dissection. */
-    init_dissection();
-
-  }
-
-  /* We don't yet know which will be the first and last frames displayed. */
-  cf->first_displayed = NULL;
-  cf->last_displayed = NULL;
-
-  reset_elapsed();
-
-  /* We currently don't display any packets */
-  cf->displayed_count = 0;
-
-  /* Iterate through the list of frames.  Call a routine for each frame
-     to check whether it should be displayed and, if so, add it to
-     the display list. */
-  nstime_set_unset(&first_ts);
-  nstime_set_unset(&prev_dis_ts);
-  cum_bytes = 0;
-
-  /* Update the progress bar when it gets to this value. */
-  progbar_nextstep = 0;
-  /* When we reach the value that triggers a progress bar update,
-     bump that value by this amount. */
-  progbar_quantum = cf->count/N_PROGBAR_UPDATES;
-  /* Count of packets at which we've looked. */
-  count = 0;
-  /* Progress so far. */
-  progbar_val = 0.0f;
-
-  stop_flag = FALSE;
   g_get_current_time(&start_time);
 
-  row = -1;     /* no previous row yet */
-  prev_row = -1;
-  prev_frame = NULL;
-
-  preceding_row = -1;
-  preceding_frame = NULL;
-  following_row = -1;
-  following_frame = NULL;
-
-  selected_frame_seen = FALSE;
 
-  for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
-    /* Create the progress bar if necessary.
-       We check on every iteration of the loop, so that it takes no
-       longer than the standard time to create it (otherwise, for a
-       large file, we might take considerably longer than that standard
-       time in order to get to the next progress bar step). */
-    if (progbar == NULL)
-      progbar = delayed_create_progress_dlg(action, action_item, TRUE,
-                                            &stop_flag, &start_time,
-                                            progbar_val);
-
-    /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
-       when we update it, we have to run the GTK+ main loop to get it
-       to repaint what's pending, and doing so may involve an "ioctl()"
-       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 (count >= progbar_nextstep) {
-      /* let's not divide by zero. I should never be started
-       * with count == 0, so let's assert that
-       */
-      g_assert(cf->count > 0);
-      progbar_val = (gfloat) count / cf->count;
-
-      if (progbar != NULL) {
-        g_snprintf(status_str, sizeof(status_str),
-                  "%4u of %u frames", count, cf->count);
-        update_progress_dlg(progbar, progbar_val, status_str);
-      }
-
-      progbar_nextstep += progbar_quantum;
-    }
-
-    if (stop_flag) {
-      /* Well, the user decided to abort the filtering.  Just stop.
-
-         XXX - go back to the previous filter?  Users probably just
-     want not to wait for a filtering operation to finish;
-     unless we cancel by having no filter, reverting to the
-     previous filter will probably be even more expensive than
-     continuing the filtering, as it involves going back to the
-     beginning and filtering, and even with no filter we currently
-     have to re-generate the entire clist, which is also expensive.
-
-     I'm not sure what Network Monitor does, but it doesn't appear
-     to give you an unfiltered display if you cancel. */
-      break;
-    }
-
-    count++;
-
-    if (redissect) {
-      /* Since all state for the frame was destroyed, mark the frame
-       * as not visited, free the GSList referring to the state
-       * data (the per-frame data itself was freed by
-       * "init_dissection()"), and null out the GSList pointer.
-       */
-      fdata->flags.visited = 0;
-      frame_data_cleanup(fdata);
-    }
-
-    if (!wtap_seek_read (cf->wth, fdata->file_off, &cf->pseudo_header,
-        cf->pd, fdata->cap_len, &err, &err_info)) {
-            simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
-            cf_read_error_message(err, err_info), cf->filename);
-            break;
-    }
-
-    /* If the previous frame is displayed, and we haven't yet seen the
-       selected frame, remember that frame - it's the closest one we've
-       yet seen before the selected frame. */
-    if (prev_row != -1 && !selected_frame_seen) {
-      preceding_row = prev_row;
-      preceding_frame = prev_frame;
-    }
-    row = add_packet_to_packet_list(fdata, cf, dfcode, filtering_tap_listeners,
-                                    tap_flags, &cf->pseudo_header, cf->pd,
-                                    refilter,
-                                    add_to_packet_list);
-
-    /* If this frame is displayed, and this is the first frame we've
-       seen displayed after the selected frame, remember this frame -
-       it's the closest one we've yet seen at or after the selected
-       frame. */
-    if (row != -1 && selected_frame_seen && following_row == -1) {
-      following_row = row;
-      following_frame = fdata;
-    }
-    if (fdata == selected_frame) {
-      selected_row = row;
-      selected_frame_seen = TRUE;
-    }
-
-    /* Remember this row/frame - it'll be the previous row/frame
-       on the next pass through the loop. */
-    prev_row = row;
-    prev_frame = fdata;
+  /* Now rescan the packet list, applying the new filter, but not
+     throwing away information constructed on a previous pass. */
+  if (dftext == NULL) {
+    rescan_packets(cf, "Resetting", "Filter", TRUE, FALSE);
+  } else {
+    rescan_packets(cf, "Filtering", dftext, TRUE, FALSE);
   }
 
-  /* We are done redissecting the packet list. */
-  cf->redissecting = FALSE;
+  /* Cleanup and release all dfilter resources */
+  dfilter_free(dfcode);
 
-  if (redissect) {
-    /* Clear out what remains of the visited flags and per-frame data
-       pointers.
+  return CF_OK;
+}
 
-       XXX - that may cause various forms of bogosity when dissecting
-       these frames, as they won't have been seen by this sequential
-       pass, but the only alternative I see is to keep scanning them
-       even though the user requested that the scan stop, and that
-       would leave the user stuck with an Wireshark grinding on
-       until it finishes.  Should we just stick them with that? */
-    for (; fdata != NULL; fdata = fdata->next) {
-      fdata->flags.visited = 0;
-      frame_data_cleanup(fdata);
-    }
-  }
+void
+cf_reftime_packets(capture_file *cf)
+{
 
-  /* We're done filtering the packets; destroy the progress bar if it
-     was created. */
-  if (progbar != NULL)
-    destroy_progress_dlg(progbar);
+  ref_time_packets(cf);
+}
 
-  /* Unfreeze the packet list. */
-  packet_list_thaw();
+void
+cf_redissect_packets(capture_file *cf)
+{
+  rescan_packets(cf, "Reprocessing", "all packets", TRUE, TRUE);
+}
 
-  if (selected_row == -1) {
-    /* The selected frame didn't pass the filter. */
-    if (selected_frame == NULL) {
-      /* That's because there *was* no selected frame.  Make the first
-         displayed frame the current frame. */
-      selected_row = 0;
-    } else {
-      /* Find the nearest displayed frame to the selected frame (whether
-         it's before or after that frame) and make that the current frame.
-         If the next and previous displayed frames are equidistant from the
-         selected frame, choose the next one. */
-      g_assert(following_frame == NULL ||
-               following_frame->num >= selected_frame->num);
-      g_assert(preceding_frame == NULL ||
-               preceding_frame->num <= selected_frame->num);
-      if (following_frame == NULL) {
-        /* No frame after the selected frame passed the filter, so we
-           have to select the last displayed frame before the selected
-           frame. */
-        selected_row = preceding_row;
-      } else if (preceding_frame == NULL) {
-        /* No frame before the selected frame passed the filter, so we
-           have to select the first displayed frame after the selected
-           frame. */
-        selected_row = following_row;
-      } else {
-        /* Frames before and after the selected frame passed the filter, so
-           we'll select the previous frame */
-        selected_row = preceding_row;
-      }
-    }
-  }
+gboolean
+cf_read_frame_r(capture_file *cf, frame_data *fdata,
+                union wtap_pseudo_header *pseudo_header, guint8 *pd)
+{
+  int err;
+  gchar *err_info;
+  char errmsg_errno[1024+1];
 
-  if (selected_row == -1) {
-    /* There are no frames displayed at all. */
-    cf_unselect_packet(cf);
-  } else {
-    /* Either the frame that was selected passed the filter, or we've
-       found the nearest displayed frame to that frame.  Select it, make
-       it the focus row, and make it visible. */
-    if (selected_row == 0) {
-      /* Set to invalid to force update of packet list and packet details */
-      cf->current_row = -1;
+  if (!wtap_seek_read(cf->wth, fdata->file_off, pseudo_header, pd,
+                      fdata->cap_len, &err, &err_info)) {
+    switch (err) {
+
+    case WTAP_ERR_UNSUPPORTED_ENCAP:
+      g_snprintf(errmsg_errno, sizeof(errmsg_errno),
+                 "The file \"%%s\" has a packet with a network type that Wireshark doesn't support.\n(%s)",
+                 err_info);
+      g_free(err_info);
+      break;
+
+    case WTAP_ERR_BAD_RECORD:
+      g_snprintf(errmsg_errno, sizeof(errmsg_errno),
+                 "An error occurred while reading from the file \"%%s\": %s.\n(%s)",
+                 wtap_strerror(err), err_info);
+      g_free(err_info);
+      break;
+
+    default:
+      g_snprintf(errmsg_errno, sizeof(errmsg_errno),
+                 "An error occurred while reading from the file \"%%s\": %s.",
+                 wtap_strerror(err));
+      break;
     }
-    packet_list_set_selected_row(selected_row);
+    simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, errmsg_errno, cf->filename);
+    return FALSE;
   }
+  return TRUE;
+}
 
-  /* Cleanup and release all dfilter resources */
-  if (dfcode != NULL){
-    dfilter_free(dfcode);
-  }
+gboolean
+cf_read_frame(capture_file *cf, frame_data *fdata)
+{
+  return cf_read_frame_r(cf, fdata, &cf->pseudo_header, cf->pd);
 }
 
-#else
+/* Rescan the list of packets, reconstructing the CList.
+
+   "action" describes why we're doing this; it's used in the progress
+   dialog box.
+
+   "action_item" describes what we're doing; it's used in the progress
+   dialog box.
 
+   "refilter" is TRUE if we need to re-evaluate the filter expression.
+
+   "redissect" is TRUE if we need to make the dissectors reconstruct
+   any state information they have (because a preference that affects
+   some dissector has changed, meaning some dissector might construct
+   its state differently from the way it was constructed the last time). */
 static void
 rescan_packets(capture_file *cf, const char *action, const char *action_item,
         gboolean refilter, gboolean redissect)
@@ -2101,12 +1625,9 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item,
   progdlg_t  *progbar = NULL;
   gboolean    stop_flag;
   int         count;
-  int         err;
-  gchar      *err_info;
   frame_data *selected_frame, *preceding_frame, *following_frame, *prev_frame;
   int         selected_frame_num, preceding_frame_num, following_frame_num, prev_frame_num;
   gboolean    selected_frame_seen;
-  int         frame_num;
   float       progbar_val;
   GTimeVal    start_time;
   gchar       status_str[100];
@@ -2138,7 +1659,7 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item,
      start? */
   selected_frame = cf->current_frame;
 
-  /* Mark frane num as not found */
+  /* Mark frame num as not found */
   selected_frame_num = -1;
 
   /* Freeze the packet list while we redo it, so we don't get any
@@ -2170,8 +1691,6 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item,
   cf->first_displayed = NULL;
   cf->last_displayed = NULL;
 
-  reset_elapsed();
-
   /* We currently don't display any packets */
   cf->displayed_count = 0;
 
@@ -2180,6 +1699,7 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item,
      the display list. */
   nstime_set_unset(&first_ts);
   nstime_set_unset(&prev_dis_ts);
+  nstime_set_unset(&prev_cap_ts);
   cum_bytes = 0;
 
   /* Update the progress bar when it gets to this value. */
@@ -2196,7 +1716,6 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item,
   g_get_current_time(&start_time);
 
   /* no previous row yet */
-  frame_num = -1;
   prev_frame_num = -1;
   prev_frame = NULL;
 
@@ -2207,7 +1726,7 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item,
 
   selected_frame_seen = FALSE;
 
-  for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
+  for (fdata = cf->plist_start; fdata != NULL; fdata = fdata->next) {
     /* Create the progress bar if necessary.
        We check on every iteration of the loop, so that it takes no
        longer than the standard time to create it (otherwise, for a
@@ -2243,15 +1762,15 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item,
       /* Well, the user decided to abort the filtering.  Just stop.
 
          XXX - go back to the previous filter?  Users probably just
-     want not to wait for a filtering operation to finish;
-     unless we cancel by having no filter, reverting to the
-     previous filter will probably be even more expensive than
-     continuing the filtering, as it involves going back to the
-     beginning and filtering, and even with no filter we currently
-     have to re-generate the entire clist, which is also expensive.
-
-     I'm not sure what Network Monitor does, but it doesn't appear
-     to give you an unfiltered display if you cancel. */
+         want not to wait for a filtering operation to finish;
+         unless we cancel by having no filter, reverting to the
+         previous filter will probably be even more expensive than
+         continuing the filtering, as it involves going back to the
+         beginning and filtering, and even with no filter we currently
+         have to re-generate the entire clist, which is also expensive.
+
+         I'm not sure what Network Monitor does, but it doesn't appear
+         to give you an unfiltered display if you cancel. */
       break;
     }
 
@@ -2269,16 +1788,11 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item,
        * And after that fdata->col_text (which is allocated using se_alloc0())
        * no longer points to valid memory.
        */
-        fdata->col_text_len = se_alloc0(sizeof(fdata->col_text_len) * (cf->cinfo.num_cols));
-        fdata->col_text = se_alloc0(sizeof(fdata->col_text) * (cf->cinfo.num_cols));
+      init_col_text(fdata, cf->cinfo.num_cols);
     }
 
-    if (!wtap_seek_read (cf->wth, fdata->file_off, &cf->pseudo_header,
-        cf->pd, fdata->cap_len, &err, &err_info)) {
-            simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
-            cf_read_error_message(err, err_info), cf->filename);
-            break;
-    }
+    if (!cf_read_frame(cf, fdata))
+      break; /* error reading the frame */
 
     /* If the previous frame is displayed, and we haven't yet seen the
        selected frame, remember that frame - it's the closest one we've
@@ -2340,6 +1854,9 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item,
   if (!add_to_packet_list)
     new_packet_list_recreate_visible_rows();
 
+  /* Compute the time it took to filter the file */
+  compute_elapsed(&start_time);
+
   new_packet_list_thaw();
 
   if (selected_frame_num == -1) {
@@ -2385,6 +1902,8 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item,
     /* Either the frame that was selected passed the filter, or we've
        found the nearest displayed frame to that frame.  Select it, make
        it the focus row, and make it visible. */
+    /* Set to invalid to force update of packet list and packet details */
+    cf->current_row = -1;
     if (selected_frame_num == 0) {
       new_packet_list_select_first_row();
     }else{
@@ -2393,18 +1912,15 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item,
   }
 
   /* Cleanup and release all dfilter resources */
-  if (dfcode != NULL){
-    dfilter_free(dfcode);
-  }
+  dfilter_free(dfcode);
 }
-#endif /* NEW_PACKET_LIST */
+
 
 /*
  * Scan trough all frame data and recalculate the ref time
  * without rereading the file.
  * XXX - do we need a progres bar or is this fast enough?
  */
-#ifdef NEW_PACKET_LIST
 static void
 ref_time_packets(capture_file *cf)
 {
@@ -2414,11 +1930,13 @@ ref_time_packets(capture_file *cf)
   nstime_set_unset(&prev_dis_ts);
   cum_bytes = 0;
 
-  for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
-
-    fdata->cum_bytes  = cum_bytes + fdata->pkt_len;
+  for (fdata = cf->plist_start; fdata != NULL; fdata = fdata->next) {
     /* 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 = cum_bytes + fdata->pkt_len;
+
+    /*
+     *Timestamps
+     */
 
     /* 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
@@ -2429,7 +1947,7 @@ ref_time_packets(capture_file *cf)
       /* if this frames is marked as a reference time frame, reset
         firstsec and firstusec to this frame */
     if(fdata->flags.ref_time){
-    first_ts = fdata->abs_ts;
+        first_ts = fdata->abs_ts;
     }
 
     /* If we don't have the time stamp of the previous displayed packet,
@@ -2455,12 +1973,17 @@ ref_time_packets(capture_file *cf)
      this packet. */
     nstime_delta(&fdata->del_dis_ts, &fdata->abs_ts, &prev_dis_ts);
 
+    prev_dis_ts = fdata->abs_ts;
+
+    /*
+     * Byte counts
+     */
     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 */
         if(fdata->flags.ref_time){
-            /* if this was a TIME REF frame we should reset the cubytes field */
+            /* if this was a TIME REF frame we should reset the cum_bytes field */
             cum_bytes = fdata->pkt_len;
             fdata->cum_bytes =  cum_bytes;
         } else {
@@ -2470,7 +1993,6 @@ ref_time_packets(capture_file *cf)
     }
   }
 }
-#endif
 
 typedef enum {
   PSP_FINISHED,
@@ -2486,8 +2008,6 @@ process_specified_packets(capture_file *cf, packet_range_t *range,
     void *callback_args)
 {
   frame_data *fdata;
-  int         err;
-  gchar      *err_info;
   union wtap_pseudo_header pseudo_header;
   guint8      pd[WTAP_MAX_PACKET_SIZE+1];
   psp_return_t ret = PSP_FINISHED;
@@ -2519,7 +2039,7 @@ process_specified_packets(capture_file *cf, packet_range_t *range,
 
   /* Iterate through the list of packets, printing the packets that
      were selected by the current display filter.  */
-  for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
+  for (fdata = cf->plist_start; fdata != NULL; fdata = fdata->next) {
     /* Create the progress bar if necessary.
        We check on every iteration of the loop, so that it takes no
        longer than the standard time to create it (otherwise, for a
@@ -2574,11 +2094,8 @@ process_specified_packets(capture_file *cf, packet_range_t *range,
     }
 
     /* Get the packet */
-    if (!wtap_seek_read(cf->wth, fdata->file_off, &pseudo_header,
-                        pd, fdata->cap_len, &err, &err_info)) {
+    if (!cf_read_frame_r(cf, fdata, &pseudo_header, pd)) {
       /* Attempt to get the packet failed. */
-      simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
-                    cf_read_error_message(err, err_info), cf->filename);
       ret = PSP_FAILED;
       break;
     }
@@ -2707,6 +2224,7 @@ print_packet(capture_file *cf, frame_data *fdata,
   /* 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, pseudo_header, pd, fdata, &cf->cinfo);
     epan_dissect_fill_in_columns(&edt, FALSE, TRUE);
   } else
@@ -3039,6 +2557,7 @@ write_psml_packet(capture_file *cf, frame_data *fdata,
      if having custom columns. */
   proto_tree_needed = have_custom_cols(&cf->cinfo);
   epan_dissect_init(&edt, proto_tree_needed, proto_tree_needed);
+  col_custom_prime_edt(&edt, &cf->cinfo);
   epan_dissect_run(&edt, pseudo_header, pd, fdata, &cf->cinfo);
   epan_dissect_fill_in_columns(&edt, FALSE, TRUE);
 
@@ -3113,6 +2632,7 @@ write_csv_packet(capture_file *cf, frame_data *fdata,
      if having custom columns. */
   proto_tree_needed = have_custom_cols(&cf->cinfo);
   epan_dissect_init(&edt, proto_tree_needed, proto_tree_needed);
+  col_custom_prime_edt(&edt, &cf->cinfo);
   epan_dissect_run(&edt, pseudo_header, pd, fdata, &cf->cinfo);
   epan_dissect_fill_in_columns(&edt, FALSE, TRUE);
 
@@ -3181,257 +2701,93 @@ write_carrays_packet(capture_file *cf _U_, frame_data *fdata,
 {
   FILE *fh = argsp;
 
-  proto_tree_write_carrays(pd, fdata->cap_len, fdata->num, fh);
-  return !ferror(fh);
-}
-
-cf_print_status_t
-cf_write_carrays_packets(capture_file *cf, print_args_t *print_args)
-{
-  FILE        *fh;
-  psp_return_t ret;
-
-  fh = ws_fopen(print_args->file, "w");
-
-  if (fh == NULL)
-    return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
-
-  write_carrays_preamble(fh);
-
-  if (ferror(fh)) {
-    fclose(fh);
-    return CF_PRINT_WRITE_ERROR;
-  }
-
-  /* Iterate through the list of packets, printing the packets we were
-     told to print. */
-  ret = process_specified_packets(cf, &print_args->range,
-                  "Writing C Arrays",
-                  "selected packets", TRUE,
-                                  write_carrays_packet, fh);
-  switch (ret) {
-  case PSP_FINISHED:
-    /* Completed successfully. */
-    break;
-  case PSP_STOPPED:
-    /* Well, the user decided to abort the printing. */
-    break;
-  case PSP_FAILED:
-    /* Error while printing. */
-    fclose(fh);
-    return CF_PRINT_WRITE_ERROR;
-  }
-
-  write_carrays_finale(fh);
-
-  if (ferror(fh)) {
-    fclose(fh);
-    return CF_PRINT_WRITE_ERROR;
-  }
-
-  fclose(fh);
-  return CF_PRINT_OK;
-}
-
-#ifndef NEW_PACKET_LIST /* This function is not needed with the new packet list */
-
-/* Scan through the packet list and change all columns that use the
-   "command-line-specified" time stamp format to use the current
-   value of that format. */
-void
-cf_change_time_formats(capture_file *cf)
-{
-  int         i;
-  frame_data *fdata;
-  progdlg_t  *progbar = NULL;
-  gboolean    stop_flag;
-  int         count;
-  int         row;
-  float       progbar_val;
-  GTimeVal    start_time;
-  gchar       status_str[100];
-  int         progbar_nextstep;
-  int         progbar_quantum;
-  gboolean    sorted_by_frame_column;
-
-  /* Adjust timestamp precision if auto is selected */
-  cf_timestamp_auto_precision(cf);
-
-  /* Are there any columns with time stamps in the "command-line-specified"
-     format?
-
-     XXX - we have to force the "column is writable" flag on, as it
-     might be off from the last frame that was dissected. */
-  col_set_writable(&cf->cinfo, TRUE);
-  if (!check_col(&cf->cinfo, COL_CLS_TIME) &&
-      !check_col(&cf->cinfo, COL_ABS_TIME) &&
-      !check_col(&cf->cinfo, COL_ABS_DATE_TIME) &&
-      !check_col(&cf->cinfo, COL_REL_TIME) &&
-      !check_col(&cf->cinfo, COL_DELTA_TIME) &&
-      !check_col(&cf->cinfo, COL_DELTA_TIME_DIS)) {
-    /* No, there aren't any columns in that format, so we have no work
-       to do. */
-    return;
-  }
-
-  /* Freeze the packet list while we redo it, so we don't get any
-     screen updates while it happens. */
-  packet_list_freeze();
-
-  /* Update the progress bar when it gets to this value. */
-  progbar_nextstep = 0;
-  /* When we reach the value that triggers a progress bar update,
-     bump that value by this amount. */
-  progbar_quantum = cf->count/N_PROGBAR_UPDATES;
-  /* Count of packets at which we've looked. */
-  count = 0;
-  /* Progress so far. */
-  progbar_val = 0.0f;
-
-  /*  If the rows are currently sorted by the frame column then we know
-   *  the row number of each packet: it's the row number of the previously
-   *  displayed packet + 1.
-   *
-   *  Otherwise, if the display is sorted by a different column then we have
-   *  to use the O(N) packet_list_find_row_from_data() (thus making the job
-   *  of changing the time display format O(N**2)).
-   *
-   *  (XXX - In fact it's still O(N**2) because gtk_clist_set_text() takes
-   *  the row number and walks that many elements down the clist to find
-   *  the appropriate element.)
-   */
-  sorted_by_frame_column = FALSE;
-  for (i = 0; i < cf->cinfo.num_cols; i++) {
-    if (cf->cinfo.col_fmt[i] == COL_NUMBER)
-    {
-      sorted_by_frame_column = (i == packet_list_get_sort_column());
-      break;
-    }
-  }
-
-  stop_flag = FALSE;
-  g_get_current_time(&start_time);
-
-  /* Iterate through the list of packets, checking whether the packet
-     is in a row of the summary list and, if so, whether there are
-     any columns that show the time in the "command-line-specified"
-     format and, if so, update that row. */
-  for (fdata = cf->plist, row = -1; fdata != NULL; fdata = fdata->next) {
-    /* Create the progress bar if necessary.
-       We check on every iteration of the loop, so that it takes no
-       longer than the standard time to create it (otherwise, for a
-       large file, we might take considerably longer than that standard
-       time in order to get to the next progress bar step). */
-    if (progbar == NULL)
-      progbar = delayed_create_progress_dlg("Changing", "time display",
-        TRUE, &stop_flag, &start_time, progbar_val);
-
-    /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
-       when we update it, we have to run the GTK+ main loop to get it
-       to repaint what's pending, and doing so may involve an "ioctl()"
-       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 (count >= progbar_nextstep) {
-      /* let's not divide by zero. I should never be started
-       * with count == 0, so let's assert that
-       */
-      g_assert(cf->count > 0);
-
-      progbar_val = (gfloat) count / cf->count;
-
-      if (progbar != NULL) {
-        g_snprintf(status_str, sizeof(status_str),
-                   "%4u of %u packets", count, cf->count);
-        update_progress_dlg(progbar, progbar_val, status_str);
-      }
-
-      progbar_nextstep += progbar_quantum;
-    }
+  proto_tree_write_carrays(pd, fdata->cap_len, fdata->num, fh);
+  return !ferror(fh);
+}
 
-    if (stop_flag) {
-      /* Well, the user decided to abort the redisplay.  Just stop.
+cf_print_status_t
+cf_write_carrays_packets(capture_file *cf, print_args_t *print_args)
+{
+  FILE        *fh;
+  psp_return_t ret;
 
-         XXX - this leaves the time field in the old format in
-     frames we haven't yet processed.  So it goes; should we
-     simply not offer them the option of stopping? */
-      break;
-    }
+  fh = ws_fopen(print_args->file, "w");
 
-    count++;
+  if (fh == NULL)
+    return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
 
-    /* Find what row this packet is in. */
-    if (!sorted_by_frame_column) {
-      /* This function is O(N), so we try to avoid using it... */
-      row = packet_list_find_row_from_data(fdata);
-    } else {
-      /* ...which we do by maintaining a count of packets that are
-         being displayed (i.e., that have passed the display filter),
-         and using the current value of that count as the row number
-         (which is why we can only do it when the display is sorted
-         by the frame number). */
-      if (fdata->flags.passed_dfilter)
-        row++;
-      else
-        continue;
-    }
+  write_carrays_preamble(fh);
 
-    if (row != -1) {
-      /* This packet is in the summary list, on row "row". */
+  if (ferror(fh)) {
+    fclose(fh);
+    return CF_PRINT_WRITE_ERROR;
+  }
 
-      for (i = 0; i < cf->cinfo.num_cols; i++) {
-        if (col_has_time_fmt(&cf->cinfo, i)) {
-          /* This is one of the columns that shows the time in
-             "command-line-specified" format; update it. */
-          cf->cinfo.col_buf[i][0] = '\0';
-          col_set_fmt_time(fdata, &cf->cinfo, cf->cinfo.col_fmt[i], i);
-          packet_list_set_text(row, i, cf->cinfo.col_data[i]);
-        }
-      }
-    }
+  /* Iterate through the list of packets, printing the packets we were
+     told to print. */
+  ret = process_specified_packets(cf, &print_args->range,
+                  "Writing C Arrays",
+                  "selected packets", TRUE,
+                                  write_carrays_packet, fh);
+  switch (ret) {
+  case PSP_FINISHED:
+    /* Completed successfully. */
+    break;
+  case PSP_STOPPED:
+    /* Well, the user decided to abort the printing. */
+    break;
+  case PSP_FAILED:
+    /* Error while printing. */
+    fclose(fh);
+    return CF_PRINT_WRITE_ERROR;
   }
 
-  /* We're done redisplaying the packets; destroy the progress bar if it
-     was created. */
-  if (progbar != NULL)
-    destroy_progress_dlg(progbar);
+  write_carrays_finale(fh);
 
-  /* 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++) {
-    if (col_has_time_fmt(&cf->cinfo, i)) {
-      packet_list_set_time_width(cf->cinfo.col_fmt[i], i);
-    }
+  if (ferror(fh)) {
+    fclose(fh);
+    return CF_PRINT_WRITE_ERROR;
   }
 
-  /* Unfreeze the packet list. */
-  packet_list_thaw();
+  fclose(fh);
+  return CF_PRINT_OK;
 }
-#endif /* NEW_PACKET_LIST */
-
-
-typedef struct {
-    const char  *string;
-    size_t      string_len;
-    capture_file    *cf;
-    gboolean    frame_matched;
-} match_data;
 
 gboolean
-cf_find_packet_protocol_tree(capture_file *cf, const char *string)
+cf_find_packet_protocol_tree(capture_file *cf, const char *string,
+                             search_direction dir)
 {
   match_data        mdata;
 
   mdata.string = string;
   mdata.string_len = strlen(string);
-  return find_packet(cf, match_protocol_tree, &mdata);
+  return find_packet(cf, match_protocol_tree, &mdata, dir);
 }
 
-static gboolean
+gboolean
+cf_find_string_protocol_tree(capture_file *cf, proto_tree *tree,  match_data *mdata)
+{
+  mdata->frame_matched = FALSE;
+  mdata->string = convert_string_case(cf->sfilter, cf->case_type);
+  mdata->string_len = strlen(mdata->string);
+  mdata->cf = cf;
+  /* Iterate through all the nodes looking for matching text */
+  proto_tree_children_foreach(tree, match_subtree_text, mdata);
+  return mdata->frame_matched ? MR_MATCHED : MR_NOTMATCHED; 
+}
+
+static match_result
 match_protocol_tree(capture_file *cf, frame_data *fdata, void *criterion)
 {
   match_data        *mdata = criterion;
   epan_dissect_t    edt;
 
+  /* Load the frame's data. */
+  if (!cf_read_frame(cf, fdata)) {
+    /* Attempt to get the packet failed. */
+    return MR_ERROR;
+  }
+
   /* Construct the protocol tree, including the displayed text */
   epan_dissect_init(&edt, TRUE, TRUE);
   /* We don't need the column information */
@@ -3442,7 +2798,7 @@ match_protocol_tree(capture_file *cf, frame_data *fdata, void *criterion)
   mdata->frame_matched = FALSE;
   proto_tree_children_foreach(edt.tree, match_subtree_text, mdata);
   epan_dissect_cleanup(&edt);
-  return mdata->frame_matched;
+  return mdata->frame_matched ? MR_MATCHED : MR_NOTMATCHED;
 }
 
 static void
@@ -3450,15 +2806,15 @@ match_subtree_text(proto_node *node, gpointer data)
 {
   match_data    *mdata = (match_data*) data;
   const gchar   *string = mdata->string;
-  size_t    string_len = mdata->string_len;
+  size_t        string_len = mdata->string_len;
   capture_file  *cf = mdata->cf;
   field_info    *fi = PNODE_FINFO(node);
-  gchar     label_str[ITEM_LABEL_LENGTH];
-  gchar     *label_ptr;
-  size_t    label_len;
-  guint32   i;
-  guint8    c_char;
-  size_t    c_match = 0;
+  gchar         label_str[ITEM_LABEL_LENGTH];
+  gchar         *label_ptr;
+  size_t        label_len;
+  guint32       i;
+  guint8        c_char;
+  size_t        c_match = 0;
 
   g_assert(fi && "dissection with an invisible proto tree?");
 
@@ -3489,9 +2845,10 @@ match_subtree_text(proto_node *node, gpointer data)
     if (c_char == string[c_match]) {
       c_match++;
       if (c_match == string_len) {
-    /* No need to look further; we have a match */
-    mdata->frame_matched = TRUE;
-    return;
+        /* No need to look further; we have a match */
+        mdata->frame_matched = TRUE;
+        mdata->finfo = fi;
+        return;
       }
     } else
       c_match = 0;
@@ -3503,29 +2860,36 @@ match_subtree_text(proto_node *node, gpointer data)
 }
 
 gboolean
-cf_find_packet_summary_line(capture_file *cf, const char *string)
+cf_find_packet_summary_line(capture_file *cf, const char *string,
+                            search_direction dir)
 {
   match_data        mdata;
 
   mdata.string = string;
   mdata.string_len = strlen(string);
-  return find_packet(cf, match_summary_line, &mdata);
+  return find_packet(cf, match_summary_line, &mdata, dir);
 }
 
-static gboolean
+static match_result
 match_summary_line(capture_file *cf, frame_data *fdata, void *criterion)
 {
   match_data        *mdata = criterion;
   const gchar       *string = mdata->string;
-  size_t        string_len = mdata->string_len;
+  size_t            string_len = mdata->string_len;
   epan_dissect_t    edt;
   const char        *info_column;
-  size_t        info_column_len;
-  gboolean      frame_matched = FALSE;
-  gint          colx;
-  guint32       i;
-  guint8        c_char;
-  size_t        c_match = 0;
+  size_t            info_column_len;
+  match_result      result = MR_NOTMATCHED;
+  gint              colx;
+  guint32           i;
+  guint8            c_char;
+  size_t            c_match = 0;
+
+  /* Load the frame's data. */
+  if (!cf_read_frame(cf, fdata)) {
+    /* Attempt to get the packet failed. */
+    return MR_ERROR;
+  }
 
   /* Don't bother constructing the protocol tree */
   epan_dissect_init(&edt, FALSE, FALSE);
@@ -3539,23 +2903,23 @@ match_summary_line(capture_file *cf, frame_data *fdata, void *criterion)
       info_column = edt.pi.cinfo->col_data[colx];
       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);
-    if (c_char == string[c_match]) {
-      c_match++;
-      if (c_match == string_len) {
-        frame_matched = TRUE;
-        break;
-      }
-    } else
-      c_match = 0;
+        c_char = info_column[i];
+        if (cf->case_type)
+          c_char = toupper(c_char);
+        if (c_char == string[c_match]) {
+          c_match++;
+          if (c_match == string_len) {
+            result = MR_MATCHED;
+            break;
+          }
+        } else
+          c_match = 0;
       }
       break;
     }
   }
   epan_dissect_cleanup(&edt);
-  return frame_matched;
+  return result;
 }
 
 typedef struct {
@@ -3564,7 +2928,8 @@ typedef struct {
 } cbs_t;    /* "Counted byte string" */
 
 gboolean
-cf_find_packet_data(capture_file *cf, const guint8 *string, size_t string_size)
+cf_find_packet_data(capture_file *cf, const guint8 *string, size_t string_size,
+                    search_direction dir)
 {
   cbs_t info;
 
@@ -3577,35 +2942,41 @@ cf_find_packet_data(capture_file *cf, const guint8 *string, size_t string_size)
     switch (cf->scs_type) {
 
     case SCS_ASCII_AND_UNICODE:
-      return find_packet(cf, match_ascii_and_unicode, &info);
+      return find_packet(cf, match_ascii_and_unicode, &info, dir);
 
     case SCS_ASCII:
-      return find_packet(cf, match_ascii, &info);
+      return find_packet(cf, match_ascii, &info, dir);
 
     case SCS_UNICODE:
-      return find_packet(cf, match_unicode, &info);
+      return find_packet(cf, match_unicode, &info, dir);
 
     default:
       g_assert_not_reached();
       return FALSE;
     }
   } else
-    return find_packet(cf, match_binary, &info);
+    return find_packet(cf, match_binary, &info, dir);
 }
 
-static gboolean
+static match_result
 match_ascii_and_unicode(capture_file *cf, frame_data *fdata, void *criterion)
 {
-  cbs_t     *info = criterion;
-  const guint8  *ascii_text = info->data;
-  size_t    textlen = info->data_len;
-  gboolean  frame_matched;
-  guint32   buf_len;
-  guint32   i;
-  guint8    c_char;
-  size_t    c_match = 0;
-
-  frame_matched = FALSE;
+  cbs_t        *info = criterion;
+  const guint8 *ascii_text = info->data;
+  size_t       textlen = info->data_len;
+  match_result result;
+  guint32      buf_len;
+  guint32      i;
+  guint8       c_char;
+  size_t       c_match = 0;
+
+  /* Load the frame's data. */
+  if (!cf_read_frame(cf, fdata)) {
+    /* Attempt to get the packet failed. */
+    return MR_ERROR;
+  }
+
+  result = MR_NOTMATCHED;
   buf_len = fdata->pkt_len;
   for (i = 0; i < buf_len; i++) {
     c_char = cf->pd[i];
@@ -3613,33 +2984,39 @@ match_ascii_and_unicode(capture_file *cf, frame_data *fdata, void *criterion)
       c_char = toupper(c_char);
     if (c_char != 0) {
       if (c_char == ascii_text[c_match]) {
-    c_match++;
-    if (c_match == textlen) {
-      frame_matched = TRUE;
-      cf->search_pos = i; /* Save the position of the last character
-                   for highlighting the field. */
-      break;
-    }
+        c_match++;
+        if (c_match == textlen) {
+          result = MR_MATCHED;
+          cf->search_pos = i; /* Save the position of the last character
+                                 for highlighting the field. */
+          break;
+        }
       } else
-    c_match = 0;
+        c_match = 0;
     }
   }
-  return frame_matched;
+  return result;
 }
 
-static gboolean
+static match_result
 match_ascii(capture_file *cf, frame_data *fdata, void *criterion)
 {
-  cbs_t     *info = criterion;
-  const guint8  *ascii_text = info->data;
-  size_t    textlen = info->data_len;
-  gboolean  frame_matched;
-  guint32   buf_len;
-  guint32   i;
-  guint8    c_char;
-  size_t    c_match = 0;
-
-  frame_matched = FALSE;
+  cbs_t        *info = criterion;
+  const guint8 *ascii_text = info->data;
+  size_t       textlen = info->data_len;
+  match_result result;
+  guint32      buf_len;
+  guint32      i;
+  guint8       c_char;
+  size_t       c_match = 0;
+
+  /* Load the frame's data. */
+  if (!cf_read_frame(cf, fdata)) {
+    /* Attempt to get the packet failed. */
+    return MR_ERROR;
+  }
+
+  result = MR_NOTMATCHED;
   buf_len = fdata->pkt_len;
   for (i = 0; i < buf_len; i++) {
     c_char = cf->pd[i];
@@ -3648,30 +3025,36 @@ match_ascii(capture_file *cf, frame_data *fdata, void *criterion)
     if (c_char == ascii_text[c_match]) {
       c_match++;
       if (c_match == textlen) {
-    frame_matched = TRUE;
-    cf->search_pos = i; /* Save the position of the last character
-                   for highlighting the field. */
-    break;
+        result = MR_MATCHED;
+        cf->search_pos = i; /* Save the position of the last character
+                               for highlighting the field. */
+        break;
       }
     } else
       c_match = 0;
   }
-  return frame_matched;
+  return result;
 }
 
-static gboolean
+static match_result
 match_unicode(capture_file *cf, frame_data *fdata, void *criterion)
 {
-  cbs_t     *info = criterion;
-  const guint8  *ascii_text = info->data;
-  size_t    textlen = info->data_len;
-  gboolean  frame_matched;
-  guint32   buf_len;
-  guint32   i;
-  guint8    c_char;
-  size_t    c_match = 0;
-
-  frame_matched = FALSE;
+  cbs_t        *info = criterion;
+  const guint8 *ascii_text = info->data;
+  size_t       textlen = info->data_len;
+  match_result result;
+  guint32      buf_len;
+  guint32      i;
+  guint8       c_char;
+  size_t       c_match = 0;
+
+  /* Load the frame's data. */
+  if (!cf_read_frame(cf, fdata)) {
+    /* Attempt to get the packet failed. */
+    return MR_ERROR;
+  }
+
+  result = MR_NOTMATCHED;
   buf_len = fdata->pkt_len;
   for (i = 0; i < buf_len; i++) {
     c_char = cf->pd[i];
@@ -3681,86 +3064,148 @@ match_unicode(capture_file *cf, frame_data *fdata, void *criterion)
       c_match++;
       i++;
       if (c_match == textlen) {
-    frame_matched = TRUE;
-    cf->search_pos = i; /* Save the position of the last character
-                   for highlighting the field. */
-    break;
+        result = MR_MATCHED;
+        cf->search_pos = i; /* Save the position of the last character
+                               for highlighting the field. */
+        break;
       }
     } else
       c_match = 0;
   }
-  return frame_matched;
+  return result;
 }
 
-static gboolean
+static match_result
 match_binary(capture_file *cf, frame_data *fdata, void *criterion)
 {
-  cbs_t     *info = criterion;
-  const guint8  *binary_data = info->data;
-  size_t    datalen = info->data_len;
-  gboolean  frame_matched;
-  guint32   buf_len;
-  guint32   i;
-  size_t    c_match = 0;
-
-  frame_matched = FALSE;
+  cbs_t        *info = criterion;
+  const guint8 *binary_data = info->data;
+  size_t       datalen = info->data_len;
+  match_result result;
+  guint32      buf_len;
+  guint32      i;
+  size_t       c_match = 0;
+
+  /* Load the frame's data. */
+  if (!cf_read_frame(cf, fdata)) {
+    /* Attempt to get the packet failed. */
+    return MR_ERROR;
+  }
+
+  result = MR_NOTMATCHED;
   buf_len = fdata->pkt_len;
   for (i = 0; i < buf_len; i++) {
     if (cf->pd[i] == binary_data[c_match]) {
       c_match++;
       if (c_match == datalen) {
-    frame_matched = TRUE;
-    cf->search_pos = i; /* Save the position of the last character
-                   for highlighting the field. */
-    break;
+        result = MR_MATCHED;
+        cf->search_pos = i; /* Save the position of the last character
+                               for highlighting the field. */
+        break;
       }
     } else
       c_match = 0;
   }
-  return frame_matched;
+  return result;
 }
 
 gboolean
-cf_find_packet_dfilter(capture_file *cf, dfilter_t *sfcode)
+cf_find_packet_dfilter(capture_file *cf, dfilter_t *sfcode,
+                       search_direction dir)
 {
-  return find_packet(cf, match_dfilter, sfcode);
+  return find_packet(cf, match_dfilter, sfcode, dir);
 }
 
-static gboolean
+gboolean
+cf_find_packet_dfilter_string(capture_file *cf, const char *filter,
+                              search_direction dir)
+{
+  dfilter_t *sfcode;
+  gboolean result;
+
+  if (!dfilter_compile(filter, &sfcode)) {
+     /*
+      * XXX - this shouldn't happen, as the filter string is machine
+      * generated
+      */
+    return FALSE;
+  }
+  if (sfcode == NULL) {
+    /*
+     * XXX - this shouldn't happen, as the filter string is machine
+     * generated.
+     */
+    return FALSE;
+  }
+  result = find_packet(cf, match_dfilter, sfcode, dir);
+  dfilter_free(sfcode);
+  return result;
+}
+
+static match_result
 match_dfilter(capture_file *cf, frame_data *fdata, void *criterion)
 {
-  dfilter_t     *sfcode = criterion;
-  epan_dissect_t    edt;
-  gboolean      frame_matched;
+  dfilter_t      *sfcode = criterion;
+  epan_dissect_t edt;
+  match_result   result;
+
+  /* Load the frame's data. */
+  if (!cf_read_frame(cf, fdata)) {
+    /* Attempt to get the packet failed. */
+    return MR_ERROR;
+  }
 
   epan_dissect_init(&edt, TRUE, FALSE);
   epan_dissect_prime_dfilter(&edt, sfcode);
   epan_dissect_run(&edt, &cf->pseudo_header, cf->pd, fdata, NULL);
-  frame_matched = dfilter_apply_edt(sfcode, &edt);
+  result = dfilter_apply_edt(sfcode, &edt) ? MR_MATCHED : MR_NOTMATCHED;
   epan_dissect_cleanup(&edt);
-  return frame_matched;
+  return result;
+}
+
+gboolean
+cf_find_packet_marked(capture_file *cf, search_direction dir)
+{
+  return find_packet(cf, match_marked, NULL, dir);
+}
+
+static match_result
+match_marked(capture_file *cf _U_, frame_data *fdata, void *criterion _U_)
+{
+  return fdata->flags.marked ? MR_MATCHED : MR_NOTMATCHED;
+}
+
+gboolean
+cf_find_packet_time_reference(capture_file *cf, search_direction dir)
+{
+  return find_packet(cf, match_time_reference, NULL, dir);
+}
+
+static match_result
+match_time_reference(capture_file *cf _U_, frame_data *fdata, void *criterion _U_)
+{
+  return fdata->flags.ref_time ? MR_MATCHED : MR_NOTMATCHED;
 }
 
 static gboolean
 find_packet(capture_file *cf,
-            gboolean (*match_function)(capture_file *, frame_data *, void *),
-            void *criterion)
+            match_result (*match_function)(capture_file *, frame_data *, void *),
+            void *criterion, search_direction dir)
 {
-  frame_data *start_fd;
-  frame_data *fdata;
-  frame_data *new_fd = NULL;
-  progdlg_t  *progbar = NULL;
-  gboolean    stop_flag;
-  int         count;
-  int         err;
-  gchar      *err_info;
-  int         row;
-  float       progbar_val;
-  GTimeVal    start_time;
-  gchar       status_str[100];
-  int         progbar_nextstep;
-  int         progbar_quantum;
-  char       *title;
+  frame_data  *start_fd;
+  frame_data  *fdata;
+  frame_data  *new_fd = NULL;
+  progdlg_t   *progbar = NULL;
+  gboolean     stop_flag;
+  int          count;
+  int          row;
+  float        progbar_val;
+  GTimeVal     start_time;
+  gchar        status_str[100];
+  int          progbar_nextstep;
+  int          progbar_quantum;
+  const char  *title;
+  match_result result;
 
   start_fd = cf->current_frame;
   if (start_fd != NULL)  {
@@ -3781,7 +3226,6 @@ find_packet(capture_file *cf,
     stop_flag = FALSE;
     g_get_current_time(&start_time);
 
-    fdata = start_fd;
     title = cf->sfilter?cf->sfilter:"";
     for (;;) {
       /* Create the progress bar if necessary.
@@ -3823,7 +3267,7 @@ find_packet(capture_file *cf,
       }
 
       /* Go past the current frame. */
-      if (cf->sbackward) {
+      if (dir == SD_BACKWARD) {
         /* Go on to the previous frame. */
         fdata = fdata->prev;
         if (fdata == NULL) {
@@ -3837,18 +3281,12 @@ find_packet(capture_file *cf,
 
           if (prefs.gui_find_wrap)
           {
-              simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
-                            "%sBeginning of capture exceeded!%s\n\n"
-                            "Search is continued from the end of the capture.",
-                            simple_dialog_primary_start(), simple_dialog_primary_end());
+              statusbar_push_temporary_msg("Search reached the beginning. Continuing at end.");
               fdata = cf->plist_end;    /* wrap around */
           }
           else
           {
-              simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
-                            "%sBeginning of capture exceeded!%s\n\n"
-                            "Try searching forwards.",
-                            simple_dialog_primary_start(), simple_dialog_primary_end());
+              statusbar_push_temporary_msg("Search reached the beginning.");
               fdata = start_fd;        /* stay on previous packet */
           }
         }
@@ -3858,18 +3296,12 @@ find_packet(capture_file *cf,
         if (fdata == NULL) {
           if (prefs.gui_find_wrap)
           {
-              simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
-                            "%sEnd of capture exceeded!%s\n\n"
-                            "Search is continued from the start of the capture.",
-                            simple_dialog_primary_start(), simple_dialog_primary_end());
-              fdata = cf->plist;    /* wrap around */
+              statusbar_push_temporary_msg("Search reached the end. Continuing at beginning.");
+              fdata = cf->plist_start;    /* wrap around */
           }
           else
           {
-              simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
-                            "%sEnd of capture exceeded!%s\n\n"
-                            "Try searching backwards.",
-                            simple_dialog_primary_start(), simple_dialog_primary_end());
+              statusbar_push_temporary_msg("Search reached the end.");
               fdata = start_fd;     /* stay on previous packet */
           }
         }
@@ -3879,27 +3311,23 @@ find_packet(capture_file *cf,
 
       /* Is this packet in the display? */
       if (fdata->flags.passed_dfilter) {
-        /* Yes.  Load its data. */
-        if (!wtap_seek_read(cf->wth, fdata->file_off, &cf->pseudo_header,
-                cf->pd, fdata->cap_len, &err, &err_info)) {
-          /* Read error.  Report the error, and go back to the frame
+        /* Yes.  Does it match the search criterion? */
+        result = (*match_function)(cf, fdata, criterion);
+        if (result == MR_ERROR) {
+          /* Error; our caller has reported the error.  Go back to the frame
              where we started. */
-          simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
-            cf_read_error_message(err, err_info), cf->filename);
           new_fd = start_fd;
           break;
-        }
-
-    /* Does it match the search criterion? */
-    if ((*match_function)(cf, fdata, criterion)) {
+        } else if (result == MR_MATCHED) {
+          /* Yes.  Go to the new frame. */
           new_fd = fdata;
-          break;    /* found it! */
+          break;
         }
       }
 
       if (fdata == start_fd) {
         /* We're back to the frame we were on originally, and that frame
-       doesn't match the search filter.  The search failed. */
+           doesn't match the search filter.  The search failed. */
         break;
       }
     }
@@ -3911,28 +3339,21 @@ find_packet(capture_file *cf,
   }
 
   if (new_fd != NULL) {
-#ifdef NEW_PACKET_LIST
-      /* Find and select */
-      row = new_packet_list_find_row_from_data(fdata, TRUE);
-#else
-    /* We found a frame.  Find what row it's in. */
-    row = packet_list_find_row_from_data(new_fd);
-#endif /* NEW_PACKET_LIST */
+    /* Find and select */
+    cf->search_in_progress = TRUE;
+    row = new_packet_list_find_row_from_data(fdata, TRUE);
+    cf->search_in_progress = FALSE;
+    cf->search_pos = 0; /* Reset the position */
     if (row == -1) {
-        /* We didn't find a row even though we know that a frame
-         * exists that satifies the search criteria. This means that the
-         * frame isn't being displayed currently so we can't select it. */
-        simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
-                      "%sEnd of capture exceeded!%s\n\n"
-                      "The capture file is probably not fully loaded.",
-                      simple_dialog_primary_start(), simple_dialog_primary_end());
-        return FALSE;
+      /* We didn't find a row even though we know that a frame
+       * exists that satifies the search criteria. This means that the
+       * frame isn't being displayed currently so we can't select it. */
+      simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
+                    "%sEnd of capture exceeded!%s\n\n"
+                    "The capture file is probably not fully loaded.",
+                    simple_dialog_primary_start(), simple_dialog_primary_end());
+      return FALSE;
     }
-
-#ifndef NEW_PACKET_LIST
-    /* Select that row, make it the focus row, and make it visible. */
-    packet_list_set_selected_row(row);
-#endif /* NEW_PACKET_LIST */
     return TRUE;    /* success */
   } else
     return FALSE;   /* failure */
@@ -3942,101 +3363,39 @@ gboolean
 cf_goto_frame(capture_file *cf, guint fnumber)
 {
   frame_data *fdata;
-  int row;
 
-  for (fdata = cf->plist; fdata != NULL && fdata->num < fnumber; fdata = fdata->next)
+  for (fdata = cf->plist_start; fdata != NULL && fdata->num < fnumber; fdata = fdata->next)
     ;
 
   if (fdata == NULL) {
     /* we didn't find a packet with that packet number */
-    simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
-          "There is no packet with the packet number %u.", fnumber);
+    statusbar_push_temporary_msg("There is no packet number %u.", fnumber);
     return FALSE;   /* we failed to go to that packet */
   }
   if (!fdata->flags.passed_dfilter) {
     /* that packet currently isn't displayed */
     /* XXX - add it to the set of displayed packets? */
-    simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
-          "The packet number %u isn't currently being displayed.", fnumber);
+    statusbar_push_temporary_msg("Packet number %u isn't displayed.", fnumber);
     return FALSE;   /* we failed to go to that packet */
   }
 
-#ifdef NEW_PACKET_LIST
-  row = new_packet_list_find_row_from_data(fdata, TRUE);
-#else
-  /* We found that packet, and it's currently being displayed.
-     Find what row it's in. */
-  row = packet_list_find_row_from_data(fdata);
-  g_assert(row != -1);
-
-  /* Select that row, make it the focus row, and make it visible. */
-  packet_list_set_selected_row(row);
-#endif /* NEW_PACKET_LIST */
+  new_packet_list_find_row_from_data(fdata, TRUE);
   return TRUE;  /* we got to that packet */
 }
 
 gboolean
-cf_goto_top_frame(capture_file *cf _U_)
+cf_goto_top_frame()
 {
-#ifdef NEW_PACKET_LIST
   /* Find and select */
   new_packet_list_select_first_row();
-#else
-  frame_data *fdata;
-  int row;
-  frame_data *lowest_fdata = NULL;
-
-  for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
-    if (fdata->flags.passed_dfilter) {
-        lowest_fdata = fdata;
-        break;
-    }
-  }
-
-  if (lowest_fdata == NULL) {
-      return FALSE;
-  }
-
-  /* We found that packet, and it's currently being displayed.
-     Find what row it's in. */
-  row = packet_list_find_row_from_data(lowest_fdata);
-  g_assert(row != -1);
-
-  /* Select that row, make it the focus row, and make it visible. */
-  packet_list_set_selected_row(row);
-#endif /* NEW_PACKET_LIST */
   return TRUE;  /* we got to that packet */
 }
 
 gboolean
-cf_goto_bottom_frame(capture_file *cf _U_) /* cf is unused w/ NEW_PACKET_LIST */
+cf_goto_bottom_frame()
 {
-#ifdef NEW_PACKET_LIST
   /* Find and select */
   new_packet_list_select_last_row();
-#else
-  frame_data *fdata;
-  int row;
-  frame_data *highest_fdata = NULL;
-
-  for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
-    if (fdata->flags.passed_dfilter) {
-        highest_fdata = fdata;
-    }
-  }
-
-  if (highest_fdata == NULL) {
-      return FALSE;
-  }
-
-  /* We found that packet, and it's currently being displayed.
-     Find what row it's in. */
-  row = packet_list_find_row_from_data(highest_fdata);
-  g_assert(row != -1);
-
-  /* Select that row, make it the focus row, and make it visible. */
-  packet_list_set_selected_row(row);
-#endif /* NEW_PACKET_LIST */
   return TRUE;  /* we got to that packet */
 }
 
@@ -4067,15 +3426,9 @@ void
 cf_select_packet(capture_file *cf, int row)
 {
   frame_data *fdata;
-  int err;
-  gchar *err_info;
 
   /* Get the frame data struct pointer for this frame */
-#ifdef NEW_PACKET_LIST
   fdata = new_packet_list_get_row_data(row);
-#else
-  fdata = (frame_data *)packet_list_get_row_data(row);
-#endif
 
   if (fdata == NULL) {
     /* XXX - if a GtkCList's selection mode is GTK_SELECTION_BROWSE, when
@@ -4114,10 +3467,7 @@ cf_select_packet(capture_file *cf, int row)
   }
 
   /* Get the data in that frame. */
-  if (!wtap_seek_read (cf->wth, fdata->file_off, &cf->pseudo_header,
-               cf->pd, fdata->cap_len, &err, &err_info)) {
-    simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
-          cf_read_error_message(err, err_info), cf->filename);
+  if (!cf_read_frame (cf, fdata)) {
     return;
   }
 
@@ -4132,6 +3482,7 @@ cf_select_packet(capture_file *cf, int row)
   /* We don't need the columns here. */
   cf->edt = epan_dissect_new(TRUE, TRUE);
 
+  tap_build_interesting(cf->edt);
   epan_dissect_run(cf->edt, &cf->pseudo_header, cf->pd, cf->current_frame,
           NULL);
 
@@ -4195,6 +3546,32 @@ cf_unmark_frame(capture_file *cf, frame_data *frame)
   }
 }
 
+/*
+ * Ignore a particular frame.
+ */
+void
+cf_ignore_frame(capture_file *cf, frame_data *frame)
+{
+  if (! frame->flags.ignored) {
+    frame->flags.ignored = TRUE;
+    if (cf->count > cf->ignored_count)
+      cf->ignored_count++;
+  }
+}
+
+/*
+ * Un-ignore a particular frame.
+ */
+void
+cf_unignore_frame(capture_file *cf, frame_data *frame)
+{
+  if (frame->flags.ignored) {
+    frame->flags.ignored = FALSE;
+    if (cf->ignored_count > 0)
+      cf->ignored_count--;
+  }
+}
+
 typedef struct {
   wtap_dumper *pdh;
   const char  *fname;
@@ -4262,7 +3639,7 @@ cf_save(capture_file *cf, const char *fname, packet_range_t *range, guint save_f
   wtap_dumper  *pdh;
   save_callback_args_t callback_args;
 
-  cf_callback_invoke(cf_cb_file_safe_started, (gpointer) fname);
+  cf_callback_invoke(cf_cb_file_save_started, (gpointer)fname);
 
   /* don't write over an existing file. */
   /* this should've been already checked by our caller, just to be sure... */
@@ -4276,7 +3653,6 @@ cf_save(capture_file *cf, const char *fname, packet_range_t *range, guint save_f
 
   packet_range_process_init(range);
 
-
   if (packet_range_process_all(range) && save_format == cf->cd_t) {
     /* We're not filtering packets, and we're saving it in the format
        it's already in, so we can just move or copy the raw data. */
@@ -4284,7 +3660,7 @@ cf_save(capture_file *cf, const char *fname, packet_range_t *range, guint save_f
     if (cf->is_tempfile) {
       /* The file being saved is a temporary file from a live
          capture, so it doesn't need to stay around under that name;
-     first, try renaming the capture buffer file to the new name. */
+         first, try renaming the capture buffer file to the new name. */
 #ifndef _WIN32
       if (ws_rename(cf->filename, fname) == 0) {
         /* That succeeded - there's no need to copy the source file. */
@@ -4292,22 +3668,22 @@ cf_save(capture_file *cf, const char *fname, packet_range_t *range, guint save_f
     do_copy = FALSE;
       } else {
         if (errno == EXDEV) {
-      /* They're on different file systems, so we have to copy the
-         file. */
-      do_copy = TRUE;
+          /* They're on different file systems, so we have to copy the
+             file. */
+          do_copy = TRUE;
           from_filename = cf->filename;
-    } else {
-      /* The rename failed, but not because they're on different
-         file systems - put up an error message.  (Or should we
-         just punt and try to copy?  The only reason why I'd
-         expect the rename to fail and the copy to succeed would
-         be if we didn't have permission to remove the file from
-         the temporary directory, and that might be fixable - but
-         is it worth requiring the user to go off and fix it?) */
-      simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
-                file_rename_error_message(errno), fname);
-      goto fail;
-    }
+        } else {
+          /* The rename failed, but not because they're on different
+             file systems - put up an error message.  (Or should we
+             just punt and try to copy?  The only reason why I'd
+             expect the rename to fail and the copy to succeed would
+             be if we didn't have permission to remove the file from
+             the temporary directory, and that might be fixable - but
+             is it worth requiring the user to go off and fix it?) */
+          simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+                        file_rename_error_message(errno), fname);
+          goto fail;
+        }
       }
 #else
       do_copy = TRUE;
@@ -4375,7 +3751,7 @@ cf_save(capture_file *cf, const char *fname, packet_range_t *range, guint save_f
     }
   }
 
-  cf_callback_invoke(cf_cb_file_safe_finished, NULL);
+  cf_callback_invoke(cf_cb_file_save_finished, NULL);
 
   if (packet_range_process_all(range)) {
     /* We saved the entire capture, not just some packets from it.
@@ -4393,7 +3769,8 @@ cf_save(capture_file *cf, const char *fname, packet_range_t *range, guint save_f
     if ((cf_open(cf, fname, FALSE, &err)) == CF_OK) {
       /* XXX - report errors if this fails?
          What should we return if it fails or is aborted? */
-      switch (cf_read(cf)) {
+
+      switch (cf_read(cf, TRUE)) {
 
       case CF_READ_OK:
       case CF_READ_ERROR:
@@ -4409,13 +3786,13 @@ cf_save(capture_file *cf, const char *fname, packet_range_t *range, guint save_f
        correctly for the "no capture file open" state). */
     break;
       }
-      cf_callback_invoke(cf_cb_file_safe_reload_finished, NULL);
+      cf_callback_invoke(cf_cb_file_save_reload_finished, cf);
     }
   }
   return CF_OK;
 
 fail:
-  cf_callback_invoke(cf_cb_file_safe_failed, NULL);
+  cf_callback_invoke(cf_cb_file_save_failed, NULL);
   return CF_ERROR;
 }
 
@@ -4472,10 +3849,10 @@ cf_open_failure_alert_box(const char *filename, int err, gchar *err_info,
 
     case WTAP_ERR_UNSUPPORTED_ENCAP:
       if (for_writing) {
-    simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+        simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
               "Wireshark can't save this capture in that format.");
       } else {
-    simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+        simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
               "The file \"%s\" is a capture for a network type that Wireshark doesn't support.\n"
               "(%s)",
               filename, err_info);
@@ -4485,10 +3862,10 @@ cf_open_failure_alert_box(const char *filename, int err, gchar *err_info,
 
     case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
       if (for_writing) {
-    simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+        simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
               "Wireshark can't save this capture in that format.");
       } else {
-    simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+        simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
               "The file \"%s\" is a capture for a network type that Wireshark doesn't support.",
               filename);
       }
@@ -4505,11 +3882,11 @@ cf_open_failure_alert_box(const char *filename, int err, gchar *err_info,
 
     case WTAP_ERR_CANT_OPEN:
       if (for_writing) {
-    simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+        simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
               "The file \"%s\" could not be created for some unknown reason.",
               filename);
       } else {
-    simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+        simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
               "The file \"%s\" could not be opened for some unknown reason.",
               filename);
       }
@@ -4573,36 +3950,6 @@ file_rename_error_message(int err)
   return errmsg;
 }
 
-char *
-cf_read_error_message(int err, gchar *err_info)
-{
-  static char errmsg_errno[1024+1];
-
-  switch (err) {
-
-  case WTAP_ERR_UNSUPPORTED_ENCAP:
-    g_snprintf(errmsg_errno, sizeof(errmsg_errno),
-               "The file \"%%s\" has a packet with a network type that Wireshark doesn't support.\n(%s)",
-               err_info);
-    g_free(err_info);
-    break;
-
-  case WTAP_ERR_BAD_RECORD:
-    g_snprintf(errmsg_errno, sizeof(errmsg_errno),
-         "An error occurred while reading from the file \"%%s\": %s.\n(%s)",
-         wtap_strerror(err), err_info);
-    g_free(err_info);
-    break;
-
-  default:
-    g_snprintf(errmsg_errno, sizeof(errmsg_errno),
-         "An error occurred while reading from the file \"%%s\": %s.",
-         wtap_strerror(err));
-    break;
-  }
-  return errmsg_errno;
-}
-
 static void
 cf_write_failure_alert_box(const char *filename, int err)
 {
@@ -4674,7 +4021,7 @@ cf_reload(capture_file *cf) {
   is_tempfile = cf->is_tempfile;
   cf->is_tempfile = FALSE;
   if (cf_open(cf, filename, is_tempfile, &err) == CF_OK) {
-    switch (cf_read(cf)) {
+    switch (cf_read(cf, FALSE)) {
 
     case CF_READ_OK:
     case CF_READ_ERROR:
@@ -4704,3 +4051,16 @@ cf_reload(capture_file *cf) {
      we should free up our copy. */
   g_free(filename);
 }
+
+/*
+ * Editor modelines
+ *
+ * Local Variables:
+ * c-basic-offset: 2
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * ex: set shiftwidth=2 tabstop=8 expandtab
+ * :indentSize=2:tabSize=8:noTabs=true:
+ */