Move the new files to the same places as in automake.
[obnox/wireshark/wip.git] / wiretap / catapult_dct2000.c
index f39bbe03c3ec2b489fc7b1a68e7b68b7f10294c7..041ee83275cfc6349c4ecdefb9be62d92d86f468 100644 (file)
 
 #define MAX_FIRST_LINE_LENGTH      200
 #define MAX_TIMESTAMP_LINE_LENGTH  100
-#define MAX_LINE_LENGTH            32000
+#define MAX_LINE_LENGTH            65536
+#define MAX_TIMESTAMP_LEN          32
 #define MAX_SECONDS_CHARS          16
 #define MAX_SUBSECOND_DECIMALS     4
 #define MAX_CONTEXT_NAME           64
 #define MAX_PROTOCOL_NAME          64
 #define MAX_PORT_DIGITS            2
 #define MAX_VARIANT_DIGITS         32
-#define MAX_OUTHDR_NAME            64
+#define MAX_OUTHDR_NAME            256
 #define AAL_HEADER_CHARS           12
 
 /* TODO:
@@ -60,16 +61,33 @@ typedef enum packet_direction_t
 } packet_direction_t;
 
 
+/***********************************************************************/
+/* For each line, store (in case we need to dump):                     */
+/* - String before time field                                          */
+/* - String beween time field and data (if NULL assume " l ")          */
 typedef struct
 {
     gchar *before_time;
-    gchar *after_time; /* If NULL assume " l " */
+    gchar *after_time;
 } line_prefix_info_t;
 
+
 /*******************************************************************/
-/* Information stored external to a file (wtap) needed for dumping */
+/* Information stored external to a file (wtap) needed for reading and dumping */
 typedef struct dct2000_file_externals
 {
+    /* Remember the time at the start of capture */
+    time_t  start_secs;
+    guint32 start_usecs;
+
+    /*
+     * The following information is needed only for dumping.
+     *
+     * XXX - Wiretap is not *supposed* to require that a packet being
+     * dumped come from a file of the same type that you currently have
+     * open; this should be fixed.
+     */
+
     /* Buffer to hold first line, including magic and format number */
     gchar firstline[MAX_FIRST_LINE_LENGTH];
     gint  firstline_length;
@@ -79,160 +97,141 @@ typedef struct dct2000_file_externals
     gint  secondline_length;
 
     /* Hash table to store text prefix data part of displayed packets.
-       Records (file offset -> pre-data-prefix-string)
-       N.B. This is only needed for dumping
+       Records (file offset -> line_prefix_info_t)
     */
     GHashTable *packet_prefix_table;
 } dct2000_file_externals_t;
 
-/* This global table maps wtap -> file_external structs */
-static GHashTable *file_externals_table = NULL;
-
-
-/***********************************************************/
-/* Transient data used for parsing                         */
-
-/* Buffer to hold a single text line read from the file */
-static gchar linebuff[MAX_LINE_LENGTH];
-
-/* Buffer for separate AAL header */
-static gchar aal_header_chars[AAL_HEADER_CHARS];
-
 /* 'Magic number' at start of Catapult DCT2000 .out files. */
 static const gchar catapult_dct2000_magic[] = "Session Transcript";
 
-/* Context name + port that the packet was captured at */
-static gchar context_name[MAX_CONTEXT_NAME];
-static guint8 context_port;
-
-/* The DCT2000 protocol name of the packet, plus variant number */
-static gchar protocol_name[MAX_PROTOCOL_NAME+1];
-static gchar variant_name[MAX_VARIANT_DIGITS+1];
-static gchar outhdr_name[MAX_OUTHDR_NAME+1];
-
-
 /************************************************************/
-/* Functions called from wiretap                            */
+/* Functions called from wiretap core                       */
 static gboolean catapult_dct2000_read(wtap *wth, int *err, gchar **err_info,
                                       gint64 *data_offset);
 static gboolean catapult_dct2000_seek_read(wtap *wth, gint64 seek_off,
                                            union wtap_pseudo_header *pseudo_header,
-                                           guchar *pd, int length,
+                                           guint8 *pd, int length,
                                            int *err, gchar **err_info);
 static void catapult_dct2000_close(wtap *wth);
 
 static gboolean catapult_dct2000_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
                                       const union wtap_pseudo_header *pseudo_header,
-                                      const guchar *pd, int *err);
-static gboolean catapult_dct2000_dump_close(wtap_dumper *wdh, int *err);
+                                      const guint8 *pd, int *err);
 
 
 /************************************************************/
 /* Private helper functions                                 */
-static gboolean read_new_line(FILE_T fh, gint64 *offset, gint *length);
-static gboolean parse_line(gint line_length, gint *seconds, gint *useconds,
+static gboolean read_new_line(FILE_T fh, gint64 *offset, gint *length,
+                              gchar *buf, size_t bufsize);
+static gboolean parse_line(char *linebuff, gint line_length,
+                           gint *seconds, gint *useconds,
                            long *before_time_offset, long *after_time_offset,
                            long *data_offset,
                            gint *data_chars,
                            packet_direction_t *direction,
-                           int *encap);
-static int write_stub_header(guchar *frame_buffer, char *timestamp_string,
-                      packet_direction_t direction, int encap);
-static guchar hex_from_char(gchar c);
-static gchar char_from_hex(guchar hex);
+                           int *encap, int *is_comment,
+                           gchar *aal_header_chars,
+                           gchar *context_name, guint8 *context_portp,
+                           gchar *protocol_name, gchar *variant_name,
+                           gchar *outhdr_name);
+static int write_stub_header(guint8 *frame_buffer, char *timestamp_string,
+                             packet_direction_t direction, int encap,
+                             gchar *context_name, guint8 context_port,
+                             gchar *protocol_name, gchar *variant_name,
+                             gchar *outhdr_name);
+static guint8 hex_from_char(gchar c);
+static guint8 hex_byte_from_chars(gchar *c);
+static gchar char_from_hex(guint8 hex);
 
 static void set_pseudo_header_info(wtap *wth,
                                    int pkt_encap,
                                    gint64 file_offset,
                                    union wtap_pseudo_header *pseudo_header,
-                                   packet_direction_t direction);
+                                   packet_direction_t direction,
+                                   gchar *aal_header_chars);
 static void set_aal_info(union wtap_pseudo_header *pseudo_header,
-                         packet_direction_t direction);
+                         packet_direction_t direction,
+                         gchar *aal_header_chars);
 static void set_isdn_info(union wtap_pseudo_header *pseudo_header,
                           packet_direction_t direction);
 static void set_ppp_info(union wtap_pseudo_header *pseudo_header,
                          packet_direction_t direction);
 
-static gint wth_equal(gconstpointer v, gconstpointer v2);
-static guint wth_hash_func(gconstpointer v);
 static gint packet_offset_equal(gconstpointer v, gconstpointer v2);
 static guint packet_offset_hash_func(gconstpointer v);
 
-static gboolean get_file_time_stamp(time_t *secs, guint32 *usecs);
+static gboolean get_file_time_stamp(gchar *linebuff, time_t *secs, guint32 *usecs);
 static gboolean free_line_prefix_info(gpointer key, gpointer value, gpointer user_data);
 
 
 
 /********************************************/
-/* Open file                                */
+/* Open file (for reading)                 */
 /********************************************/
-int catapult_dct2000_open(wtap *wth, int *err, gchar **err_info _U_)
+int
+catapult_dct2000_open(wtap *wth, int *err, gchar **err_info _U_)
 {
     gint64  offset = 0;
     time_t  timestamp;
     guint32 usecs;
     gint firstline_length = 0;
     dct2000_file_externals_t *file_externals;
+    static gchar linebuff[MAX_LINE_LENGTH];
 
     /* Clear errno before reading from the file */
     errno = 0;
 
 
-    /*********************************************************************/
-    /* Need entry in file_externals table                                */
-
-    /* Create file externals table if it doesn't yet exist */
-    if (file_externals_table == NULL)
-    {
-        file_externals_table = g_hash_table_new(wth_hash_func, wth_equal);
-    }
-
-
     /********************************************************************/
     /* First line needs to contain at least as many characters as magic */
 
-    read_new_line(wth->fh, &offset, &firstline_length);
+    read_new_line(wth->fh, &offset, &firstline_length, linebuff,
+                  sizeof linebuff);
     if (((size_t)firstline_length < strlen(catapult_dct2000_magic)) ||
-        firstline_length >= MAX_FIRST_LINE_LENGTH)
-    {
+        firstline_length >= MAX_FIRST_LINE_LENGTH) {
+
         return 0;
     }
 
     /* This file is not for us if it doesn't match our signature */
-    if (memcmp(catapult_dct2000_magic, linebuff, strlen(catapult_dct2000_magic)) != 0)
-    {
+    if (memcmp(catapult_dct2000_magic, linebuff, strlen(catapult_dct2000_magic)) != 0) {
         return 0;
     }
 
 
-    /* Allocate a new file_externals structure */
+    /*********************************************************************/
+    /* Need entry in file_externals table                                */
+
+    /* Allocate a new file_externals structure for this file */
     file_externals = g_malloc(sizeof(dct2000_file_externals_t));
     memset((void*)file_externals, '\0', sizeof(dct2000_file_externals_t));
 
     /* Copy this first line into buffer so could write out later */
-    strncpy(file_externals->firstline, linebuff, firstline_length);
+    g_strlcpy(file_externals->firstline, linebuff, firstline_length+1);
     file_externals->firstline_length = firstline_length;
 
 
     /***********************************************************/
     /* Second line contains file timestamp                     */
-    /* Store this offset in in wth->capture->catapult_dct2000  */
+    /* Store this offset in in file_externals                  */
 
-    read_new_line(wth->fh, &offset, &(file_externals->secondline_length));
+    read_new_line(wth->fh, &offset, &(file_externals->secondline_length),
+                  linebuff, sizeof linebuff);
     if ((file_externals->secondline_length >= MAX_TIMESTAMP_LINE_LENGTH) ||
-        (!get_file_time_stamp(&timestamp, &usecs)))
-    {
+        (!get_file_time_stamp(linebuff, &timestamp, &usecs))) {
+
         /* Give up if file time line wasn't valid */
         g_free(file_externals);
         return 0;
     }
 
-    wth->capture.catapult_dct2000 = g_malloc(sizeof(catapult_dct2000_t));
-    wth->capture.catapult_dct2000->start_secs = timestamp;
-    wth->capture.catapult_dct2000->start_usecs = usecs;
+    /* Fill in timestamp */
+    file_externals->start_secs = timestamp;
+    file_externals->start_usecs = usecs;
 
     /* Copy this second line into buffer so could write out later */
-    strncpy(file_externals->secondline, linebuff, file_externals->secondline_length);
+    g_strlcpy(file_externals->secondline, linebuff, file_externals->secondline_length+1);
 
 
     /************************************************************/
@@ -258,9 +257,8 @@ int catapult_dct2000_open(wtap *wth, int *err, gchar **err_info _U_)
     file_externals->packet_prefix_table =
         g_hash_table_new(packet_offset_hash_func, packet_offset_equal);
 
-    /* Add file_externals for this wtap into the global table */
-    g_hash_table_insert(file_externals_table,
-                        (void*)wth, (void*)file_externals);
+    /* Set this wtap to point to the file_externals */
+    wth->priv = (void*)file_externals;
 
     *err = errno;
     return 1;
@@ -268,11 +266,12 @@ int catapult_dct2000_open(wtap *wth, int *err, gchar **err_info _U_)
 
 
 /**************************************************/
-/* Read function.                                 */
+/* Read packet function.                          */
 /* Look for and read the next usable packet       */
 /* - return TRUE and details if found             */
 /**************************************************/
-gboolean catapult_dct2000_read(wtap *wth, int *err, gchar **err_info _U_,
+static gboolean
+catapult_dct2000_read(wtap *wth, int *err, gchar **err_info _U_,
                                gint64 *data_offset)
 {
     gint64 offset = wth->data_offset;
@@ -280,25 +279,30 @@ gboolean catapult_dct2000_read(wtap *wth, int *err, gchar **err_info _U_,
     packet_direction_t direction;
     int encap;
 
-    /* Find wtap external structure for this wtap */
+    /* Get wtap external structure for this wtap */
     dct2000_file_externals_t *file_externals =
-        (dct2000_file_externals_t*)g_hash_table_lookup(file_externals_table, wth);
+        (dct2000_file_externals_t*)wth->priv;
 
     /* There *has* to be an entry for this wth */
-    if (!file_externals)
-    {
+    if (!file_externals) {
         return FALSE;
     }
 
-    /* Search for a line containing a usable message */
-    while (1)
-    {
+    /* Search for a line containing a usable packet */
+    while (1) {
         int line_length, seconds, useconds, data_chars;
+        int is_comment = FALSE;
         gint64 this_offset = offset;
+        static gchar linebuff[MAX_LINE_LENGTH+1];
+        gchar aal_header_chars[AAL_HEADER_CHARS];
+        gchar context_name[MAX_CONTEXT_NAME];
+        guint8 context_port;
+        gchar protocol_name[MAX_PROTOCOL_NAME+1];
+        gchar variant_name[MAX_VARIANT_DIGITS+1];
+        gchar outhdr_name[MAX_OUTHDR_NAME+1];
 
         /* Are looking for first packet after 2nd line */
-        if (wth->data_offset == 0)
-        {
+        if (wth->data_offset == 0) {
             this_offset += (file_externals->firstline_length+1+
                             file_externals->secondline_length+1);
         }
@@ -307,26 +311,30 @@ gboolean catapult_dct2000_read(wtap *wth, int *err, gchar **err_info _U_,
         errno = 0;
 
         /* Read a new line from file into linebuff */
-        if (read_new_line(wth->fh, &offset, &line_length) == FALSE)
-        {
-            /* Get out when no more lines to be read */
+        if (read_new_line(wth->fh, &offset, &line_length, linebuff,
+                          sizeof linebuff) == FALSE) {
+            /* Get out if no more lines can be read */
             break;
         }
 
-        /* Try to parse the line as a message */
-        if (parse_line(line_length, &seconds, &useconds,
+        /* Try to parse the line as a frame record */
+        if (parse_line(linebuff, line_length, &seconds, &useconds,
                        &before_time_offset, &after_time_offset,
                        &dollar_offset,
-                       &data_chars, &direction, &encap))
-        {
-            guchar *frame_buffer;
+                       &data_chars, &direction, &encap, &is_comment,
+                       aal_header_chars,
+                       context_name, &context_port,
+                       protocol_name, variant_name, outhdr_name)) {
+            guint8 *frame_buffer;
             int n;
             int stub_offset = 0;
             line_prefix_info_t *line_prefix_info;
-            char timestamp_string[32];
+            char timestamp_string[MAX_TIMESTAMP_LEN+1];
             gint64 *pkey = NULL;
 
-            sprintf(timestamp_string, "%d.%04d", seconds, useconds/100);
+            g_snprintf(timestamp_string, MAX_TIMESTAMP_LEN, "%d.%04d", seconds, useconds/100);
+
+            wth->phdr.presence_flags = WTAP_HAS_TS;
 
             /* All packets go to Catapult DCT2000 stub dissector */
             wth->phdr.pkt_encap = WTAP_ENCAP_CATAPULT_DCT2000;
@@ -340,13 +348,12 @@ gboolean catapult_dct2000_read(wtap *wth, int *err, gchar **err_info _U_,
             wth->data_offset = this_offset + line_length + 1;
 
             /* Fill in timestamp (capture base + packet offset) */
-            wth->phdr.ts.secs = wth->capture.catapult_dct2000->start_secs + seconds;
-            if ((wth->capture.catapult_dct2000->start_usecs + useconds) >= 1000000)
-            {
+            wth->phdr.ts.secs = file_externals->start_secs + seconds;
+            if ((file_externals->start_usecs + useconds) >= 1000000) {
                 wth->phdr.ts.secs++;
             }
             wth->phdr.ts.nsecs =
-                ((wth->capture.catapult_dct2000->start_usecs + useconds) % 1000000) *1000;
+                ((file_externals->start_usecs + useconds) % 1000000) *1000;
 
             /* Get buffer pointer ready */
             buffer_assure_space(wth->frame_buffer,
@@ -358,61 +365,71 @@ gboolean catapult_dct2000_read(wtap *wth, int *err, gchar **err_info _U_,
                                 strlen(protocol_name)+1 +    /* Protocol name */
                                 1 +                          /* direction */
                                 1 +                          /* encap */
-                                (data_chars/2));
+                                (is_comment ? data_chars : (data_chars/2)));
             frame_buffer = buffer_start_ptr(wth->frame_buffer);
 
 
             /*********************/
             /* Write stub header */
             stub_offset = write_stub_header(frame_buffer, timestamp_string,
-                                            direction, encap);
+                                            direction, encap, context_name,
+                                            context_port,
+                                            protocol_name, variant_name,
+                                            outhdr_name);
 
             /* Binary data length is half bytestring length + stub header */
-            wth->phdr.len = data_chars/2 + stub_offset;
-            wth->phdr.caplen = data_chars/2 + stub_offset;
+            wth->phdr.len = stub_offset + (is_comment ? data_chars : (data_chars/2));
+            wth->phdr.caplen = stub_offset + (is_comment ? data_chars : (data_chars/2));
 
 
-            /*************************/
-            /* Copy data into buffer */
-            for (n=0; n <= data_chars; n+=2)
-            {
-                frame_buffer[stub_offset + n/2] =
-                    (hex_from_char(linebuff[dollar_offset+n]) << 4) |
-                     hex_from_char(linebuff[dollar_offset+n+1]);
+            if (!is_comment) {
+                /****************************************************/
+                /* Copy data into buffer, converting from ascii hex */
+                for (n=0; n <= data_chars; n+=2) {
+                    frame_buffer[stub_offset + n/2] =
+                        hex_byte_from_chars(linebuff+dollar_offset+n);
+                }
+            }
+            else {
+                /***********************************************************/
+                /* Copy packet data into buffer, just copying ascii chars  */
+                for (n=0; n <= data_chars; n++) {
+                    frame_buffer[stub_offset + n] = linebuff[dollar_offset+n];
+                }
             }
 
             /* Store the packet prefix in the hash table */
             line_prefix_info = g_malloc(sizeof(line_prefix_info_t));
 
             /* Create and use buffer for contents before time */
-            line_prefix_info->before_time = g_malloc(before_time_offset+1);
-            strncpy(line_prefix_info->before_time, linebuff, before_time_offset);
-            line_prefix_info->before_time[before_time_offset] = '\0';
+            line_prefix_info->before_time = g_malloc(before_time_offset+2);
+            g_strlcpy(line_prefix_info->before_time, linebuff, before_time_offset+1);
+            line_prefix_info->before_time[before_time_offset+1] = '\0';
 
             /* Create and use buffer for contents before time.
                Do this only if it doesn't correspond to " l ", which is by far the most
                common case. */
             if (((size_t)(dollar_offset - after_time_offset -1) == strlen(" l ")) &&
-                (strncmp(linebuff+after_time_offset, " l ", strlen(" l ")) == 0))
-            {
+                (strncmp(linebuff+after_time_offset, " l ", strlen(" l ")) == 0)) {
+
                 line_prefix_info->after_time = NULL;
             }
-            else
-            {
+            else {
+                /* Allocate & write buffer for line between timestamp and data */
                 line_prefix_info->after_time = g_malloc(dollar_offset - after_time_offset);
-                strncpy(line_prefix_info->after_time, linebuff+after_time_offset,
-                        dollar_offset - after_time_offset);
+                g_strlcpy(line_prefix_info->after_time, linebuff+after_time_offset,
+                          dollar_offset - after_time_offset);
                 line_prefix_info->after_time[dollar_offset - after_time_offset-1] = '\0';
             }
 
             /* Add packet entry into table */
-            pkey = g_malloc(sizeof(pkey));
+            pkey = g_malloc(sizeof(*pkey));
             *pkey = this_offset;
             g_hash_table_insert(file_externals->packet_prefix_table, pkey, line_prefix_info);
 
             /* Set pseudo-header if necessary */
             set_pseudo_header_info(wth, encap, this_offset, &wth->pseudo_header,
-                                   direction);
+                                   direction, aal_header_chars);
 
             /* OK, we have packet details to return */
             *err = errno;
@@ -431,11 +448,19 @@ gboolean catapult_dct2000_read(wtap *wth, int *err, gchar **err_info _U_,
 /**************************************************/
 static gboolean
 catapult_dct2000_seek_read(wtap *wth, gint64 seek_off,
-                           union wtap_pseudo_header *pseudo_header, guchar *pd,
+                           union wtap_pseudo_header *pseudo_header, guint8 *pd,
                            int length, int *err, gchar **err_info)
 {
     gint64 offset = wth->data_offset;
     long dollar_offset, before_time_offset, after_time_offset;
+    static gchar linebuff[MAX_LINE_LENGTH+1];
+    gchar aal_header_chars[AAL_HEADER_CHARS];
+    gchar context_name[MAX_CONTEXT_NAME];
+    guint8 context_port;
+    gchar protocol_name[MAX_PROTOCOL_NAME+1];
+    gchar variant_name[MAX_VARIANT_DIGITS+1];
+    gchar outhdr_name[MAX_OUTHDR_NAME+1];
+    int  is_comment = FALSE;
     packet_direction_t direction;
     int encap;
     int seconds, useconds, data_chars;
@@ -444,27 +469,28 @@ catapult_dct2000_seek_read(wtap *wth, gint64 seek_off,
     *err = errno = 0;
 
     /* Seek to beginning of packet */
-    if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
-    {
+    if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1) {
         return FALSE;
     }
 
-    /* Re-read whole line (this should succeed) */
-    if (read_new_line(wth->random_fh, &offset, &length) == FALSE)
-    {
+    /* Re-read whole line (this really should succeed) */
+    if (read_new_line(wth->random_fh, &offset, &length, linebuff,
+                      sizeof linebuff) == FALSE) {
         return FALSE;
     }
 
     /* Try to parse this line again (should succeed as re-reading...) */
-    if (parse_line(length, &seconds, &useconds,
+    if (parse_line(linebuff, length, &seconds, &useconds,
                    &before_time_offset, &after_time_offset,
                    &dollar_offset,
-                   &data_chars, &direction, &encap))
-    {
+                   &data_chars, &direction, &encap, &is_comment,
+                   aal_header_chars,
+                   context_name, &context_port,
+                   protocol_name, variant_name, outhdr_name)) {
         int n;
         int stub_offset = 0;
-        char timestamp_string[32];
-        sprintf(timestamp_string, "%d.%04d", seconds, useconds/100);
+        char timestamp_string[MAX_TIMESTAMP_LEN+1];
+        g_snprintf(timestamp_string, MAX_TIMESTAMP_LEN, "%d.%04d", seconds, useconds/100);
 
         /* Make sure all packets go to catapult dct2000 dissector */
         wth->phdr.pkt_encap = WTAP_ENCAP_CATAPULT_DCT2000;
@@ -472,20 +498,31 @@ catapult_dct2000_seek_read(wtap *wth, gint64 seek_off,
 
         /*********************/
         /* Write stub header */
-        stub_offset = write_stub_header((guchar*)pd, timestamp_string,
-                                        direction, encap);
-
-
-        /********************************/
-        /* Copy packet data into buffer */
-        for (n=0; n <= data_chars; n+=2)
-        {
-            pd[stub_offset + n/2] = (hex_from_char(linebuff[dollar_offset+n]) << 4) |
-                                     hex_from_char(linebuff[dollar_offset+n+1]);
+        stub_offset = write_stub_header(pd, timestamp_string,
+                                        direction, encap, context_name,
+                                        context_port,
+                                        protocol_name, variant_name,
+                                        outhdr_name);
+
+
+        if (!is_comment) {
+            /***********************************************************/
+            /* Copy packet data into buffer, converting from ascii hex */
+            for (n=0; n <= data_chars; n+=2) {
+                pd[stub_offset + n/2] = hex_byte_from_chars(linebuff+dollar_offset+n);
+            }
+        }
+        else {
+            /***********************************************************/
+            /* Copy packet data into buffer, just copying ascii chars  */
+            for (n=0; n <= data_chars; n++) {
+                pd[stub_offset+n] = linebuff[dollar_offset+n];
+            }
         }
 
         /* Set packet pseudo-header if necessary */
-        set_pseudo_header_info(wth, encap, seek_off, pseudo_header, direction);
+        set_pseudo_header_info(wth, encap, seek_off, pseudo_header, direction,
+                               aal_header_chars);
 
         *err = errno = 0;
         return TRUE;
@@ -494,23 +531,24 @@ catapult_dct2000_seek_read(wtap *wth, gint64 seek_off,
     /* If get here, must have failed */
     *err = errno;
     *err_info = g_strdup_printf("catapult dct2000: seek_read failed to read/parse "
-                                "line at position %lld", (long long) seek_off);
+                                "line at position %" G_GINT64_MODIFIER "d",
+                                seek_off);
     return FALSE;
 }
 
 
-/******************************************/
-/* Free dct2000-specific capture info     */
-/******************************************/
-void catapult_dct2000_close(wtap *wth)
+/***************************************************************************/
+/* Free dct2000-specific capture info from file that was open for reading  */
+/***************************************************************************/
+static void
+catapult_dct2000_close(wtap *wth)
 {
-    /* Look up externals for this file */
+    /* Get externals for this file */
     dct2000_file_externals_t *file_externals =
-        (dct2000_file_externals_t*)g_hash_table_lookup(file_externals_table, wth);
+        (dct2000_file_externals_t*)wth->priv;
 
     /* The entry *has* to be found */
-    if (!file_externals)
-    {
+    if (!file_externals) {
         return;
     }
 
@@ -519,15 +557,6 @@ void catapult_dct2000_close(wtap *wth)
                                 free_line_prefix_info, NULL);
     /* Free up its line prefix table */
     g_hash_table_destroy(file_externals->packet_prefix_table);
-
-    /* And remove the externals entry from the global table */
-    g_hash_table_remove(file_externals_table, (void*)wth);
-
-    /* And free up file_externals itself */
-    g_free(file_externals);
-
-    /* Also free this capture info */
-    g_free(wth->capture.catapult_dct2000);
 }
 
 
@@ -537,15 +566,20 @@ void catapult_dct2000_close(wtap *wth)
 /* Dump functions          */
 /***************************/
 
+typedef struct {
+    gboolean           first_packet_written;
+    struct wtap_nstime start_time;
+} dct2000_dump_t;
+
 /*****************************************************/
 /* The file that we are writing to has been opened.  */
 /* Set other dump callbacks.                         */
 /*****************************************************/
-gboolean catapult_dct2000_dump_open(wtap_dumper *wdh, gboolean cant_seek _U_, int *err _U_)
+gboolean
+catapult_dct2000_dump_open(wtap_dumper *wdh, int *err _U_)
 {
     /* Fill in other dump callbacks */
     wdh->subtype_write = catapult_dct2000_dump;
-    wdh->subtype_close = catapult_dct2000_dump_close;
 
     return TRUE;
 }
@@ -554,14 +588,16 @@ gboolean catapult_dct2000_dump_open(wtap_dumper *wdh, gboolean cant_seek _U_, in
 /* Respond to queries about which encap types we support */
 /* writing to.                                           */
 /*********************************************************/
-int catapult_dct2000_dump_can_write_encap(int encap)
+int
+catapult_dct2000_dump_can_write_encap(int encap)
 {
-    switch (encap)
-    {
+    switch (encap) {
         case WTAP_ENCAP_CATAPULT_DCT2000:
             /* We support this */
             return 0;
+
         default:
+            /* But don't write to any other formats... */
             return WTAP_ERR_UNSUPPORTED_ENCAP;
     }
 }
@@ -570,47 +606,58 @@ int catapult_dct2000_dump_can_write_encap(int encap)
 /*****************************************/
 /* Write a single packet out to the file */
 /*****************************************/
-gboolean catapult_dct2000_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
+
+static gboolean
+catapult_dct2000_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
                                const union wtap_pseudo_header *pseudo_header,
-                               const guchar *pd, int *err _U_)
+                               const guint8 *pd, int *err)
 {
     guint32 n;
     line_prefix_info_t *prefix = NULL;
     gchar time_string[16];
+    gboolean is_comment;
+    dct2000_dump_t *dct2000;
 
     /******************************************************/
-    /* Look up the file_externals structure for this file */
+    /* Get the file_externals structure for this file */
     /* Find wtap external structure for this wtap */
     dct2000_file_externals_t *file_externals =
-        (dct2000_file_externals_t*)g_hash_table_lookup(file_externals_table,
-                                                       pseudo_header->dct2000.wth);
+        (dct2000_file_externals_t*)pseudo_header->dct2000.wth->priv;
 
-    if (wdh->dump.dct2000 == NULL)
-    {
-        /* Allocate the dct2000-specific dump structure */
-        wdh->dump.dct2000 = g_malloc(sizeof(catapult_dct2000_t));
+    dct2000 = (dct2000_dump_t *)wdh->priv;
+    if (dct2000 == NULL) {
 
         /* Write out saved first line */
-        fwrite(file_externals->firstline, 1, file_externals->firstline_length, wdh->fh);
-        fwrite("\n", 1, 1, wdh->fh);
+        if (!wtap_dump_file_write(wdh, file_externals->firstline,
+                                  file_externals->firstline_length, err)) {
+            return FALSE;
+        }
+        if (!wtap_dump_file_write(wdh, "\n", 1, err)) {
+            return FALSE;
+        }
 
         /* Also write out saved second line with timestamp corresponding to the
            opening time of the log.
         */
-        fwrite(file_externals->secondline, 1, file_externals->secondline_length, wdh->fh);
-        fwrite("\n", 1, 1, wdh->fh);
+        if (!wtap_dump_file_write(wdh, file_externals->secondline,
+                                  file_externals->secondline_length, err)) {
+            return FALSE;
+        }
+        if (!wtap_dump_file_write(wdh, "\n", 1, err)) {
+            return FALSE;
+        }
 
         /* Allocate the dct2000-specific dump structure */
-        wdh->dump.dct2000 = g_malloc(sizeof(catapult_dct2000_t));
+        dct2000 = (dct2000_dump_t *)g_malloc(sizeof(dct2000_dump_t));
+        wdh->priv = (void *)dct2000;
 
         /* Copy time of beginning of file */
-        wdh->dump.dct2000->start_time.secs =
-            pseudo_header->dct2000.wth->capture.catapult_dct2000->start_secs;
-        wdh->dump.dct2000->start_time.nsecs =
-            (pseudo_header->dct2000.wth->capture.catapult_dct2000->start_usecs * 1000);
+        dct2000->start_time.secs = file_externals->start_secs;
+        dct2000->start_time.nsecs =
+            (file_externals->start_usecs * 1000);
 
         /* Set flag do don't write header out again */
-        wdh->dump.dct2000->first_packet_written = TRUE;
+        dct2000->first_packet_written = TRUE;
     }
 
 
@@ -622,33 +669,42 @@ gboolean catapult_dct2000_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
                                                       (const void*)&(pseudo_header->dct2000.seek_off));
 
     /* Write out text before timestamp */
-    fwrite(prefix->before_time, 1, strlen(prefix->before_time), wdh->fh);
+    if (!wtap_dump_file_write(wdh, prefix->before_time,
+                              strlen(prefix->before_time), err)) {
+        return FALSE;
+    }
+
+    /* Can infer from prefix if this is a comment (whose payload is displayed differently) */
+    is_comment = (strstr(prefix->before_time, "/////") != NULL);
 
     /* Calculate time of this packet to write, relative to start of dump */
-    if (phdr->ts.nsecs >= wdh->dump.dct2000->start_time.nsecs)
-    {
+    if (phdr->ts.nsecs >= dct2000->start_time.nsecs) {
         g_snprintf(time_string, 16, "%ld.%04d",
-                 (long)(phdr->ts.secs - wdh->dump.dct2000->start_time.secs),
-                 (phdr->ts.nsecs - wdh->dump.dct2000->start_time.nsecs) / 100000);
+                  (long)(phdr->ts.secs - dct2000->start_time.secs),
+                  (phdr->ts.nsecs - dct2000->start_time.nsecs) / 100000);
     }
-    else
-    {
+    else {
         g_snprintf(time_string, 16, "%ld.%04u",
-                 (long)(phdr->ts.secs - wdh->dump.dct2000->start_time.secs-1),
-                 ((1000000000 + (phdr->ts.nsecs / 100000)) - (wdh->dump.dct2000->start_time.nsecs / 100000)) % 10000);
+                  (long)(phdr->ts.secs - dct2000->start_time.secs-1),
+                  ((1000000000 + (phdr->ts.nsecs / 100000)) - (dct2000->start_time.nsecs / 100000)) % 10000);
     }
 
     /* Write out the calculated timestamp */
-    fwrite(time_string, 1, strlen(time_string), wdh->fh);
+    if (!wtap_dump_file_write(wdh, time_string, strlen(time_string), err)) {
+        return FALSE;
+    }
 
     /* Write out text between timestamp and start of hex data */
-    if (prefix->after_time == NULL)
-    {
-        fwrite(" l ", 1, strlen(" l "), wdh->fh);
+    if (prefix->after_time == NULL) {
+        if (!wtap_dump_file_write(wdh, " l ", strlen(" l "), err)) {
+            return FALSE;
+        }
     }
-    else
-    {
-        fwrite(prefix->after_time, 1, strlen(prefix->after_time), wdh->fh);
+    else {
+        if (!wtap_dump_file_write(wdh, prefix->after_time,
+                                  strlen(prefix->after_time), err)) {
+            return FALSE;
+        }
     }
 
 
@@ -684,66 +740,72 @@ gboolean catapult_dct2000_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
 
     /**************************************/
     /* Remainder is encapsulated protocol */
-    fwrite("$", 1, 1, wdh->fh);
+    if (!wtap_dump_file_write(wdh, "$", 1, err)) {
+        return FALSE;
+    }
 
-    /* Each binary byte is written out as 2 hex string chars */ 
-    for (; n < phdr->len; n++)
-    {
-        gchar c[2];
-        c[0] = char_from_hex((guchar)(pd[n] >> 4));
-        c[1] = char_from_hex((guchar)(pd[n] & 0x0f));
+    if (!is_comment) {
+        /* Each binary byte is written out as 2 hex string chars */ 
+        for (; n < phdr->len; n++) {
+            gchar c[2];
+            c[0] = char_from_hex((guint8)(pd[n] >> 4));
+            c[1] = char_from_hex((guint8)(pd[n] & 0x0f));
 
-        /* Write both hex chars of byte together */
-        fwrite(c, 1, 2, wdh->fh);
+            /* Write both hex chars of byte together */
+            if (!wtap_dump_file_write(wdh, c, 2, err)) {
+                return FALSE;
+            }
+        }
     }
+    else {
+        for (; n < phdr->len; n++) {
+            char c[1];
+            c[0] = pd[n];
 
-    /* End the line */
-    fwrite("\n", 1, 1, wdh->fh);
-
-    return TRUE;
-}
+            /* Write both hex chars of byte together */
+            if (!wtap_dump_file_write(wdh, c, 1, err)) {
+                return FALSE;
+            }
+        }
+    }
 
+    /* End the line */
+    if (!wtap_dump_file_write(wdh, "\n", 1, err)) {
+        return FALSE;
+    }
 
-/******************************************************/
-/* Close a file we've been writing to.                */
-/******************************************************/
-static gboolean catapult_dct2000_dump_close(wtap_dumper *wdh _U_, int *err _U_)
-{
     return TRUE;
 }
 
 
-
-
 /****************************/
 /* Private helper functions */
 /****************************/
 
 /**********************************************************************/
 /* Read a new line from the file, starting at offset.                 */
-/* - writes data to static var linebuff                               */
+/* - writes data to its argument linebuff                             */
 /* - on return 'offset' will point to the next position to read from  */
 /* - return TRUE if this read is successful                           */
 /**********************************************************************/
-gboolean read_new_line(FILE_T fh, gint64 *offset, gint *length)
+static gboolean
+read_new_line(FILE_T fh, gint64 *offset, gint *length,
+                       gchar *linebuff, size_t linebuffsize)
 {
-    char *result;
-
     /* Read in a line */
-    result = file_gets(linebuff, MAX_LINE_LENGTH, fh);
-    if (result == NULL)
-    {
-        /* No characters found */
+    gint64 pos_before = file_tell(fh);
+    char *result = file_gets(linebuff, (int)linebuffsize - 1, fh);
+    if (result == NULL) {
+        /* No characters found, or error */
         return FALSE;
     }
 
-    /* Set length and offset.. */
-    *length = strlen(linebuff);
+    /* Set length (avoiding strlen()) and offset.. */
+    *length = (gint)(file_tell(fh) - pos_before);
     *offset = *offset + *length;
 
     /* ...but don't want to include newline in line length */
-    if (linebuff[*length-1] == '\n')
-    {
+    if (linebuff[*length-1] == '\n') {
         linebuff[*length-1] = '\0';
         *length = *length - 1;
     }
@@ -759,14 +821,20 @@ gboolean read_new_line(FILE_T fh, gint64 *offset, gint *length)
 /* - data position and length                                         */
 /* Return TRUE if this packet looks valid and can be displayed        */
 /**********************************************************************/
-gboolean parse_line(gint line_length, gint *seconds, gint *useconds,
-                    long *before_time_offset, long *after_time_offset,
-                    long *data_offset, gint *data_chars,
-                    packet_direction_t *direction,
-                    int *encap)
+static gboolean
+parse_line(gchar *linebuff, gint line_length,
+                           gint *seconds, gint *useconds,
+                           long *before_time_offset, long *after_time_offset,
+                           long *data_offset, gint *data_chars,
+                           packet_direction_t *direction,
+                           int *encap, int *is_comment,
+                           gchar *aal_header_chars,
+                           gchar *context_name, guint8 *context_portp,
+                           gchar *protocol_name, gchar *variant_name,
+                           gchar *outhdr_name)
 {
     int  n = 0;
-    int  port_digits = 0;
+    int  port_digits;
     char port_number_string[MAX_PORT_DIGITS+1];
     int  variant_digits = 0;
     int  variant = 1;
@@ -777,140 +845,142 @@ gboolean parse_line(gint line_length, gint *seconds, gint *useconds,
     int  seconds_chars;
     char subsecond_decimals_buff[MAX_SUBSECOND_DECIMALS+1];
     int  subsecond_decimals_chars;
-
+    int  skip_first_byte = FALSE;
     gboolean atm_header_present = FALSE;
 
+    *is_comment = FALSE;
+
     /* Read context name until find '.' */
-    for (n=0; linebuff[n] != '.' && (n < MAX_CONTEXT_NAME) && (n+1 < line_length); n++)
-    {
-       if (!isalnum((int)linebuff[n]) && (linebuff[n] != '_'))
-        {
+    for (n=0; (linebuff[n] != '.') && (n < MAX_CONTEXT_NAME) && (n+1 < line_length); n++) {
+        if (linebuff[n] == '/') {
+            context_name[n] = '\0';
+
+            /* If not a comment (/////), not a valid line */
+            if (strncmp(linebuff+n, "/////", 5) != 0) {
+                return FALSE;
+            }
+
+            /* There is no variant, outhdr, etc.  Set protocol to be a comment */
+            g_snprintf(protocol_name, MAX_PROTOCOL_NAME, "comment");
+            *is_comment = TRUE;
+            break;
+        }
+        if (!isalnum((guchar)linebuff[n]) && (linebuff[n] != '_') && (linebuff[n] != '-')) {
             return FALSE;
         }
         context_name[n] = linebuff[n];
     }
-    if (n == MAX_CONTEXT_NAME || (n+1 >= line_length))
-    {
+    if (n == MAX_CONTEXT_NAME || (n+1 >= line_length)) {
         return FALSE;
     }
 
-    /* '.' must follow context name */
-    if (linebuff[n] != '.')
-    {
-        return FALSE;
-    }
-    context_name[n] = '\0';
-    /* Skip it */
-    n++;
-
+    /* Reset strings (that won't be set by comments) */
+    variant_name[0] = '\0';
+    outhdr_name[0] = '\0';
+    port_number_string[0] = '\0';
 
-    /* Now read port number */
-    for (port_digits = 0;
-         (linebuff[n] != '/') && (port_digits <= MAX_PORT_DIGITS) && (n+1 < line_length);
-         n++, port_digits++)
-    {
-       if (!isdigit((int)linebuff[n]))
-        {
+    if (!(*is_comment)) {
+        /* '.' must follow context name */
+        if (linebuff[n] != '.') {
             return FALSE;
         }
-        port_number_string[port_digits] = linebuff[n];
-    }
-    if (port_digits > MAX_PORT_DIGITS || (n+1 >= line_length))
-    {
-        return FALSE;
-    }
+        context_name[n] = '\0';
+        /* Skip it */
+        n++;
 
-    /* Slash char must follow port number */
-    if (linebuff[n] != '/')
-    {
-        return FALSE;
-    }
-    port_number_string[port_digits] = '\0';
-    context_port = atoi(port_number_string);
-    /* Skip it */
-    n++;
+        /* Now read port number */
+        for (port_digits = 0;
+             (linebuff[n] != '/') && (port_digits <= MAX_PORT_DIGITS) && (n+1 < line_length);
+             n++, port_digits++) {
 
+            if (!isdigit((guchar)linebuff[n])) {
+                return FALSE;
+            }
+            port_number_string[port_digits] = linebuff[n];
+        }
+        if (port_digits > MAX_PORT_DIGITS || (n+1 >= line_length)) {
+            return FALSE;
+        }
 
-    /* Now for the protocol name */
-    for (protocol_chars = 0;
-         (linebuff[n] != '/') && (protocol_chars < MAX_PROTOCOL_NAME) && (n < line_length);
-         n++, protocol_chars++)
-    {
-       if (!isalnum((int)linebuff[n]) && linebuff[n] != '_')
+        /* Slash char must follow port number */
+        if (linebuff[n] != '/')
         {
             return FALSE;
         }
-        protocol_name[protocol_chars] = linebuff[n];
-    }
-    if (protocol_chars == MAX_PROTOCOL_NAME || n >= line_length)
-    {
-        /* If doesn't fit, fail rather than truncate */
-        return FALSE;
-    }
-    protocol_name[protocol_chars] = '\0';
+        port_number_string[port_digits] = '\0';
+        *context_portp = atoi(port_number_string);
+        /* Skip it */
+        n++;
 
-    /* Slash char must follow protocol name */
-    if (linebuff[n] != '/')
-    {
-        return FALSE;
-    }
-    /* Skip it */
-    n++;
+        /* Now for the protocol name */
+        for (protocol_chars = 0;
+             (linebuff[n] != '/') && (protocol_chars < MAX_PROTOCOL_NAME) && (n < line_length);
+             n++, protocol_chars++) {
 
+            if (!isalnum((guchar)linebuff[n]) && linebuff[n] != '_') {
+                return FALSE;
+            }
+            protocol_name[protocol_chars] = linebuff[n];
+        }
+        if (protocol_chars == MAX_PROTOCOL_NAME || n >= line_length) {
+            /* If doesn't fit, fail rather than truncate */
+            return FALSE;
+        }
+        protocol_name[protocol_chars] = '\0';
 
-    /* Following the / is the variant number.  No digits indicate 1 */
-    for (variant_digits = 0;
-         (isdigit((int)linebuff[n])) && (variant_digits <= MAX_VARIANT_DIGITS) && (n+1 < line_length);
-         n++, variant_digits++)
-    {
-       if (!isdigit((int)linebuff[n]))
-        {
+        /* Slash char must follow protocol name */
+        if (linebuff[n] != '/') {
             return FALSE;
         }
-        variant_name[variant_digits] = linebuff[n];
-    }
-    if (variant_digits > MAX_VARIANT_DIGITS || (n+1 >= line_length))
-    {
-        return FALSE;
-    }
-    if (variant_digits > 0)
-    {
-        variant_name[variant_digits] = '\0';
-        variant = atoi(variant_name);
-    }
-    else
-    {
-        strcpy(variant_name, "1");
-    }
+        /* Skip it */
+        n++;
 
 
-    /* Outheader values may follow */
-    outhdr_name[0] = '\0';
-    if (linebuff[n] == ',')
-    {
-        /* Skip , */
-        n++;
+        /* Following the / is the variant number.  No digits indicate 1 */
+        for (variant_digits = 0;
+             (isdigit((guchar)linebuff[n])) && (variant_digits <= MAX_VARIANT_DIGITS) && (n+1 < line_length);
+             n++, variant_digits++) {
 
-        for (outhdr_chars = 0;
-             (isdigit((int)linebuff[n]) || linebuff[n] == ',') &&
-             (outhdr_chars <= MAX_OUTHDR_NAME) && (n+1 < line_length);
-             n++, outhdr_chars++)
-        {
-           if (!isdigit((int)linebuff[n]) && (linebuff[n] != ','))
-            {
+            if (!isdigit((guchar)linebuff[n])) {
                 return FALSE;
             }
-            outhdr_name[outhdr_chars] = linebuff[n];
+            variant_name[variant_digits] = linebuff[n];
         }
-        if (outhdr_chars > MAX_OUTHDR_NAME || (n+1 >= line_length))
-        {
+        if (variant_digits > MAX_VARIANT_DIGITS || (n+1 >= line_length)) {
             return FALSE;
         }
-        /* Terminate (possibly empty) string */
-        outhdr_name[outhdr_chars] = '\0';
-    }
+        if (variant_digits > 0) {
+            variant_name[variant_digits] = '\0';
+            variant = atoi(variant_name);
+        }
+        else {
+            g_strlcpy(variant_name, "1", MAX_VARIANT_DIGITS+1);
+        }
+
 
+        /* Outheader values may follow */
+        outhdr_name[0] = '\0';
+        if (linebuff[n] == ',') {
+            /* Skip , */
+            n++;
 
+            for (outhdr_chars = 0;
+                 (isdigit((guchar)linebuff[n]) || linebuff[n] == ',') &&
+                 (outhdr_chars <= MAX_OUTHDR_NAME) && (n+1 < line_length);
+                 n++, outhdr_chars++) {
+
+                if (!isdigit((guchar)linebuff[n]) && (linebuff[n] != ',')) {
+                    return FALSE;
+                }
+                outhdr_name[outhdr_chars] = linebuff[n];
+            }
+            if (outhdr_chars > MAX_OUTHDR_NAME || (n+1 >= line_length)) {
+                return FALSE;
+            }
+            /* Terminate (possibly empty) string */
+            outhdr_name[outhdr_chars] = '\0';
+        }
+    }
 
 
     /******************************************************************/
@@ -918,8 +988,10 @@ gboolean parse_line(gint line_length, gint *seconds, gint *useconds,
 
     if ((strcmp(protocol_name, "ip") == 0) ||
         (strcmp(protocol_name, "sctp") == 0) ||
-        (strcmp(protocol_name, "mipv6") == 0))
-    {
+        (strcmp(protocol_name, "gre") == 0) ||
+        (strcmp(protocol_name, "mipv6") == 0) ||
+        (strcmp(protocol_name, "igmp") == 0)) {
+
         *encap = WTAP_ENCAP_RAW_IP;
     }
     else
@@ -928,70 +1000,67 @@ gboolean parse_line(gint line_length, gint *seconds, gint *useconds,
     if ((strcmp(protocol_name, "fp") == 0) ||
         (strcmp(protocol_name, "fp_r4") == 0) ||
         (strcmp(protocol_name, "fp_r5") == 0) ||
-        (strcmp(protocol_name, "fp_r6") == 0))
-    {
-        if ((variant > 256) && (variant % 256 == 3))
-        {
+        (strcmp(protocol_name, "fp_r6") == 0) ||
+        (strcmp(protocol_name, "fp_r7") == 0) ||
+        (strcmp(protocol_name, "fp_r8") == 0)) {
+
+        if ((variant > 256) && (variant % 256 == 3)) {
             /* FP over udp is contained in IPPrim... */
             *encap = 0;
         }
-        else
-        {
+        else {
             /* FP over AAL0 or AAL2 */
             *encap = WTAP_ENCAP_ATM_PDUS_UNTRUNCATED;
             atm_header_present = TRUE;
         }
     }
-    else if (strcmp(protocol_name, "fpiur_r5") == 0)
-    {
+    else if (strcmp(protocol_name, "fpiur_r5") == 0) {
         /* FP (IuR) over AAL2 */
         *encap = WTAP_ENCAP_ATM_PDUS_UNTRUNCATED;
         atm_header_present = TRUE;
     }
 
-
     else
-    if (strcmp(protocol_name, "ppp") == 0)
-    {
+    if (strcmp(protocol_name, "ppp") == 0) {
         *encap = WTAP_ENCAP_PPP;
     }
     else
-    if (strcmp(protocol_name, "isdn_l3") == 0)
-    {
-        /* Despite the name, this does seem to correspond to L2... */
+    if (strcmp(protocol_name, "isdn_l3") == 0) {
+       /* TODO: find out what this byte means... */
+        skip_first_byte = TRUE;
         *encap = WTAP_ENCAP_ISDN;
     }
     else
-    if (strcmp(protocol_name, "ethernet") == 0)
-    {
+    if (strcmp(protocol_name, "isdn_l2") == 0) {
+        *encap = WTAP_ENCAP_ISDN;
+    }
+    else
+    if (strcmp(protocol_name, "ethernet") == 0) {
         *encap = WTAP_ENCAP_ETHERNET;
     }
     else
     if ((strcmp(protocol_name, "saalnni_sscop") == 0) ||
-        (strcmp(protocol_name, "saaluni_sscop") == 0))
-    {
+        (strcmp(protocol_name, "saaluni_sscop") == 0)) {
+
         *encap = DCT2000_ENCAP_SSCOP;
     }
     else
-    if (strcmp(protocol_name, "frelay_l2") == 0)
-    {
+    if (strcmp(protocol_name, "frelay_l2") == 0) {
         *encap = WTAP_ENCAP_FRELAY;
     }
     else
-    if (strcmp(protocol_name, "ss7_mtp2") == 0)
-    {
+    if (strcmp(protocol_name, "ss7_mtp2") == 0) {
         *encap = DCT2000_ENCAP_MTP2;
     }
     else
     if ((strcmp(protocol_name, "nbap") == 0) ||
         (strcmp(protocol_name, "nbap_r4") == 0) ||
-        (strncmp(protocol_name, "nbap_sscfuni", strlen("nbap_sscfuni")) == 0))
-    {
+        (strncmp(protocol_name, "nbap_sscfuni", strlen("nbap_sscfuni")) == 0)) {
+
         /* The entire message in these cases is nbap, so use an encap value. */
         *encap = DCT2000_ENCAP_NBAP;
     }
-    else
-    {
+    else {
         /* Not a supported board port protocol/encap, but can show as raw data or
            in some cases find protocol embedded inside primitive */
         *encap = DCT2000_ENCAP_UNHANDLED;
@@ -999,65 +1068,75 @@ gboolean parse_line(gint line_length, gint *seconds, gint *useconds,
 
 
     /* Find separate ATM header if necessary */
-    if (atm_header_present)
-    {
+    if (atm_header_present) {
         int header_chars_seen = 0;
 
         /* Scan ahead to the next $ */
         for (; (linebuff[n] != '$') && (n+1 < line_length); n++);
         /* Skip it */
         n++;
-        if (n+1 >= line_length)
-        {
+        if (n+1 >= line_length) {
             return FALSE;
         }
 
         /* Read consecutive hex chars into atm header buffer */
         for (;
-             (isalnum((int)linebuff[n]) &&
+             ((linebuff[n] >= '0') && (linebuff[n] <= '?') &&
               (n < line_length) &&
               (header_chars_seen < AAL_HEADER_CHARS));
-             n++, header_chars_seen++)
-        {
+             n++, header_chars_seen++) {
+
             aal_header_chars[header_chars_seen] = linebuff[n];
+            /* Next 6 characters after '9' are mapped to a->f */
+            if (!isdigit((guchar)linebuff[n])) {
+                aal_header_chars[header_chars_seen] = 'a' + (linebuff[n] - '9') -1;
+            }
         }
 
-        /* Sometimes see strange encoding of cid in last (non-digit) character */
-        if (header_chars_seen == (AAL_HEADER_CHARS-1))
-        {
-            aal_header_chars[AAL_HEADER_CHARS-1] = linebuff[n];
-            header_chars_seen++;
+        if (header_chars_seen != AAL_HEADER_CHARS || n >= line_length) {
+            return FALSE;
         }
+    }
 
-        if (header_chars_seen != AAL_HEADER_CHARS || n >= line_length)
-        {
-            return FALSE;
+    /* Skip next '/' */
+    n++;
+
+    /* If there is a number, skip all info to next '/'.
+       TODO: for IP encapsulation, should store PDCP ueid, drb in pseudo info
+       and display dct2000 dissector... */
+    if (isdigit(linebuff[n])) {
+        while ((n+1 < line_length) && linebuff[n] != '/') {
+            n++;
         }
     }
 
+    /* Skip '/' */
+    while ((n+1 < line_length) && linebuff[n] == '/') {
+        n++;
+    }
 
-    /* Scan ahead to the next space */
-    for (; (linebuff[n] != ' ') && (n+1 < line_length); n++);
-    if (n+1 >= line_length)
-    {
-        return FALSE;
+    /* Skip a space that may happen here */
+    if ((n+1 < line_length) && linebuff[n] == ' ') {
+        n++;
     }
-    /* Skip it */
-    n++;
 
     /* Next character gives direction of message (must be 's' or 'r') */
-    if (linebuff[n] == 's')
-    {
-        *direction = sent;
-    }
-    else
-    if (linebuff[n] == 'r')
-    {
-        *direction = received;
+    if (!(*is_comment)) {
+        if (linebuff[n] == 's') {
+            *direction = sent;
+        }
+        else
+        if (linebuff[n] == 'r') {
+            *direction = received;
+        }
+        else {
+            return FALSE;
+        }
+        /* Skip it */
+        n++;
     }
-    else
-    {
-        return FALSE;
+    else {
+        *direction = sent;
     }
 
 
@@ -1065,9 +1144,15 @@ gboolean parse_line(gint line_length, gint *seconds, gint *useconds,
     /* Find and read the timestamp                                       */
 
     /* Now scan to the next digit, which should be the start of the timestamp */
-    for (; !isdigit((int)linebuff[n]) && (n < line_length); n++);
-    if (n >= line_length)
-    {
+    /* This will involve skipping " tm "                                      */
+
+    for (; ((linebuff[n] != 't') || (linebuff[n+1] != 'm')) && (n+1 < line_length); n++);
+    if (n >= line_length) {
+        return FALSE;
+    }
+
+    for (; !isdigit((guchar)linebuff[n]) && (n < line_length); n++);
+    if (n >= line_length) {
         return FALSE;
     }
 
@@ -1078,17 +1163,15 @@ gboolean parse_line(gint line_length, gint *seconds, gint *useconds,
          (linebuff[n] != '.') &&
          (seconds_chars <= MAX_SECONDS_CHARS) &&
          (n < line_length);
-         n++, seconds_chars++)
-    {
-       if (!isdigit((int)linebuff[n]))
-        {
+         n++, seconds_chars++) {
+
+        if (!isdigit((guchar)linebuff[n])) {
             /* Found a non-digit before decimal point. Fail */
             return FALSE;
         }
         seconds_buff[seconds_chars] = linebuff[n];
     }
-    if (seconds_chars > MAX_SECONDS_CHARS || n >= line_length)
-    {
+    if (seconds_chars > MAX_SECONDS_CHARS || n >= line_length) {
         /* Didn't fit in buffer.  Fail rather than use truncated */
         return FALSE;
     }
@@ -1098,8 +1181,7 @@ gboolean parse_line(gint line_length, gint *seconds, gint *useconds,
     *seconds = atoi(seconds_buff);
 
     /* The decimal point must follow the last of the seconds digits */
-    if (linebuff[n] != '.')
-    {
+    if (linebuff[n] != '.') {
         return FALSE;
     }
     /* Skip it */
@@ -1110,16 +1192,14 @@ gboolean parse_line(gint line_length, gint *seconds, gint *useconds,
          (linebuff[n] != ' ') &&
          (subsecond_decimals_chars <= MAX_SUBSECOND_DECIMALS) &&
          (n < line_length);
-         n++, subsecond_decimals_chars++)
-    {
-       if (!isdigit((int)linebuff[n]))
-        {
+         n++, subsecond_decimals_chars++) {
+
+        if (!isdigit((guchar)linebuff[n])) {
             return FALSE;
         }
         subsecond_decimals_buff[subsecond_decimals_chars] = linebuff[n];
     }
-    if (subsecond_decimals_chars > MAX_SUBSECOND_DECIMALS || n >= line_length)
-    {
+    if (subsecond_decimals_chars > MAX_SUBSECOND_DECIMALS || n >= line_length) {
         /* More numbers than expected - give up */
         return FALSE;
     }
@@ -1128,17 +1208,16 @@ gboolean parse_line(gint line_length, gint *seconds, gint *useconds,
     *useconds = atoi(subsecond_decimals_buff) * 100;
 
     /* Space character must follow end of timestamp */
-    if (linebuff[n] != ' ')
-    {
+    if (linebuff[n] != ' ') {
         return FALSE;
     }
 
     *after_time_offset = n;
 
     /* Now skip ahead to find start of data (marked by '$') */
-    for (; (linebuff[n] != '$') && (n+1 < line_length); n++);
-    if (n+1 >= line_length)
-    {
+    /* Want to avoid matching with normal sprint command output at the moment... */
+    for (; (linebuff[n] != '$') && (linebuff[n] != '\'') && (n+1 < line_length); n++);
+    if ((linebuff[n] == '\'') || (n+1 >= line_length)) {
         return FALSE;
     }
     /* Skip it */
@@ -1150,11 +1229,8 @@ gboolean parse_line(gint line_length, gint *seconds, gint *useconds,
     /* Set number of chars that comprise the hex string protocol data */
     *data_chars = line_length - n;
 
-    /* Need to skip first byte (2 hex string chars) from ISDN messages.
-       TODO: find out what this byte means...
-    */
-    if (*encap == WTAP_ENCAP_ISDN)
-    {
+    /* May need to skip first byte (2 hex string chars) */
+    if (skip_first_byte) {
         *data_offset += 2;
         *data_chars -= 2;
     }
@@ -1165,33 +1241,37 @@ gboolean parse_line(gint line_length, gint *seconds, gint *useconds,
 /*****************************************************************/
 /* Write the stub info to the data buffer while reading a packet */
 /*****************************************************************/
-int write_stub_header(guchar *frame_buffer, char *timestamp_string,
-                      packet_direction_t direction, int encap)
+static int
+write_stub_header(guint8 *frame_buffer, char *timestamp_string,
+                             packet_direction_t direction, int encap,
+                             gchar *context_name, guint8 context_port,
+                             gchar *protocol_name, gchar *variant_name,
+                             gchar *outhdr_name)
 {
     int stub_offset = 0;
-    
-    strcpy((char*)frame_buffer, context_name);
-    stub_offset += (strlen(context_name) + 1);
+
+    g_strlcpy((char*)frame_buffer, context_name, MAX_CONTEXT_NAME+1);
+    stub_offset += (int)(strlen(context_name) + 1);
 
     /* Context port number */
     frame_buffer[stub_offset] = context_port;
     stub_offset++;
 
     /* Timestamp within file */
-    strcpy((char*)&frame_buffer[stub_offset], timestamp_string);
-    stub_offset += (strlen(timestamp_string) + 1);
+    g_strlcpy((char*)&frame_buffer[stub_offset], timestamp_string, MAX_TIMESTAMP_LEN+1);
+    stub_offset += (int)(strlen(timestamp_string) + 1);
 
     /* Protocol name */
-    strcpy((char*)&frame_buffer[stub_offset], protocol_name);
-    stub_offset += (strlen(protocol_name) + 1);
+    g_strlcpy((char*)&frame_buffer[stub_offset], protocol_name, MAX_PROTOCOL_NAME+1);
+    stub_offset += (int)(strlen(protocol_name) + 1);
 
     /* Protocol variant number (as string) */
-    strcpy((void*)&frame_buffer[stub_offset], variant_name);
-    stub_offset += (strlen(variant_name) + 1);
+    g_strlcpy((void*)&frame_buffer[stub_offset], variant_name, MAX_VARIANT_DIGITS+1);
+    stub_offset += (int)(strlen(variant_name) + 1);
 
     /* Outhdr */
-    strcpy((char*)&frame_buffer[stub_offset], outhdr_name);
-    stub_offset += (strlen(outhdr_name) + 1);
+    g_strlcpy((char*)&frame_buffer[stub_offset], outhdr_name, MAX_OUTHDR_NAME+1);
+    stub_offset += (int)(strlen(outhdr_name) + 1);
 
     /* Direction */
     frame_buffer[stub_offset] = direction;
@@ -1208,19 +1288,20 @@ int write_stub_header(guchar *frame_buffer, char *timestamp_string,
 /**************************************************************/
 /* Set pseudo-header info depending upon packet encapsulation */
 /**************************************************************/
-void set_pseudo_header_info(wtap *wth,
-                            int pkt_encap,
-                            gint64 file_offset,
-                            union wtap_pseudo_header *pseudo_header,
-                            packet_direction_t direction)
+static void
+set_pseudo_header_info(wtap *wth,
+                                   int pkt_encap,
+                                   gint64 file_offset,
+                                   union wtap_pseudo_header *pseudo_header,
+                                   packet_direction_t direction,
+                                   gchar *aal_header_chars)
 {
     pseudo_header->dct2000.seek_off = file_offset;
     pseudo_header->dct2000.wth = wth;
 
-    switch (pkt_encap)
-    {
+    switch (pkt_encap) {
         case WTAP_ENCAP_ATM_PDUS_UNTRUNCATED:
-            set_aal_info(pseudo_header, direction);
+            set_aal_info(pseudo_header, direction, aal_header_chars);
             break;
         case WTAP_ENCAP_ISDN:
             set_isdn_info(pseudo_header, direction);
@@ -1239,7 +1320,10 @@ void set_pseudo_header_info(wtap *wth,
 /*********************************************/
 /* Fill in atm pseudo-header with known info */
 /*********************************************/
-void set_aal_info(union wtap_pseudo_header *pseudo_header, packet_direction_t direction)
+static void
+set_aal_info(union wtap_pseudo_header *pseudo_header,
+                         packet_direction_t direction,
+                         gchar *aal_header_chars)
 {
     /* 'aal_head_chars' has this format (for AAL2 at least):
        Global Flow Control (4 bits) | VPI (8 bits) | VCI (16 bits) |
@@ -1264,8 +1348,7 @@ void set_aal_info(union wtap_pseudo_header *pseudo_header, packet_direction_t di
 
     /* vpi is 8 bits (2nd & 3rd nibble) */
     pseudo_header->dct2000.inner_pseudo_header.atm.vpi =
-        ((hex_from_char(aal_header_chars[1]) << 4) |
-          hex_from_char(aal_header_chars[2]));
+        hex_byte_from_chars(aal_header_chars+1);
 
     /* vci is next 16 bits */
     pseudo_header->dct2000.inner_pseudo_header.atm.vci =
@@ -1279,25 +1362,22 @@ void set_aal_info(union wtap_pseudo_header *pseudo_header, packet_direction_t di
 
     /* cid is usually last byte.  Unless last char is not hex digit, in which
        case cid is derived from last char in ascii */
-    if (isalnum((int)aal_header_chars[11]))
-    {
+    if (isalnum((guchar)aal_header_chars[11])) {
         pseudo_header->dct2000.inner_pseudo_header.atm.aal2_cid =
-            ((hex_from_char(aal_header_chars[10]) << 4) |
-              hex_from_char(aal_header_chars[11]));
+            hex_byte_from_chars(aal_header_chars+10);
     }
-    else
-    {
+    else {
         pseudo_header->dct2000.inner_pseudo_header.atm.aal2_cid =
-            (int)aal_header_chars[11] - 48;
+            (int)aal_header_chars[11] - '0';
     }
-
 }
 
 
 /**********************************************/
 /* Fill in isdn pseudo-header with known info */
 /**********************************************/
-void set_isdn_info(union wtap_pseudo_header *pseudo_header,
+static void
+set_isdn_info(union wtap_pseudo_header *pseudo_header,
                    packet_direction_t direction)
 {
     /* This field is used to set the 'Source' and 'Destination' columns to
@@ -1316,7 +1396,8 @@ void set_isdn_info(union wtap_pseudo_header *pseudo_header,
 /*********************************************/
 /* Fill in ppp pseudo-header with known info */
 /*********************************************/
-static void set_ppp_info(union wtap_pseudo_header *pseudo_header,
+static void
+set_ppp_info(union wtap_pseudo_header *pseudo_header,
                          packet_direction_t direction)
 {
     /* Set direction. */
@@ -1327,15 +1408,14 @@ static void set_ppp_info(union wtap_pseudo_header *pseudo_header,
 /********************************************************/
 /* Return hex nibble equivalent of hex string character */
 /********************************************************/
-guchar hex_from_char(gchar c)
+static guint8
+hex_from_char(gchar c)
 {
-    if ((c >= '0') && (c <= '9'))
-    {
+    if ((c >= '0') && (c <= '9')) {
         return c - '0';
     }
 
-    if ((c >= 'a') && (c <= 'f'))
-    {
+    if ((c >= 'a') && (c <= 'f')) {
         return 0x0a + (c - 'a');
     }
 
@@ -1343,44 +1423,54 @@ guchar hex_from_char(gchar c)
     return 0xff;
 }
 
+/* Extract and return a byte value from 2 ascii hex chars, starting from the given pointer */
+static guint8
+hex_byte_from_chars(gchar *c)
+{
+    static guchar hex_char_array[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+                                         'a', 'b', 'c', 'd', 'e', 'f' };
+
+    /* Populate lookup table first time */
+    static guint8 tableValues[255][255];
+    static gint tableSet = FALSE;
+    if (!tableSet) {
+        gint i, j;
+        for (i=0; i < 16; i++) {
+            for (j=0; j < 16; j++) {
+                tableValues[hex_char_array[i]][hex_char_array[j]] = i*16 + j;
+            }
+        }
+
+        tableSet = TRUE;
+    }
+
+    /* Return value from quick table lookup */
+    return tableValues[(unsigned char)c[0]][(unsigned char)c[1]];
+}
+
+
 
 /********************************************************/
 /* Return character corresponding to hex nibble value   */
 /********************************************************/
-gchar char_from_hex(guchar hex)
+static gchar
+char_from_hex(guint8 hex)
 {
     static char hex_lookup[16] =
     { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
 
-    if (hex > 15)
-    {
+    if (hex > 15) {
         return '?';
     }
 
     return hex_lookup[hex];
 }
 
-/***************************************************/
-/* Equality function for file_externals hash table */
-/***************************************************/
-gint wth_equal(gconstpointer v, gconstpointer v2)
-{
-    return (v == v2);
-}
-
-/***********************************************/
-/* Hash function for file_externals hash table */
-/***********************************************/
-guint wth_hash_func(gconstpointer v)
-{
-    return (guint)(unsigned long)v;
-}
-
-
 /***********************************************/
 /* Equality test for packet prefix hash tables */
 /***********************************************/
-gint packet_offset_equal(gconstpointer v, gconstpointer v2)
+static gint
+packet_offset_equal(gconstpointer v, gconstpointer v2)
 {
     /* Dereferenced pointers must have same gint64 offset value */
     return (*(const gint64*)v == *(const gint64*)v2);
@@ -1390,7 +1480,8 @@ gint packet_offset_equal(gconstpointer v, gconstpointer v2)
 /********************************************/
 /* Hash function for packet-prefix hash table */
 /********************************************/
-guint packet_offset_hash_func(gconstpointer v)
+static guint
+packet_offset_hash_func(gconstpointer v)
 {
     /* Use low-order bits of git64 offset value */
     return (guint)(*(const gint64*)v);
@@ -1402,7 +1493,8 @@ guint packet_offset_hash_func(gconstpointer v)
 /* Set secs and usecs as output                                         */
 /* Return FALSE if no valid time can be read                            */
 /************************************************************************/
-gboolean get_file_time_stamp(time_t *secs, guint32 *usecs)
+static gboolean
+get_file_time_stamp(gchar *linebuff, time_t *secs, guint32 *usecs)
 {
     int n;
     struct tm tm;
@@ -1413,15 +1505,13 @@ gboolean get_file_time_stamp(time_t *secs, guint32 *usecs)
     int scan_found;
 
     /* If line longer than expected, file is probably not correctly formatted */
-    if (strlen(linebuff) > MAX_TIMESTAMP_LINE_LENGTH)
-    {
+    if (strlen(linebuff) > MAX_TIMESTAMP_LINE_LENGTH) {
         return FALSE;
     }
 
     /**************************************************************/
     /* First is month. Read until get a space following the month */
-    for (n=0; (linebuff[n] != ' ') && (n < MAX_MONTH_LETTERS); n++)
-    {
+    for (n=0; (linebuff[n] != ' ') && (n < MAX_MONTH_LETTERS); n++) {
         month[n] = linebuff[n];
     }
     month[n] = '\0';
@@ -1438,8 +1528,7 @@ gboolean get_file_time_stamp(time_t *secs, guint32 *usecs)
     else if (strcmp(month, "October"  ) == 0)  tm.tm_mon = 9;
     else if (strcmp(month, "November" ) == 0)  tm.tm_mon = 10;
     else if (strcmp(month, "December" ) == 0)  tm.tm_mon = 11;
-    else
-    {
+    else {
         /* Give up if not found a properly-formatted date */
         return FALSE;
     }
@@ -1448,10 +1537,9 @@ gboolean get_file_time_stamp(time_t *secs, guint32 *usecs)
 
     /********************************************************/
     /* Scan for remaining numerical fields                  */
-    scan_found = sscanf(linebuff+n, "%d, %d     %d:%d:%d.%u",
+    scan_found = sscanf(linebuff+n, "%2d, %4d     %2d:%2d:%2d.%4u",
                         &day, &year, &hour, &minute, &second, usecs);
-    if (scan_found != 6)
-    {
+    if (scan_found != 6) {
         /* Give up if not all found */
         return FALSE;
     }
@@ -1475,7 +1563,8 @@ gboolean get_file_time_stamp(time_t *secs, guint32 *usecs)
 }
 
 /* Free the data allocated inside a line_prefix_info_t */
-gboolean free_line_prefix_info(gpointer key, gpointer value,
+static gboolean
+free_line_prefix_info(gpointer key, gpointer value,
                                gpointer user_data _U_)
 {
     line_prefix_info_t *info = (line_prefix_info_t*)value;
@@ -1485,8 +1574,7 @@ gboolean free_line_prefix_info(gpointer key, gpointer value,
 
     /* Free the strings inside */
     g_free(info->before_time);
-    if (info->after_time)
-    {
+    if (info->after_time) {
         g_free(info->after_time);
     }