Clarify what the special cases in wtap_wtap_encap_to_pcap_encap() are
[metze/wireshark/wip.git] / file.c
diff --git a/file.c b/file.c
index dfb1d1b0ce441b51a8b302e387ffc07cc7dfa12b..fa980114556f5a1d07ff7ac2a31027efbdb37353 100644 (file)
--- a/file.c
+++ b/file.c
@@ -46,6 +46,7 @@
 
 #include <wiretap/merge.h>
 
+#include <epan/epan-int.h>
 #include <epan/epan.h>
 #include <epan/column.h>
 #include <epan/packet.h>
@@ -108,7 +109,7 @@ gboolean auto_scroll_live;
 #endif
 
 static guint32 cum_bytes;
-static nstime_t first_ts;
+static const frame_data *ref;
 static frame_data *prev_dis;
 static frame_data *prev_cap;
 
@@ -149,6 +150,8 @@ static gboolean find_packet(capture_file *cf,
     match_result (*match_function)(capture_file *, frame_data *, void *),
     void *criterion, search_direction dir);
 
+static const char *cf_get_user_packet_comment(capture_file *cf, const frame_data *fd);
+
 static void cf_open_failure_alert_box(const char *filename, int err,
                       gchar *err_info, gboolean for_writing,
                       int file_type);
@@ -302,6 +305,47 @@ static void compute_elapsed(GTimeVal *start_time)
   computed_elapsed = (gulong) (delta_time / 1000); /* ms */
 }
 
+static const nstime_t *
+ws_get_frame_ts(void *data, guint32 frame_num)
+{
+  capture_file *cf = (capture_file *) data;
+
+  if (prev_dis && prev_dis->num == frame_num)
+    return &prev_dis->abs_ts;
+
+  if (prev_cap && prev_cap->num == frame_num)
+    return &prev_cap->abs_ts;
+
+  if (cf->frames) {
+    frame_data *fd = frame_data_sequence_find(cf->frames, frame_num);
+
+    return (fd) ? &fd->abs_ts : NULL;
+  }
+
+  return NULL;
+}
+
+static const char *
+ws_get_user_comment(void *data, const frame_data *fd)
+{
+  capture_file *cf = (capture_file *) data;
+
+  return cf_get_user_packet_comment(cf, fd);
+}
+
+static epan_t *
+ws_epan_new(capture_file *cf)
+{
+  epan_t *epan = epan_new();
+
+  epan->data = cf;
+  epan->get_frame_ts = ws_get_frame_ts;
+  epan->get_interface_name = cap_file_get_interface_name;
+  epan->get_user_comment = ws_get_user_comment;
+
+  return epan;
+}
+
 cf_status_t
 cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
 {
@@ -320,10 +364,10 @@ cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
      the packets, so we know how much we'll ultimately need. */
   buffer_init(&cf->buf, 1500);
 
-  /* Cleanup all data structures used for dissection. */
-  cleanup_dissection();
-  /* Initialize all data structures used for dissection. */
-  init_dissection();
+  /* Create new epan session for dissection.
+   * (The old one was freed in cf_close().)
+   */
+  cf->epan = ws_epan_new(cf);
 
   /* We're about to start reading the file. */
   cf->state = FILE_READ_IN_PROGRESS;
@@ -366,7 +410,7 @@ cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
   cf->frames = new_frame_data_sequence();
 
   nstime_set_zero(&cf->elapsed_time);
-  nstime_set_unset(&first_ts);
+  ref = NULL;
   prev_dis = NULL;
   prev_cap = NULL;
   cum_bytes = 0;
@@ -454,6 +498,10 @@ cf_reset_state(capture_file *cf)
     cf->edited_frames = NULL;
   }
 #endif
+  if (cf->frames_user_comments) {
+    g_tree_destroy(cf->frames_user_comments);
+    cf->frames_user_comments = NULL;
+  }
   cf_unselect_packet(cf);   /* nothing to select */
   cf->first_displayed = 0;
   cf->last_displayed = 0;
@@ -492,7 +540,8 @@ cf_close(capture_file *cf)
   /* close things, if not already closed before */
     color_filters_cleanup();
     cf_reset_state(cf);
-    cleanup_dissection();
+    epan_free(cf->epan);
+    cf->epan = NULL;
 
     cf_callback_invoke(cf_cb_file_closed, cf);
   }
@@ -1123,11 +1172,11 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
   gint            row               = -1;
 
   frame_data_set_before_dissect(fdata, &cf->elapsed_time,
-                                &first_ts, prev_dis, prev_cap);
+                                &ref, prev_dis);
   prev_cap = fdata;
 
   /* Dissect the frame. */
-  epan_dissect_init(&edt, create_proto_tree, FALSE);
+  epan_dissect_init(&edt, cf->epan, create_proto_tree, FALSE);
 
   if (dfcode != NULL) {
       epan_dissect_prime_dfilter(&edt, dfcode);
@@ -1217,7 +1266,7 @@ read_packet(capture_file *cf, dfilter_t *dfcode,
   passed = TRUE;
   if (cf->rfcode) {
     epan_dissect_t edt;
-    epan_dissect_init(&edt, TRUE, FALSE);
+    epan_dissect_init(&edt, cf->epan, TRUE, FALSE);
     epan_dissect_prime_dfilter(&edt, cf->rfcode);
     epan_dissect_run(&edt, phdr, frame_tvbuff_new(&fdlocal, buf), &fdlocal, NULL);
     passed = dfilter_apply_edt(cf->rfcode, &edt);
@@ -1229,7 +1278,7 @@ read_packet(capture_file *cf, dfilter_t *dfcode,
     fdata = frame_data_sequence_add(cf->frames, &fdlocal);
 
     cf->count++;
-    if (fdlocal.opt_comment != NULL)
+    if (phdr->opt_comment != NULL)
       cf->packet_comment_count++;
     cf->f_datalen = offset + fdlocal.cap_len;
 
@@ -1686,7 +1735,7 @@ cf_redissect_packets(capture_file *cf)
 }
 
 gboolean
-cf_read_frame_r(capture_file *cf, frame_data *fdata,
+cf_read_frame_r(capture_file *cf, const frame_data *fdata,
                 struct wtap_pkthdr *phdr, Buffer *buf)
 {
   int    err;
@@ -1819,10 +1868,9 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item, gb
        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();
+    /* 'reset' dissection session */
+    epan_free(cf->epan);
+    cf->epan = ws_epan_new(cf);
 
     /* We need to redissect the packets so we have to discard our old
      * packet list store. */
@@ -1840,7 +1888,7 @@ rescan_packets(capture_file *cf, const char *action, const char *action_item, gb
   /* Iterate through the list of frames.  Call a routine for each frame
      to check whether it should be displayed and, if so, add it to
      the display list. */
-  nstime_set_unset(&first_ts);
+  ref = NULL;
   prev_dis = NULL;
   prev_cap = NULL;
   cum_bytes = 0;
@@ -2077,8 +2125,9 @@ ref_time_packets(capture_file *cf)
 {
   guint32     framenum;
   frame_data *fdata;
+  nstime_t rel_ts;
 
-  nstime_set_unset(&first_ts);
+  ref = NULL;
   prev_dis = NULL;
   cum_bytes = 0;
 
@@ -2095,14 +2144,12 @@ ref_time_packets(capture_file *cf)
     /* If we don't have the time stamp of the first packet in the
      capture, it's because this is the first packet.  Save the time
      stamp of this packet as the time stamp of the first packet. */
-    if (nstime_is_unset(&first_ts)) {
-        first_ts  = fdata->abs_ts;
-    }
+    if (ref == NULL)
+        ref = fdata;
       /* 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 (fdata->flags.ref_time)
+        ref = fdata;
 
     /* If we don't have the time stamp of the previous displayed packet,
      it's because this is the first displayed packet.  Save the time
@@ -2113,20 +2160,21 @@ ref_time_packets(capture_file *cf)
     }
 
     /* Get the time elapsed between the first packet and this packet. */
-    nstime_delta(&fdata->rel_ts, &fdata->abs_ts, &first_ts);
+    fdata->frame_ref_num = (fdata != ref) ? ref->num : 0;
+    nstime_delta(&rel_ts, &fdata->abs_ts, &ref->abs_ts);
 
     /* If it's greater than the current elapsed time, set the elapsed time
      to it (we check for "greater than" so as not to be confused by
      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;
+    if ((gint32)cf->elapsed_time.secs < rel_ts.secs
+        || ((gint32)cf->elapsed_time.secs == rel_ts.secs && (gint32)cf->elapsed_time.nsecs < rel_ts.nsecs)) {
+        cf->elapsed_time = rel_ts;
     }
 
     /* If this frame is displayed, get the time elapsed between the
      previous displayed packet and this packet. */
     if ( fdata->flags.passed_dfilter ) {
-        fdata->prev_dis = prev_dis;
+        fdata->prev_dis_num = prev_dis->num;
         prev_dis = fdata;
     }
 
@@ -2293,7 +2341,7 @@ retap_packet(capture_file *cf _U_, frame_data *fdata,
   retap_callback_args_t *args = (retap_callback_args_t *)argsp;
   epan_dissect_t         edt;
 
-  epan_dissect_init(&edt, args->construct_protocol_tree, FALSE);
+  epan_dissect_init(&edt, cf->epan, args->construct_protocol_tree, FALSE);
   epan_dissect_run_with_taps(&edt, phdr, frame_tvbuff_new(fdata, pd), fdata, args->cinfo);
   epan_dissect_cleanup(&edt);
 
@@ -2384,7 +2432,7 @@ print_packet(capture_file *cf, frame_data *fdata,
      XXX - do we need it if we're just printing the hex data? */
   proto_tree_needed =
       args->print_args->print_dissections != print_dissections_none || args->print_args->print_hex || have_custom_cols(&cf->cinfo);
-  epan_dissect_init(&edt, proto_tree_needed, proto_tree_needed);
+  epan_dissect_init(&edt, cf->epan, proto_tree_needed, proto_tree_needed);
 
   /* Fill in the column information if we're printing the summary
      information. */
@@ -2690,7 +2738,7 @@ write_pdml_packet(capture_file *cf _U_, frame_data *fdata,
   epan_dissect_t  edt;
 
   /* Create the protocol tree, but don't fill in the column information. */
-  epan_dissect_init(&edt, TRUE, TRUE);
+  epan_dissect_init(&edt, cf->epan, TRUE, TRUE);
   epan_dissect_run(&edt, phdr, frame_tvbuff_new(fdata, pd), fdata, NULL);
 
   /* Write out the information in that tree. */
@@ -2763,7 +2811,7 @@ write_psml_packet(capture_file *cf, frame_data *fdata,
   /* Fill in the column information, only create the protocol tree
      if having custom columns. */
   proto_tree_needed = have_custom_cols(&cf->cinfo);
-  epan_dissect_init(&edt, proto_tree_needed, proto_tree_needed);
+  epan_dissect_init(&edt, cf->epan, proto_tree_needed, proto_tree_needed);
   col_custom_prime_edt(&edt, &cf->cinfo);
   epan_dissect_run(&edt, phdr, frame_tvbuff_new(fdata, pd), fdata, &cf->cinfo);
   epan_dissect_fill_in_columns(&edt, FALSE, TRUE);
@@ -2838,7 +2886,7 @@ write_csv_packet(capture_file *cf, frame_data *fdata,
   /* Fill in the column information, only create the protocol tree
      if having custom columns. */
   proto_tree_needed = have_custom_cols(&cf->cinfo);
-  epan_dissect_init(&edt, proto_tree_needed, proto_tree_needed);
+  epan_dissect_init(&edt, cf->epan, proto_tree_needed, proto_tree_needed);
   col_custom_prime_edt(&edt, &cf->cinfo);
   epan_dissect_run(&edt, phdr, frame_tvbuff_new(fdata, pd), fdata, &cf->cinfo);
   epan_dissect_fill_in_columns(&edt, FALSE, TRUE);
@@ -2902,14 +2950,14 @@ cf_write_csv_packets(capture_file *cf, print_args_t *print_args)
 }
 
 static gboolean
-write_carrays_packet(capture_file *cf _U_, frame_data *fdata,
+write_carrays_packet(capture_file *cf, frame_data *fdata,
              struct wtap_pkthdr *phdr,
              const guint8 *pd, void *argsp)
 {
   FILE           *fh = (FILE *)argsp;
   epan_dissect_t  edt;
 
-  epan_dissect_init(&edt, TRUE, TRUE);
+  epan_dissect_init(&edt, cf->epan, TRUE, TRUE);
   epan_dissect_run(&edt, phdr, frame_tvbuff_new(fdata, pd), fdata, NULL);
   proto_tree_write_carrays(fdata->num, fh, &edt);
   epan_dissect_cleanup(&edt);
@@ -3001,7 +3049,7 @@ match_protocol_tree(capture_file *cf, frame_data *fdata, void *criterion)
   }
 
   /* Construct the protocol tree, including the displayed text */
-  epan_dissect_init(&edt, TRUE, TRUE);
+  epan_dissect_init(&edt, cf->epan, TRUE, TRUE);
   /* We don't need the column information */
   epan_dissect_run(&edt, &cf->phdr, frame_tvbuff_new_buffer(fdata, &cf->buf), fdata, NULL);
 
@@ -3105,7 +3153,7 @@ match_summary_line(capture_file *cf, frame_data *fdata, void *criterion)
   }
 
   /* Don't bother constructing the protocol tree */
-  epan_dissect_init(&edt, FALSE, FALSE);
+  epan_dissect_init(&edt, cf->epan, FALSE, FALSE);
   /* Get the column information */
   epan_dissect_run(&edt, &cf->phdr, frame_tvbuff_new_buffer(fdata, &cf->buf), fdata,
                    &cf->cinfo);
@@ -3413,7 +3461,7 @@ match_dfilter(capture_file *cf, frame_data *fdata, void *criterion)
     return MR_ERROR;
   }
 
-  epan_dissect_init(&edt, TRUE, FALSE);
+  epan_dissect_init(&edt, cf->epan, TRUE, FALSE);
   epan_dissect_prime_dfilter(&edt, sfcode);
   epan_dissect_run(&edt, &cf->phdr, frame_tvbuff_new_buffer(fdata, &cf->buf), fdata, NULL);
   result = dfilter_apply_edt(sfcode, &edt) ? MR_MATCHED : MR_NOTMATCHED;
@@ -3745,7 +3793,7 @@ cf_select_packet(capture_file *cf, int row)
   old_edt = cf->edt;
   /* Create the logical protocol tree. */
   /* We don't need the columns here. */
-  cf->edt = epan_dissect_new(TRUE, TRUE);
+  cf->edt = epan_dissect_new(cf->epan, TRUE, TRUE);
 
   tap_build_interesting(cf->edt);
   epan_dissect_run(cf->edt, &cf->phdr, frame_tvbuff_new_buffer(cf->current_frame, &cf->buf),
@@ -3889,25 +3937,82 @@ cf_update_capture_comment(capture_file *cf, gchar *comment)
   cf->unsaved_changes = TRUE;
 }
 
-void
-cf_update_packet_comment(capture_file *cf, frame_data *fdata, gchar *comment)
+static const char *
+cf_get_user_packet_comment(capture_file *cf, const frame_data *fd)
 {
-  if (fdata->opt_comment != NULL) {
-    /* OK, remove the old comment. */
-    g_free(fdata->opt_comment);
-    fdata->opt_comment = NULL;
-    cf->packet_comment_count--;
+  if (cf->frames_user_comments)
+     return (const char *)g_tree_lookup(cf->frames_user_comments, fd);
+
+  /* g_warning? */
+  return NULL;
+}
+
+char *
+cf_get_comment(capture_file *cf, const frame_data *fd)
+{
+  /* fetch user comment */
+  if (fd->flags.has_user_comment)
+    return g_strdup(cf_get_user_packet_comment(cf, fd));
+
+  /* fetch phdr comment */
+  if (fd->flags.has_phdr_comment) {
+    struct wtap_pkthdr phdr; /* Packet header */
+    Buffer buf; /* Packet data */
+
+    phdr.opt_comment = NULL;
+
+    buffer_init(&buf, 1500);
+    if (!cf_read_frame_r(cf, fd, &phdr, &buf))
+      { /* XXX, what we can do here? */ }
+
+    buffer_free(&buf);
+    return phdr.opt_comment;
   }
-  if (comment != NULL) {
-    /* Add the new comment. */
-    fdata->opt_comment = comment;
-    cf->packet_comment_count++;
+  return NULL;
+}
+
+static int
+frame_cmp(gconstpointer a, gconstpointer b, gpointer user_data _U_)
+{
+  const frame_data *fdata1 = (const frame_data *) a;
+  const frame_data *fdata2 = (const frame_data *) b;
+
+  return (fdata1->num < fdata2->num) ? -1 :
+    (fdata1->num > fdata2->num) ? 1 :
+    0;
+}
+
+gboolean
+cf_set_user_packet_comment(capture_file *cf, frame_data *fd, const gchar *new_comment)
+{
+  char *pkt_comment = cf_get_comment(cf, fd);
+
+  /* Check if the comment has changed */
+  if (!g_strcmp0(pkt_comment, new_comment)) {
+    g_free(pkt_comment);
+    return FALSE;
   }
+  g_free(pkt_comment);
+
+  if (pkt_comment)
+    cf->packet_comment_count--;
+
+  if (new_comment)
+    cf->packet_comment_count++;
+
+  fd->flags.has_user_comment = TRUE;
+
+  if (!cf->frames_user_comments)
+    cf->frames_user_comments = g_tree_new_full(frame_cmp, NULL, NULL, g_free);
+
+  /* insert new packet comment */
+  g_tree_replace(cf->frames_user_comments, fd, g_strdup(new_comment));
 
   expert_update_comment_count(cf->packet_comment_count);
 
   /* OK, we have unsaved changes. */
   cf->unsaved_changes = TRUE;
+  return TRUE;
 }
 
 /*
@@ -3947,6 +4052,12 @@ save_packet(capture_file *cf _U_, frame_data *fdata,
   struct wtap_pkthdr    hdr;
   int           err;
   gchar        *display_basename;
+  const char   *pkt_comment;
+
+  if (fdata->flags.has_user_comment)
+    pkt_comment = cf_get_user_packet_comment(cf, fdata);
+  else
+    pkt_comment = phdr->opt_comment;
 
   /* init the wtap header for saving */
   /* TODO: reuse phdr */
@@ -3964,9 +4075,9 @@ save_packet(capture_file *cf _U_, frame_data *fdata,
   hdr.presence_flags = 0;
   if (fdata->flags.has_ts)
     hdr.presence_flags |= WTAP_HAS_TS;
-  if (fdata->flags.has_if_id)
+  if (phdr->presence_flags & WTAP_HAS_INTERFACE_ID)
     hdr.presence_flags |= WTAP_HAS_INTERFACE_ID;
-  if (fdata->flags.has_pack_flags)
+  if (phdr->presence_flags & WTAP_HAS_PACK_FLAGS)
     hdr.presence_flags |= WTAP_HAS_PACK_FLAGS;
   hdr.ts.secs      = fdata->abs_ts.secs;
   hdr.ts.nsecs     = fdata->abs_ts.nsecs;
@@ -3974,10 +4085,11 @@ save_packet(capture_file *cf _U_, frame_data *fdata,
   hdr.len          = fdata->pkt_len;
   hdr.pkt_encap    = fdata->lnk_t;
   /* pcapng */
-  hdr.interface_id = fdata->interface_id;   /* identifier of the interface. */
+  hdr.interface_id = phdr->interface_id;   /* identifier of the interface. */
   /* options */
-  hdr.pack_flags   = fdata->pack_flags;
-  hdr.opt_comment  = fdata->opt_comment; /* NULL if not available */
+  hdr.pack_flags   = phdr->pack_flags;
+  hdr.opt_comment  = g_strdup(pkt_comment);
+
   /* pseudo */
   hdr.pseudo_header = phdr->pseudo_header;
 #if 0
@@ -4014,6 +4126,8 @@ save_packet(capture_file *cf _U_, frame_data *fdata,
     }
     return FALSE;
   }
+
+  g_free(hdr.opt_comment);
   return TRUE;
 }
 
@@ -4633,15 +4747,20 @@ cf_save_packets(capture_file *cf, const char *fname, guint save_format,
       /* Remove SHB comment, if any. */
       wtap_write_shb_comment(cf->wth, NULL);
 
-      /* Remove packet comments. */
+      /* remove all user comments */
       for (framenum = 1; framenum <= cf->count; framenum++) {
         fdata = frame_data_sequence_find(cf->frames, framenum);
-        if (fdata->opt_comment) {
-          g_free(fdata->opt_comment);
-          fdata->opt_comment = NULL;
-          cf->packet_comment_count--;
-        }
+
+        fdata->flags.has_phdr_comment = FALSE;
+        fdata->flags.has_user_comment = FALSE;
       }
+
+      if (cf->frames_user_comments) {
+        g_tree_destroy(cf->frames_user_comments);
+        cf->frames_user_comments = NULL;
+      }
+
+      cf->packet_comment_count = 0;
     }
   }
   return CF_WRITE_OK;