Add some debugging output to help track down an intermittent problem on
[obnox/wireshark/wip.git] / file.c
diff --git a/file.c b/file.c
index 33f663f0d9c8ad466e20f5f905c580b1ac6da647..afbb674471607a2a07f25d71e143d2a1c57341f7 100644 (file)
--- a/file.c
+++ b/file.c
@@ -126,7 +126,6 @@ static void cf_open_failure_alert_box(const char *filename, int err,
                       gchar *err_info, gboolean for_writing,
                       int file_type);
 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);
 static void ref_time_packets(capture_file *cf);
 /* Update the progress bar this many times when reading a file. */
@@ -289,7 +288,7 @@ cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
 
   /* The open succeeded.  Close whatever capture file we had open,
      and fill in the information for this file. */
-  cf_reset_state(cf);
+  cf_close(cf);
 
   /* Cleanup all data structures used for dissection. */
   cleanup_dissection();
@@ -331,24 +330,15 @@ cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
   } else
     cf->has_snap = TRUE;
 
+  /* Allocate a frame_data_sequence for the frames in this file */
+  cf->frames = new_frame_data_sequence();
+
   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)
-#else
-  /* memory chunks have been deprecated in favor of the slice allocator,
-   * which has been added in 2.10
-   */
-  cf->plist_chunk = g_mem_chunk_new("frame_data_chunk",
-    sizeof(frame_data),
-    FRAME_DATA_CHUNK_SIZE * sizeof(frame_data),
-    G_ALLOC_AND_FREE);
-  g_assert(cf->plist_chunk);
-#endif
-
   /* Adjust timestamp precision if auto is selected, col width will be adjusted */
   cf_timestamp_auto_precision(cf);
   /* XXX needed ? */
@@ -401,12 +391,22 @@ cf_reset_state(capture_file *cf)
 
   dfilter_free(cf->rfcode);
   cf->rfcode = NULL;
-  cap_file_free_frames(cf);
+  if (cf->frames != NULL) {
+    free_frame_data_sequence(cf->frames);
+    cf->frames = NULL;
+  }
+#ifdef WANT_PACKET_EDITOR
+  if (cf->edited_frames) {
+    g_tree_destroy(cf->edited_frames);
+    cf->edited_frames = NULL;
+  }
+#endif
   cf_unselect_packet(cf);   /* nothing to select */
   cf->first_displayed = 0;
   cf->last_displayed = 0;
 
-  /* No frame selected, no field in that frame selected. */
+  /* No frames, no frame selected, no field in that frame selected. */
+  cf->count = 0;
   cf->current_frame = 0;
   cf->current_row = 0;
   cf->finfo_selected = NULL;
@@ -464,17 +464,6 @@ calc_progbar_val(capture_file *cf, gint64 size, gint64 file_pos, gchar *status_s
      */
     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;
 
@@ -488,8 +477,8 @@ calc_progbar_val(capture_file *cf, gint64 size, gint64 file_pos, gchar *status_s
   }
 
   g_snprintf(status_str, status_size,
-            "%" G_GINT64_MODIFIER "dKB of %" G_GINT64_MODIFIER "dKB",
-            file_pos / 1024, size / 1024);
+             "%" G_GINT64_MODIFIER "dKB of %" G_GINT64_MODIFIER "dKB",
+             file_pos / 1024, size / 1024);
 
   return progbar_val;
 }
@@ -503,6 +492,7 @@ cf_read(capture_file *cf, gboolean from_save)
   const char  *errmsg;
   char         errmsg_errno[1024+1];
   gint64       data_offset;
+  gint64       file_pos;
   progdlg_t *volatile progbar = NULL;
   gboolean     stop_flag;
   volatile gint64 size;
@@ -558,6 +548,7 @@ cf_read(capture_file *cf, gboolean from_save)
   /* Progress so far. */
   progbar_val = 0.0f;
 
+  /* The packet list window will be empty untill the file is completly loaded */
   new_packet_list_freeze();
 
   stop_flag = FALSE;
@@ -566,11 +557,13 @@ cf_read(capture_file *cf, gboolean from_save)
   while ((wtap_read(cf->wth, &err, &err_info, &data_offset))) {
     if (size >= 0) {
       count++;
+      file_pos = wtap_read_so_far(cf->wth);
+
       /* Create the progress bar if necessary.
        * Check whether it should be created or not every MIN_NUMBER_OF_PACKET
        */
       if ((progbar == NULL) && !(count % MIN_NUMBER_OF_PACKET)){
-        progbar_val = calc_progbar_val(cf, size, data_offset, status_str, sizeof(status_str));
+        progbar_val = calc_progbar_val(cf, size, file_pos, status_str, sizeof(status_str));
         if (from_save == FALSE)
           progbar = delayed_create_progress_dlg("Loading", name_ptr,
                                                 TRUE, &stop_flag, &start_time, progbar_val);
@@ -584,19 +577,15 @@ cf_read(capture_file *cf, gboolean from_save)
          to repaint what's pending, and doing so may involve an "ioctl()"
          to see if there's any pending input from an X server, and doing
          that for every packet can be costly, especially on a big file. */
-      if (data_offset >= progbar_nextstep) {
+      if (file_pos >= progbar_nextstep) {
         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) */
+          progbar_val = calc_progbar_val(cf, size, file_pos, status_str, sizeof(status_str));
+          /* update the packet bar content on the first run or frequently on very large files */
 #ifdef HAVE_LIBPCAP
           if (progbar_quantum > 500000 || displayed_once == 0) {
             if ((auto_scroll_live || displayed_once == 0 || cf->displayed_count < 1000) && cf->count != 0) {
               displayed_once = 1;
-              new_packet_list_thaw();
-              if (auto_scroll_live)
-                new_packet_list_moveto_end();
-              new_packet_list_freeze();
+              packets_bar_update();
             }
           }
 #endif /* HAVE_LIBPCAP */
@@ -669,7 +658,7 @@ cf_read(capture_file *cf, gboolean from_save)
      WTAP_ENCAP_PER_PACKET). */
   cf->lnk_t = wtap_file_encap(cf->wth);
 
-  cf->current_frame = cap_file_find_fdata(cf, cf->first_displayed);
+  cf->current_frame = frame_data_sequence_find(cf->frames, cf->first_displayed);
   cf->current_row = 0;
 
   new_packet_list_thaw();
@@ -720,7 +709,7 @@ cf_read(capture_file *cf, gboolean from_save)
         " in the middle of a packet.";
       break;
 
-    case WTAP_ERR_BAD_RECORD:
+    case WTAP_ERR_BAD_FILE:
       g_snprintf(errmsg_errno, sizeof(errmsg_errno),
                  "The capture file appears to be damaged or corrupt.\n(%s)",
                  err_info);
@@ -1160,16 +1149,6 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
   return row;
 }
 
-/*
- * Initialize the col_text and col_text_len arrays.
- */
-static void
-init_col_text(frame_data *fdata, gint num_cols)
-{
-  fdata->col_text_len = se_alloc0(sizeof(*fdata->col_text_len) * num_cols);
-  fdata->col_text = se_alloc0(sizeof(*fdata->col_text) * num_cols);
-}
-
 /* read in a new packet */
 /* returns the row of the new packet in the packet list or -1 if not displayed */
 static int
@@ -1190,12 +1169,6 @@ read_packet(capture_file *cf, dfilter_t *dfcode,
   framenum = cf->count + 1;
 
   frame_data_init(&fdlocal, framenum, phdr, offset, cum_bytes);
-  /* Note - if the packet doesn't pass the read filter, and is thus
-     not added to the capture_file's collection of packets, the
-     column text arrays aren't free; they're alocated with
-     se_alloc0(), so they eventually get freed when we close the
-     file. */
-  init_col_text(&fdlocal, cf->cinfo.num_cols);
 
   passed = TRUE;
   if (cf->rfcode) {
@@ -1209,8 +1182,9 @@ read_packet(capture_file *cf, dfilter_t *dfcode,
 
   if (passed) {
     /* This does a shallow copy of fdlocal, which is good enough. */
-    fdata = cap_file_add_fdata(cf, &fdlocal);
+    fdata = frame_data_sequence_add(cf->frames, &fdlocal);
 
+    cf->count++;
     cf->f_datalen = offset + fdlocal.cap_len;
 
     if (!cf->redissecting) {
@@ -1227,8 +1201,7 @@ cf_status_t
 cf_merge_files(char **out_filenamep, int in_file_count,
                char *const *in_filenames, int file_type, gboolean do_append)
 {
-  merge_in_file_t  *in_files;
-  wtap             *wth;
+  merge_in_file_t  *in_files, *in_file;
   char             *out_filename;
   char             *tmpname;
   int               out_fd;
@@ -1311,14 +1284,19 @@ cf_merge_files(char **out_filenamep, int in_file_count,
   /* do the merge (or append) */
   for (;;) {
     if (do_append)
-      wth = merge_append_read_packet(in_file_count, in_files, &read_err,
-                                     &err_info);
+      in_file = merge_append_read_packet(in_file_count, in_files, &read_err,
+                                         &err_info);
     else
-      wth = merge_read_packet(in_file_count, in_files, &read_err,
-                              &err_info);
-    if (wth == NULL) {
-      if (read_err != 0)
-        got_read_error = TRUE;
+      in_file = merge_read_packet(in_file_count, in_files, &read_err,
+                                  &err_info);
+    if (in_file == NULL) {
+      /* EOF */
+      break;
+    }
+
+    if (read_err != 0) {
+      /* I/O error reading from in_file */
+      got_read_error = TRUE;
       break;
     }
 
@@ -1346,7 +1324,7 @@ cf_merge_files(char **out_filenamep, int in_file_count,
         /* Get the sum of the seek positions in all of the files. */
         file_pos = 0;
         for (i = 0; i < in_file_count; i++)
-          file_pos += wtap_read_so_far(in_files[i].wth, NULL);
+          file_pos += wtap_read_so_far(in_files[i].wth);
         progbar_val = (gfloat) file_pos / (gfloat) f_len;
         if (progbar_val > 1.0f) {
           /* Some file probably grew while we were reading it.
@@ -1368,8 +1346,8 @@ cf_merge_files(char **out_filenamep, int in_file_count,
       break;
     }
 
-    if (!wtap_dump(pdh, wtap_phdr(wth), wtap_pseudoheader(wth),
-         wtap_buf_ptr(wth), &write_err)) {
+    if (!wtap_dump(pdh, wtap_phdr(in_file->wth), wtap_pseudoheader(in_file->wth),
+         wtap_buf_ptr(in_file->wth), &write_err)) {
       got_write_error = TRUE;
       break;
     }
@@ -1392,51 +1370,51 @@ cf_merge_files(char **out_filenamep, int in_file_count,
      */
     for (i = 0; i < in_file_count; i++) {
       if (in_files[i].state == GOT_ERROR) {
-    /* Put up a message box noting that a read failed somewhere along
-       the line. */
-    switch (read_err) {
-
-    case WTAP_ERR_UNSUPPORTED_ENCAP:
-      g_snprintf(errmsg_errno, sizeof(errmsg_errno),
-           "The capture file %%s has a packet with a network type that Wireshark doesn't support.\n(%s)",
-           err_info);
-      g_free(err_info);
-      errmsg = errmsg_errno;
-      break;
+        /* Put up a message box noting that a read failed somewhere along
+           the line. */
+        switch (read_err) {
+
+        case WTAP_ERR_UNSUPPORTED_ENCAP:
+          g_snprintf(errmsg_errno, sizeof(errmsg_errno),
+                     "The capture file %%s has a packet with a network type that Wireshark doesn't support.\n(%s)",
+                     err_info);
+          g_free(err_info);
+          errmsg = errmsg_errno;
+          break;
 
-    case WTAP_ERR_CANT_READ:
-      errmsg = "An attempt to read from the capture file %s failed for"
-           " some unknown reason.";
-      break;
+        case WTAP_ERR_CANT_READ:
+          errmsg = "An attempt to read from the capture file %s failed for"
+                   " some unknown reason.";
+          break;
 
-    case WTAP_ERR_SHORT_READ:
-      errmsg = "The capture file %s appears to have been cut short"
-           " in the middle of a packet.";
-      break;
+        case WTAP_ERR_SHORT_READ:
+          errmsg = "The capture file %s appears to have been cut short"
+                   " in the middle of a packet.";
+          break;
 
-    case WTAP_ERR_BAD_RECORD:
-      g_snprintf(errmsg_errno, sizeof(errmsg_errno),
-           "The capture file %%s appears to be damaged or corrupt.\n(%s)",
-           err_info);
-      g_free(err_info);
-      errmsg = errmsg_errno;
-      break;
+        case WTAP_ERR_BAD_FILE:
+          g_snprintf(errmsg_errno, sizeof(errmsg_errno),
+                     "The capture file %%s appears to be damaged or corrupt.\n(%s)",
+                     err_info);
+          g_free(err_info);
+          errmsg = errmsg_errno;
+          break;
 
-    case WTAP_ERR_DECOMPRESS:
-      g_snprintf(errmsg_errno, sizeof(errmsg_errno),
-                 "The compressed capture file %%s appears to be damaged or corrupt.\n"
-                 "(%s)", err_info);
-      g_free(err_info);
-      errmsg = errmsg_errno;
-      break;
+        case WTAP_ERR_DECOMPRESS:
+          g_snprintf(errmsg_errno, sizeof(errmsg_errno),
+                     "The compressed capture file %%s 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: %s.", wtap_strerror(read_err));
-      errmsg = errmsg_errno;
-      break;
-    }
+        default:
+          g_snprintf(errmsg_errno, sizeof(errmsg_errno),
+                     "An error occurred while reading the"
+                     " capture file %%s: %s.", wtap_strerror(read_err));
+          errmsg = errmsg_errno;
+          break;
+        }
         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, errmsg, in_files[i].filename);
       }
     }
@@ -1444,7 +1422,31 @@ cf_merge_files(char **out_filenamep, int in_file_count,
 
   if (got_write_error) {
     /* Put up an alert box for the write error. */
-    cf_write_failure_alert_box(out_filename, write_err);
+    if (write_err < 0) {
+      /* Wiretap error. */
+      switch (write_err) {
+
+      case WTAP_ERR_UNSUPPORTED_ENCAP:
+        /*
+         * This is a problem with the particular frame we're writing;
+         * note that, and give the frame number.
+         */
+        simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+                      "Frame %u of \"%s\" has a network type that can't be saved in a \"%s\" file.",
+                      in_file->packet_num, in_file->filename,
+                      wtap_file_type_string(file_type));
+        break;
+
+      default:
+        simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+                      "An error occurred while writing to the file \"%s\": %s.",
+                      out_filename, wtap_strerror(write_err));
+        break;
+      }
+    } else {
+      /* OS error. */
+      write_failure_alert_box(out_filename, write_err);
+    }
   }
 
   if (got_read_error || got_write_error || stop_flag) {
@@ -1548,6 +1550,22 @@ cf_read_frame_r(capture_file *cf, frame_data *fdata,
   gchar *err_info;
   char errmsg_errno[1024+1];
 
+#ifdef WANT_PACKET_EDITOR
+  /* if fdata->file_off == -1 it means packet was edited, and we must find data inside edited_frames tree */
+  if (G_UNLIKELY(fdata->file_off == -1)) {
+    const modified_frame_data *frame = (const modified_frame_data *) g_tree_lookup(cf->edited_frames, GINT_TO_POINTER(fdata->num));
+
+    if (!frame) {
+      simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "fdata->file_off == -1, but can't find modified frame!");
+      return FALSE;
+    }
+
+    *pseudo_header = frame->ph;
+    memcpy(pd, frame->pd, fdata->cap_len);
+    return TRUE;
+  }
+#endif
+
   if (!wtap_seek_read(cf->wth, fdata->file_off, pseudo_header, pd,
                       fdata->cap_len, &err, &err_info)) {
     switch (err) {
@@ -1559,7 +1577,7 @@ cf_read_frame_r(capture_file *cf, frame_data *fdata,
       g_free(err_info);
       break;
 
-    case WTAP_ERR_BAD_RECORD:
+    case WTAP_ERR_BAD_FILE:
       g_snprintf(errmsg_errno, sizeof(errmsg_errno),
                  "An error occurred while reading from the file \"%%s\": %s.\n(%s)",
                  wtap_strerror(err), err_info);
@@ -1710,7 +1728,7 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item,
   selected_frame_seen = FALSE;
 
   for (framenum = 1; framenum <= cf->count; framenum++) {
-    fdata = cap_file_find_fdata(cf, framenum);
+    fdata = frame_data_sequence_find(cf->frames, framenum);
 
     /* Create the progress bar if necessary.
        We check on every iteration of the loop, so that it takes no
@@ -1768,12 +1786,6 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item,
        * "init_dissection()"), and null out the GSList pointer. */
       fdata->flags.visited = 0;
       frame_data_cleanup(fdata);
-
-      /* cleanup_dissection() calls se_free_all();
-       * And after that fdata->col_text (which is allocated using se_alloc0())
-       * no longer points to valid memory.
-       */
-      init_col_text(fdata, cf->cinfo.num_cols);
     }
 
     if (!cf_read_frame(cf, fdata))
@@ -1825,7 +1837,7 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item,
        would leave the user stuck with an Wireshark grinding on
        until it finishes.  Should we just stick them with that? */
     for (; framenum <= cf->count; framenum++) {
-      fdata = cap_file_find_fdata(cf, framenum);
+      fdata = frame_data_sequence_find(cf->frames, framenum);
       fdata->flags.visited = 0;
       frame_data_cleanup(fdata);
     }
@@ -1926,7 +1938,7 @@ ref_time_packets(capture_file *cf)
   cum_bytes = 0;
 
   for (framenum = 1; framenum <= cf->count; framenum++) {
-    fdata = cap_file_find_fdata(cf, framenum);
+    fdata = frame_data_sequence_find(cf->frames, framenum);
 
     /* just add some value here until we know if it is being displayed or not */
     fdata->cum_bytes = cum_bytes + fdata->pkt_len;
@@ -1966,11 +1978,12 @@ ref_time_packets(capture_file *cf)
         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);
-
-    prev_dis_ts = fdata->abs_ts;
+    /* If this frame is displayed, get the time elapsed between the 
+     previous displayed packet and this packet. */ 
+    if( fdata->flags.passed_dfilter ) {
+        nstime_delta(&fdata->del_dis_ts, &fdata->abs_ts, &prev_dis_ts);
+        prev_dis_ts = fdata->abs_ts;
+    }
 
     /*
      * Byte counts
@@ -2038,7 +2051,7 @@ process_specified_packets(capture_file *cf, packet_range_t *range,
   /* Iterate through all the packets, printing the packets that
      were selected by the current display filter.  */
   for (framenum = 1; framenum <= cf->count; framenum++) {
-    fdata = cap_file_find_fdata(cf, framenum);
+    fdata = frame_data_sequence_find(cf->frames, framenum);
 
     /* Create the progress bar if necessary.
        We check on every iteration of the loop, so that it takes no
@@ -2504,7 +2517,7 @@ cf_write_pdml_packets(capture_file *cf, print_args_t *print_args)
   if (fh == NULL)
     return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
 
-  write_pdml_preamble(fh);
+  write_pdml_preamble(fh, cf->filename);
   if (ferror(fh)) {
     fclose(fh);
     return CF_PRINT_WRITE_ERROR;
@@ -2696,12 +2709,17 @@ cf_write_csv_packets(capture_file *cf, print_args_t *print_args)
 
 static gboolean
 write_carrays_packet(capture_file *cf _U_, frame_data *fdata,
-             union wtap_pseudo_header *pseudo_header _U_,
+             union wtap_pseudo_header *pseudo_header,
              const guint8 *pd, void *argsp)
 {
   FILE *fh = argsp;
+  epan_dissect_t edt;
+
+  epan_dissect_init(&edt, TRUE, TRUE);
+  epan_dissect_run(&edt, pseudo_header, pd, fdata, NULL);
+  proto_tree_write_carrays(fdata->num, fh, &edt);
+  epan_dissect_cleanup(&edt);
 
-  proto_tree_write_carrays(pd, fdata->cap_len, fdata->num, fh);
   return !ferror(fh);
 }
 
@@ -2773,7 +2791,7 @@ cf_find_string_protocol_tree(capture_file *cf, proto_tree *tree,  match_data *md
   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; 
+  return mdata->frame_matched ? MR_MATCHED : MR_NOTMATCHED;
 }
 
 static match_result
@@ -2978,22 +2996,28 @@ match_ascii_and_unicode(capture_file *cf, frame_data *fdata, void *criterion)
 
   result = MR_NOTMATCHED;
   buf_len = fdata->pkt_len;
-  for (i = 0; i < buf_len; i++) {
+  i = 0;
+  while (i < buf_len) {
     c_char = cf->pd[i];
     if (cf->case_type)
       c_char = toupper(c_char);
-    if (c_char != 0) {
+    if (c_char != '\0') {
       if (c_char == ascii_text[c_match]) {
-        c_match++;
+        c_match += 1;
         if (c_match == textlen) {
           result = MR_MATCHED;
           cf->search_pos = i; /* Save the position of the last character
                                  for highlighting the field. */
           break;
         }
-      } else
+      }
+      else {
+        g_assert(i>=c_match);
+        i -= (guint32)c_match;
         c_match = 0;
+      }
     }
+    i += 1;
   }
   return result;
 }
@@ -3018,21 +3042,28 @@ match_ascii(capture_file *cf, frame_data *fdata, void *criterion)
 
   result = MR_NOTMATCHED;
   buf_len = fdata->pkt_len;
-  for (i = 0; i < buf_len; i++) {
+  i = 0;
+  while (i < buf_len) {
     c_char = cf->pd[i];
     if (cf->case_type)
       c_char = toupper(c_char);
     if (c_char == ascii_text[c_match]) {
-      c_match++;
+      c_match += 1;
       if (c_match == textlen) {
         result = MR_MATCHED;
         cf->search_pos = i; /* Save the position of the last character
                                for highlighting the field. */
         break;
       }
-    } else
+    }
+    else {
+      g_assert(i>=c_match);
+      i -= (guint32)c_match;
       c_match = 0;
+    }
+    i += 1;
   }
+
   return result;
 }
 
@@ -3056,21 +3087,27 @@ match_unicode(capture_file *cf, frame_data *fdata, void *criterion)
 
   result = MR_NOTMATCHED;
   buf_len = fdata->pkt_len;
-  for (i = 0; i < buf_len; i++) {
+  i = 0;
+  while (i < buf_len) {
     c_char = cf->pd[i];
     if (cf->case_type)
       c_char = toupper(c_char);
     if (c_char == ascii_text[c_match]) {
-      c_match++;
-      i++;
+      c_match += 1;
       if (c_match == textlen) {
         result = MR_MATCHED;
         cf->search_pos = i; /* Save the position of the last character
                                for highlighting the field. */
         break;
       }
-    } else
+      i += 1;
+    }
+    else {
+      g_assert(i>=(c_match*2));
+      i -= (guint32)c_match*2;
       c_match = 0;
+    }
+    i += 1;
   }
   return result;
 }
@@ -3094,17 +3131,23 @@ match_binary(capture_file *cf, frame_data *fdata, void *criterion)
 
   result = MR_NOTMATCHED;
   buf_len = fdata->pkt_len;
-  for (i = 0; i < buf_len; i++) {
+  i = 0;
+  while (i < buf_len) {
     if (cf->pd[i] == binary_data[c_match]) {
-      c_match++;
+      c_match += 1;
       if (c_match == datalen) {
         result = MR_MATCHED;
         cf->search_pos = i; /* Save the position of the last character
                                for highlighting the field. */
         break;
       }
-    } else
+    }
+    else {
+      g_assert(i>=c_match);
+      i -= (guint32)c_match;
       c_match = 0;
+    }
+    i += 1;
   }
   return result;
 }
@@ -3307,7 +3350,7 @@ find_packet(capture_file *cf,
         } else
           framenum++;
       }
-      fdata = cap_file_find_fdata(cf, framenum);
+      fdata = frame_data_sequence_find(cf->frames, framenum);
 
       count++;
 
@@ -3366,7 +3409,7 @@ cf_goto_frame(capture_file *cf, guint fnumber)
 {
   frame_data *fdata;
 
-  fdata = cap_file_find_fdata(cf, fnumber);
+  fdata = frame_data_sequence_find(cf->frames, fnumber);
 
   if (fdata == NULL) {
     /* we didn't find a packet with that packet number */
@@ -3394,7 +3437,7 @@ cf_goto_frame(capture_file *cf, guint fnumber)
 }
 
 gboolean
-cf_goto_top_frame()
+cf_goto_top_frame(void)
 {
   /* Find and select */
   new_packet_list_select_first_row();
@@ -3402,7 +3445,7 @@ cf_goto_top_frame()
 }
 
 gboolean
-cf_goto_bottom_frame()
+cf_goto_bottom_frame(void)
 {
   /* Find and select */
   new_packet_list_select_last_row();
@@ -3468,7 +3511,7 @@ cf_select_packet(capture_file *cf, int row)
        GtkCList; see the comment in "add_packet_to_packet_list()". */
 
        if (row == 0 && cf->first_displayed == cf->last_displayed)
-         fdata = cap_file_find_fdata(cf, cf->first_displayed);
+         fdata = frame_data_sequence_find(cf->frames, cf->first_displayed);
   }
 
   /* If fdata _still_ isn't set simply give up. */
@@ -3585,6 +3628,7 @@ cf_unignore_frame(capture_file *cf, frame_data *frame)
 typedef struct {
   wtap_dumper *pdh;
   const char  *fname;
+  int          file_type;
 } save_callback_args_t;
 
 /*
@@ -3612,7 +3656,30 @@ save_packet(capture_file *cf _U_, frame_data *fdata,
 
   /* and save the packet */
   if (!wtap_dump(args->pdh, &hdr, pseudo_header, pd, &err)) {
-    cf_write_failure_alert_box(args->fname, err);
+    if (err < 0) {
+      /* Wiretap error. */
+      switch (err) {
+
+      case WTAP_ERR_UNSUPPORTED_ENCAP:
+        /*
+         * This is a problem with the particular frame we're writing;
+         * note that, and give the frame number.
+         */
+        simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+                      "Frame %u has a network type that can't be saved in a \"%s\" file.",
+                      fdata->num, wtap_file_type_string(args->file_type));
+        break;
+
+      default:
+        simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+                      "An error occurred while writing to the file \"%s\": %s.",
+                      args->fname, wtap_strerror(err));
+        break;
+      }
+    } else {
+      /* OS error. */
+      write_failure_alert_box(args->fname, err);
+    }
     return FALSE;
   }
   return TRUE;
@@ -3709,7 +3776,7 @@ cf_save(capture_file *cf, const char *fname, packet_range_t *range, guint save_f
     if (do_copy) {
       /* Copy the file, if we haven't moved it. */
       if (!copy_file_binary_mode(from_filename, fname))
-    goto fail;
+        goto fail;
     }
   } else {
     /* Either we're filtering packets, or we're saving in a different
@@ -3737,6 +3804,7 @@ cf_save(capture_file *cf, const char *fname, packet_range_t *range, guint save_f
        "range" since we initialized it. */
     callback_args.pdh = pdh;
     callback_args.fname = fname;
+    callback_args.file_type = save_format;
     switch (process_specified_packets(cf, range, "Saving", "selected packets",
                                       TRUE, save_packet, &callback_args)) {
 
@@ -3881,7 +3949,7 @@ cf_open_failure_alert_box(const char *filename, int err, gchar *err_info,
       }
       break;
 
-    case WTAP_ERR_BAD_RECORD:
+    case WTAP_ERR_BAD_FILE:
       /* Seen only when opening a capture file for reading. */
       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
             "The file \"%s\" appears to be damaged or corrupt.\n"
@@ -3967,20 +4035,6 @@ file_rename_error_message(int err)
   return errmsg;
 }
 
-static void
-cf_write_failure_alert_box(const char *filename, int err)
-{
-  if (err < 0) {
-    /* Wiretap error. */
-    simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
-          "An error occurred while writing to the file \"%s\": %s.",
-          filename, wtap_strerror(err));
-  } else {
-    /* OS error. */
-    write_failure_alert_box(filename, err);
-  }
-}
-
 /* Check for write errors - if the file is being written to an NFS server,
    a write error may not show up until the file is closed, as NFS clients
    might not send writes to the server until the "write()" call finishes,
@@ -4078,6 +4132,6 @@ cf_reload(capture_file *cf) {
  * indent-tabs-mode: nil
  * End:
  *
- * ex: set shiftwidth=2 tabstop=8 expandtab
+ * ex: set shiftwidth=2 tabstop=8 expandtab:
  * :indentSize=2:tabSize=8:noTabs=true:
  */