Another "this is < WTAP_MAX_PACKET_SIZE so no checks are needed" note.
[metze/wireshark/wip.git] / wiretap / catapult_dct2000.c
index 3e492d6a43ded40f47ed0de290df970d86e1ac33..093cd6b9d22a5d0534ea332f395aab2915583df1 100644 (file)
@@ -1,6 +1,4 @@
 /* catapult_dct2000.c
- *
- * $Id$
  *
  * Wiretap Library
  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#ifdef HAVE_CONFIG_H
 #include "config.h"
-#endif
 #include <errno.h>
 #include <string.h>
 #include <stdlib.h>
-#include <ctype.h>
 
 #include "wtap-int.h"
 #include "file_wrappers.h"
-#include "buffer.h"
 
 #include "catapult_dct2000.h"
 
@@ -110,45 +104,49 @@ static const gchar catapult_dct2000_magic[] = "Session Transcript";
 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,
-                                           int *err, gchar **err_info);
+                                           struct wtap_pkthdr *phdr,
+                                           Buffer *buf, 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);
+                                      const guint8 *pd, int *err, gchar **err_info);
 
 
 /************************************************************/
 /* Private helper functions                                 */
 static gboolean read_new_line(FILE_T fh, gint64 *offset, gint *length,
-                              gchar *buf, size_t bufsize);
+                              gchar *buf, size_t bufsize, int *err,
+                              gchar **err_info);
 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, int *is_comment,
+                           int *encap, int *is_comment, int *is_sprint,
                            gchar *aal_header_chars,
                            gchar *context_name, guint8 *context_portp,
                            gchar *protocol_name, gchar *variant_name,
                            gchar *outhdr_name);
-static int write_stub_header(guchar *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 guchar hex_from_char(gchar c);
-static gchar char_from_hex(guchar 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,
-                                   gchar *aal_header_chars);
+static gboolean process_parsed_line(wtap *wth,
+                                    dct2000_file_externals_t *file_externals,
+                                    struct wtap_pkthdr *phdr,
+                                    Buffer *buf, gint64 file_offset,
+                                    char *linebuff, long dollar_offset,
+                                    int seconds, int useconds,
+                                    gchar *timestamp_string,
+                                    packet_direction_t direction, int encap,
+                                    gchar *context_name, guint8 context_port,
+                                    gchar *protocol_name, gchar *variant_name,
+                                    gchar *outhdr_name, gchar *aal_header_chars,
+                                    gboolean is_comment, int data_chars,
+                                    int *err, gchar **err_info);
+static guint8 hex_from_char(gchar c);
+static void   prepare_hex_byte_from_chars_table(void);
+static guint8 hex_byte_from_chars(gchar *c);
+static gchar char_from_hex(guint8 hex);
+
 static void set_aal_info(union wtap_pseudo_header *pseudo_header,
                          packet_direction_t direction,
                          gchar *aal_header_chars);
@@ -168,14 +166,16 @@ static gboolean free_line_prefix_info(gpointer key, gpointer value, gpointer use
 /********************************************/
 /* Open file (for reading)                 */
 /********************************************/
-int catapult_dct2000_open(wtap *wth, int *err, gchar **err_info _U_)
+wtap_open_return_val
+catapult_dct2000_open(wtap *wth, int *err, gchar **err_info)
 {
     gint64  offset = 0;
     time_t  timestamp;
     guint32 usecs;
     gint firstline_length = 0;
     dct2000_file_externals_t *file_externals;
-    gchar linebuff[MAX_LINE_LENGTH];
+    static gchar linebuff[MAX_LINE_LENGTH];
+    static gboolean hex_byte_table_values_set = FALSE;
 
     /* Clear errno before reading from the file */
     errno = 0;
@@ -184,25 +184,34 @@ int catapult_dct2000_open(wtap *wth, int *err, gchar **err_info _U_)
     /********************************************************************/
     /* First line needs to contain at least as many characters as magic */
 
-    read_new_line(wth->fh, &offset, &firstline_length, linebuff,
-                  sizeof linebuff);
+    if (!read_new_line(wth->fh, &offset, &firstline_length, linebuff,
+                       sizeof linebuff, err, err_info)) {
+        if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
+            return WTAP_OPEN_ERROR;
+        return WTAP_OPEN_NOT_MINE;
+    }
     if (((size_t)firstline_length < strlen(catapult_dct2000_magic)) ||
         firstline_length >= MAX_FIRST_LINE_LENGTH) {
 
-        return 0;
+        return WTAP_OPEN_NOT_MINE;
     }
 
     /* This file is not for us if it doesn't match our signature */
     if (memcmp(catapult_dct2000_magic, linebuff, strlen(catapult_dct2000_magic)) != 0) {
-        return 0;
+        return WTAP_OPEN_NOT_MINE;
     }
 
+    /* Make sure table is ready for use */
+    if (!hex_byte_table_values_set) {
+        prepare_hex_byte_from_chars_table();
+        hex_byte_table_values_set = TRUE;
+    }
 
     /*********************************************************************/
     /* Need entry in file_externals table                                */
 
     /* Allocate a new file_externals structure for this file */
-    file_externals = g_malloc(sizeof(dct2000_file_externals_t));
+    file_externals = g_new(dct2000_file_externals_t,1);
     memset((void*)file_externals, '\0', sizeof(dct2000_file_externals_t));
 
     /* Copy this first line into buffer so could write out later */
@@ -214,14 +223,19 @@ int catapult_dct2000_open(wtap *wth, int *err, gchar **err_info _U_)
     /* Second line contains file timestamp                     */
     /* Store this offset in in file_externals                  */
 
-    read_new_line(wth->fh, &offset, &(file_externals->secondline_length),
-                  linebuff, sizeof linebuff);
+    if (!read_new_line(wth->fh, &offset, &(file_externals->secondline_length),
+                       linebuff, sizeof linebuff, err, err_info)) {
+        g_free(file_externals);
+        if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
+            return WTAP_OPEN_ERROR;
+        return WTAP_OPEN_NOT_MINE;
+    }
     if ((file_externals->secondline_length >= MAX_TIMESTAMP_LINE_LENGTH) ||
         (!get_file_time_stamp(linebuff, &timestamp, &usecs))) {
 
         /* Give up if file time line wasn't valid */
         g_free(file_externals);
-        return 0;
+        return WTAP_OPEN_NOT_MINE;
     }
 
     /* Fill in timestamp */
@@ -236,7 +250,7 @@ int catapult_dct2000_open(wtap *wth, int *err, gchar **err_info _U_)
     /* File is for us. Fill in details so packets can be read   */
 
     /* Set our file type */
-    wth->file_type = WTAP_FILE_CATAPULT_DCT2000;
+    wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_CATAPULT_DCT2000;
 
     /* Use our own encapsulation to send all packets to our stub dissector */
     wth->file_encap = WTAP_ENCAP_CATAPULT_DCT2000;
@@ -247,7 +261,7 @@ int catapult_dct2000_open(wtap *wth, int *err, gchar **err_info _U_)
     wth->subtype_close = catapult_dct2000_close;
 
     /* Choose microseconds (have 4 decimal places...) */
-    wth->tsprecision = WTAP_FILE_TSPREC_USEC;
+    wth->file_tsprec = WTAP_TSPREC_USEC;
 
 
     /***************************************************************/
@@ -259,19 +273,71 @@ int catapult_dct2000_open(wtap *wth, int *err, gchar **err_info _U_)
     wth->priv = (void*)file_externals;
 
     *err = errno;
-    return 1;
+    return WTAP_OPEN_MINE;
 }
 
+/* Ugly, but much faster than using g_snprintf! */
+static void write_timestamp_string(char *timestamp_string, int secs, int tenthousandths)
+{
+    int idx = 0;
+
+    /* Secs */
+    if (secs < 10) {
+        timestamp_string[idx++] = ((secs % 10))         + '0';
+    }
+    else if (secs < 100) {
+        timestamp_string[idx++] = ( secs  /       10)   + '0';
+        timestamp_string[idx++] = ((secs % 10))          + '0';
+    }
+    else if (secs < 1000) {
+        timestamp_string[idx++] = ((secs)         / 100)   + '0';
+        timestamp_string[idx++] = ((secs % 100))  / 10     + '0';
+        timestamp_string[idx++] = ((secs % 10))            + '0';
+    }
+    else if (secs < 10000) {
+        timestamp_string[idx++] = ((secs)          / 1000)   + '0';
+        timestamp_string[idx++] = ((secs % 1000))  / 100     + '0';
+        timestamp_string[idx++] = ((secs % 100))   / 10      + '0';
+        timestamp_string[idx++] = ((secs % 10))              + '0';
+    }
+    else if (secs < 100000) {
+        timestamp_string[idx++] = ((secs)          / 10000)   + '0';
+        timestamp_string[idx++] = ((secs % 10000)) / 1000     + '0';
+        timestamp_string[idx++] = ((secs % 1000))  / 100      + '0';
+        timestamp_string[idx++] = ((secs % 100))   / 10       + '0';
+        timestamp_string[idx++] = ((secs % 10))               + '0';
+    }
+    else if (secs < 1000000) {
+        timestamp_string[idx++] = ((secs)           / 100000) + '0';
+        timestamp_string[idx++] = ((secs % 100000)) / 10000   + '0';
+        timestamp_string[idx++] = ((secs % 10000))  / 1000    + '0';
+        timestamp_string[idx++] = ((secs % 1000))   / 100     + '0';
+        timestamp_string[idx++] = ((secs % 100))    / 10      + '0';
+        timestamp_string[idx++] = ((secs % 10))               + '0';
+    }
+    else {
+        g_snprintf(timestamp_string, MAX_TIMESTAMP_LEN, "%d.%04d", secs, tenthousandths);
+        return;
+    }
+
+    timestamp_string[idx++] = '.';
+    timestamp_string[idx++] = ( tenthousandths          / 1000) + '0';
+    timestamp_string[idx++] = ((tenthousandths % 1000)  / 100)  + '0';
+    timestamp_string[idx++] = ((tenthousandths % 100)   / 10)   + '0';
+    timestamp_string[idx++] = ((tenthousandths % 10))           + '0';
+    timestamp_string[idx++] = '\0';
+}
 
 /**************************************************/
 /* 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_,
-                               gint64 *data_offset)
+static gboolean
+catapult_dct2000_read(wtap *wth, int *err, gchar **err_info,
+                      gint64 *data_offset)
 {
-    gint64 offset = wth->data_offset;
+    gint64 offset = file_tell(wth->fh);
     long dollar_offset, before_time_offset, after_time_offset;
     packet_direction_t direction;
     int encap;
@@ -280,37 +346,32 @@ gboolean catapult_dct2000_read(wtap *wth, int *err, gchar **err_info _U_,
     dct2000_file_externals_t *file_externals =
         (dct2000_file_externals_t*)wth->priv;
 
-    /* There *has* to be an entry for this wth */
-    if (!file_externals) {
-        return FALSE;
-    }
-
     /* Search for a line containing a usable packet */
     while (1) {
         int line_length, seconds, useconds, data_chars;
         int is_comment = FALSE;
+        int is_sprint = FALSE;
         gint64 this_offset = offset;
-        gchar linebuff[MAX_LINE_LENGTH+1];
+        static gchar linebuff[MAX_LINE_LENGTH+1];
         gchar aal_header_chars[AAL_HEADER_CHARS];
         gchar context_name[MAX_CONTEXT_NAME];
-        guint8 context_port;
+        guint8 context_port = 0;
         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 (file_tell(wth->fh) == 0) {
             this_offset += (file_externals->firstline_length+1+
                             file_externals->secondline_length+1);
         }
 
-        /* Clear errno before reading from the file */
-        errno = 0;
-
         /* Read a new line from file into linebuff */
-        if (read_new_line(wth->fh, &offset, &line_length, linebuff,
-                          sizeof linebuff) == FALSE) {
-            /* Get out if no more lines can be read */
+        if (!read_new_line(wth->fh, &offset, &line_length, linebuff,
+                           sizeof linebuff, err, err_info)) {
+            if (*err != 0)
+                return FALSE;  /* error */
+            /* No more lines can be read, so quit. */
             break;
         }
 
@@ -318,89 +379,42 @@ gboolean catapult_dct2000_read(wtap *wth, int *err, gchar **err_info _U_,
         if (parse_line(linebuff, line_length, &seconds, &useconds,
                        &before_time_offset, &after_time_offset,
                        &dollar_offset,
-                       &data_chars, &direction, &encap, &is_comment,
+                       &data_chars, &direction, &encap, &is_comment, &is_sprint,
                        aal_header_chars,
                        context_name, &context_port,
                        protocol_name, variant_name, outhdr_name)) {
-            guchar *frame_buffer;
-            int n;
-            int stub_offset = 0;
             line_prefix_info_t *line_prefix_info;
             char timestamp_string[MAX_TIMESTAMP_LEN+1];
             gint64 *pkey = NULL;
 
-            g_snprintf(timestamp_string, MAX_TIMESTAMP_LEN, "%d.%04d", seconds, useconds/100);
-
-            /* All packets go to Catapult DCT2000 stub dissector */
-            wth->phdr.pkt_encap = WTAP_ENCAP_CATAPULT_DCT2000;
+            write_timestamp_string(timestamp_string, seconds, useconds/100);
 
             /* Set data_offset to the beginning of the line we're returning.
                This will be the seek_off parameter when this frame is re-read.
             */
             *data_offset = this_offset;
 
-            /* This is the position in the file where the next _read() will be called from */
-            wth->data_offset = this_offset + line_length + 1;
-
-            /* Fill in timestamp (capture base + packet offset) */
-            wth->phdr.ts.secs = file_externals->start_secs + seconds;
-            if ((file_externals->start_usecs + useconds) >= 1000000) {
-                wth->phdr.ts.secs++;
-            }
-            wth->phdr.ts.nsecs =
-                ((file_externals->start_usecs + useconds) % 1000000) *1000;
-
-            /* Get buffer pointer ready */
-            buffer_assure_space(wth->frame_buffer,
-                                strlen(context_name)+1 +     /* Context name */
-                                1 +                          /* port */
-                                strlen(timestamp_string)+1 + /* timestamp */
-                                strlen(variant_name)+1 +     /* variant */
-                                strlen(outhdr_name)+1 +      /* outhdr */
-                                strlen(protocol_name)+1 +    /* Protocol name */
-                                1 +                          /* direction */
-                                1 +                          /* encap */
-                                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, context_name,
-                                            context_port,
-                                            protocol_name, variant_name,
-                                            outhdr_name);
-
-            /* Binary data length is half bytestring length + stub header */
-            wth->phdr.len = stub_offset + (is_comment ? data_chars : (data_chars/2));
-            wth->phdr.caplen = stub_offset + (is_comment ? data_chars : (data_chars/2));
-
-
-            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_from_char(linebuff[dollar_offset+n]) << 4) |
-                         hex_from_char(linebuff[dollar_offset+n+1]);
-                }
-            }
-            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];
-                }
-            }
+            if (!process_parsed_line(wth, file_externals,
+                                     &wth->phdr,
+                                     wth->frame_buffer, this_offset,
+                                     linebuff, dollar_offset,
+                                     seconds, useconds,
+                                     timestamp_string,
+                                     direction, encap,
+                                     context_name, context_port,
+                                     protocol_name, variant_name,
+                                     outhdr_name, aal_header_chars,
+                                     is_comment, data_chars,
+                                     err, err_info))
+                return FALSE;
 
             /* Store the packet prefix in the hash table */
-            line_prefix_info = g_malloc(sizeof(line_prefix_info_t));
+            line_prefix_info = g_new(line_prefix_info_t,1);
 
             /* Create and use buffer for contents before time */
-            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';
+            line_prefix_info->before_time = (gchar *)g_malloc(before_time_offset+1);
+            memcpy(line_prefix_info->before_time, linebuff, before_time_offset);
+            line_prefix_info->before_time[before_time_offset] = '\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
@@ -412,29 +426,22 @@ gboolean catapult_dct2000_read(wtap *wth, int *err, gchar **err_info _U_,
             }
             else {
                 /* Allocate & write buffer for line between timestamp and data */
-                line_prefix_info->after_time = g_malloc(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 = (gchar *)g_malloc(dollar_offset - after_time_offset);
+                memcpy(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 = (gint64 *)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, aal_header_chars);
-
             /* OK, we have packet details to return */
-            *err = errno;
             return TRUE;
         }
     }
 
     /* No packet details to return... */
-    *err = errno;
     return FALSE;
 }
 
@@ -444,23 +451,29 @@ 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,
-                           int length, int *err, gchar **err_info)
+                           struct wtap_pkthdr *phdr, Buffer *buf,
+                           int *err, gchar **err_info)
 {
-    gint64 offset = wth->data_offset;
+    gint64 offset = 0;
+    int length;
     long dollar_offset, before_time_offset, after_time_offset;
-    gchar linebuff[MAX_LINE_LENGTH+1];
+    static gchar linebuff[MAX_LINE_LENGTH+1];
     gchar aal_header_chars[AAL_HEADER_CHARS];
     gchar context_name[MAX_CONTEXT_NAME];
-    guint8 context_port;
+    guint8 context_port = 0;
     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;
+    int  is_sprint = FALSE;
     packet_direction_t direction;
     int encap;
     int seconds, useconds, data_chars;
 
+    /* Get wtap external structure for this wtap */
+    dct2000_file_externals_t *file_externals =
+        (dct2000_file_externals_t*)wth->priv;
+
     /* Reset errno */
     *err = errno = 0;
 
@@ -470,8 +483,8 @@ catapult_dct2000_seek_read(wtap *wth, gint64 seek_off,
     }
 
     /* Re-read whole line (this really should succeed) */
-    if (read_new_line(wth->random_fh, &offset, &length, linebuff,
-                      sizeof linebuff) == FALSE) {
+    if (!read_new_line(wth->random_fh, &offset, &length, linebuff,
+                      sizeof linebuff, err, err_info)) {
         return FALSE;
     }
 
@@ -479,47 +492,26 @@ catapult_dct2000_seek_read(wtap *wth, gint64 seek_off,
     if (parse_line(linebuff, length, &seconds, &useconds,
                    &before_time_offset, &after_time_offset,
                    &dollar_offset,
-                   &data_chars, &direction, &encap, &is_comment,
+                   &data_chars, &direction, &encap, &is_comment, &is_sprint,
                    aal_header_chars,
                    context_name, &context_port,
                    protocol_name, variant_name, outhdr_name)) {
-        int n;
-        int stub_offset = 0;
         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;
-
 
-        /*********************/
-        /* Write stub header */
-        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_from_char(linebuff[dollar_offset+n]) << 4) |
-                                         hex_from_char(linebuff[dollar_offset+n+1]);
-            }
-        }
-        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,
-                               aal_header_chars);
+        write_timestamp_string(timestamp_string, seconds, useconds/100);
+
+        if (!process_parsed_line(wth, file_externals,
+                                 phdr, buf, seek_off,
+                                 linebuff, dollar_offset,
+                                 seconds, useconds,
+                                 timestamp_string,
+                                 direction, encap,
+                                 context_name, context_port,
+                                 protocol_name, variant_name,
+                                 outhdr_name, aal_header_chars,
+                                 is_comment, data_chars,
+                                 err, err_info))
+            return FALSE;
 
         *err = errno = 0;
         return TRUE;
@@ -537,17 +529,13 @@ catapult_dct2000_seek_read(wtap *wth, gint64 seek_off,
 /***************************************************************************/
 /* Free dct2000-specific capture info from file that was open for reading  */
 /***************************************************************************/
-void catapult_dct2000_close(wtap *wth)
+static void
+catapult_dct2000_close(wtap *wth)
 {
     /* Get externals for this file */
     dct2000_file_externals_t *file_externals =
         (dct2000_file_externals_t*)wth->priv;
 
-    /* The entry *has* to be found */
-    if (!file_externals) {
-        return;
-    }
-
     /* Free up its line prefix values */
     g_hash_table_foreach_remove(file_externals->packet_prefix_table,
                                 free_line_prefix_info, NULL);
@@ -563,15 +551,16 @@ void catapult_dct2000_close(wtap *wth)
 /***************************/
 
 typedef struct {
-    gboolean           first_packet_written;
-    struct wtap_nstime start_time;
+    gboolean   first_packet_written;
+    nstime_t   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;
@@ -583,7 +572,8 @@ 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) {
         case WTAP_ENCAP_CATAPULT_DCT2000:
@@ -592,7 +582,7 @@ int catapult_dct2000_dump_can_write_encap(int encap)
 
         default:
             /* But don't write to any other formats... */
-            return WTAP_ERR_UNSUPPORTED_ENCAP;
+            return WTAP_ERR_UNWRITABLE_ENCAP;
     }
 }
 
@@ -601,15 +591,19 @@ 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,
-                               const union wtap_pseudo_header *pseudo_header,
-                               const guchar *pd, int *err)
+static gboolean
+catapult_dct2000_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
+                      const guint8 *pd, int *err, gchar **err_info _U_)
 {
+    const union wtap_pseudo_header *pseudo_header = &phdr->pseudo_header;
     guint32 n;
     line_prefix_info_t *prefix = NULL;
     gchar time_string[16];
     gboolean is_comment;
+    gboolean is_sprint = FALSE;
     dct2000_dump_t *dct2000;
+    int consecutive_slashes=0;
+    char *p_c;
 
     /******************************************************/
     /* Get the file_externals structure for this file */
@@ -617,6 +611,12 @@ gboolean catapult_dct2000_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
     dct2000_file_externals_t *file_externals =
         (dct2000_file_externals_t*)pseudo_header->dct2000.wth->priv;
 
+    /* We can only write packet records. */
+    if (phdr->rec_type != REC_TYPE_PACKET) {
+        *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
+        return FALSE;
+    }
+
     dct2000 = (dct2000_dump_t *)wdh->priv;
     if (dct2000 == NULL) {
 
@@ -649,7 +649,7 @@ gboolean catapult_dct2000_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
         dct2000->start_time.nsecs =
             (file_externals->start_usecs * 1000);
 
-        /* Set flag do don't write header out again */
+        /* Set flag so don't write header out again */
         dct2000->first_packet_written = TRUE;
     }
 
@@ -668,18 +668,27 @@ gboolean catapult_dct2000_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
     }
 
     /* Can infer from prefix if this is a comment (whose payload is displayed differently) */
-    is_comment = (strstr(prefix->before_time, "/////") != NULL);
+    /* This is much faster than strstr() for "/////" */
+    p_c = prefix->before_time;
+    while (p_c && (*p_c != '/')) {
+        p_c++;
+    }
+    while (p_c && (*p_c == '/')) {
+        consecutive_slashes++;
+        p_c++;
+    }
+    is_comment = (consecutive_slashes == 5);
 
     /* Calculate time of this packet to write, relative to start of dump */
     if (phdr->ts.nsecs >= dct2000->start_time.nsecs) {
-        g_snprintf(time_string, 16, "%ld.%04d",
-                  (long)(phdr->ts.secs - dct2000->start_time.secs),
-                  (phdr->ts.nsecs - dct2000->start_time.nsecs) / 100000);
+        write_timestamp_string(time_string,
+                               (int)(phdr->ts.secs - dct2000->start_time.secs),
+                               (phdr->ts.nsecs - dct2000->start_time.nsecs) / 100000);
     }
     else {
-        g_snprintf(time_string, 16, "%ld.%04u",
-                  (long)(phdr->ts.secs - dct2000->start_time.secs-1),
-                  ((1000000000 + (phdr->ts.nsecs / 100000)) - (dct2000->start_time.nsecs / 100000)) % 10000);
+        write_timestamp_string(time_string,
+                               (int)(phdr->ts.secs - dct2000->start_time.secs-1),
+                               ((1000000000 + (phdr->ts.nsecs / 100000)) - (dct2000->start_time.nsecs / 100000)) % 10000);
     }
 
     /* Write out the calculated timestamp */
@@ -716,6 +725,9 @@ gboolean catapult_dct2000_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
     n++;
 
     /* Protocol name */
+    if (is_comment) {
+        is_sprint = (strcmp((const char *)pd+n, "sprint") == 0);
+    }
     for (; pd[n] != '\0'; n++);
     n++;
 
@@ -733,16 +745,16 @@ gboolean catapult_dct2000_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
 
     /**************************************/
     /* Remainder is encapsulated protocol */
-    if (!wtap_dump_file_write(wdh, "$", 1, err)) {
+    if (!wtap_dump_file_write(wdh, is_sprint ? " " : "$", 1, err)) {
         return FALSE;
     }
 
     if (!is_comment) {
-        /* Each binary byte is written out as 2 hex string chars */ 
+        /* 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));
+            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 */
             if (!wtap_dump_file_write(wdh, c, 2, err)) {
@@ -781,24 +793,30 @@ gboolean catapult_dct2000_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
 /* - 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,
-                       gchar *linebuff, size_t linebuffsize)
+static gboolean
+read_new_line(FILE_T fh, gint64 *offset, gint *length,
+              gchar *linebuff, size_t linebuffsize, int *err, gchar **err_info)
 {
-    char *result;
-
     /* Read in a line */
-    result = file_gets(linebuff, (int)linebuffsize - 1, fh);
-    if (result == NULL) {
+    gint64 pos_before = file_tell(fh);
+
+    if (file_gets(linebuff, (int)linebuffsize - 1, fh) == NULL) {
         /* No characters found, or error */
+        *err = file_error(fh, err_info);
         return FALSE;
     }
 
-    /* Set length and offset.. */
-    *length = (gint)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 (*length > 0 && linebuff[*length-1] == '\n') {
+        linebuff[*length-1] = '\0';
+        *length = *length - 1;
+    }
+    /* Nor do we want '\r' (as will be written when log is created on windows) */
+    if (*length > 0 && linebuff[*length-1] == '\r') {
         linebuff[*length-1] = '\0';
         *length = *length - 1;
     }
@@ -814,16 +832,17 @@ 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        */
 /**********************************************************************/
-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)
+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, int *is_sprint,
+           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;
@@ -841,9 +860,10 @@ static gboolean parse_line(gchar *linebuff, gint line_length,
     gboolean atm_header_present = FALSE;
 
     *is_comment = FALSE;
+    *is_sprint = FALSE;
 
     /* Read context name until find '.' */
-    for (n=0; (linebuff[n] != '.') && (n < MAX_CONTEXT_NAME) && (n+1 < line_length); n++) {
+    for (n=0; (n < MAX_CONTEXT_NAME) && (n+1 < line_length) && (linebuff[n] != '.'); n++) {
         if (linebuff[n] == '/') {
             context_name[n] = '\0';
 
@@ -853,11 +873,11 @@ static gboolean parse_line(gchar *linebuff, gint line_length,
             }
 
             /* There is no variant, outhdr, etc.  Set protocol to be a comment */
-            g_snprintf(protocol_name, MAX_PROTOCOL_NAME, "comment");
+            g_strlcpy(protocol_name, "comment", MAX_PROTOCOL_NAME);
             *is_comment = TRUE;
             break;
         }
-        if (!isalnum((guchar)linebuff[n]) && (linebuff[n] != '_') && (linebuff[n] != '-')) {
+        if (!g_ascii_isalnum(linebuff[n]) && (linebuff[n] != '_') && (linebuff[n] != '-')) {
             return FALSE;
         }
         context_name[n] = linebuff[n];
@@ -866,10 +886,10 @@ static gboolean parse_line(gchar *linebuff, gint line_length,
         return FALSE;
     }
 
-    /* Reset strings (that won't be set be comments) */
-    g_strlcpy(variant_name, "0", MAX_VARIANT_DIGITS);
-    g_strlcpy(outhdr_name, "", MAX_OUTHDR_NAME);
-    g_strlcpy(port_number_string, "0", MAX_PORT_DIGITS);
+    /* Reset strings (that won't be set by comments) */
+    variant_name[0] = '\0';
+    outhdr_name[0] = '\0';
+    port_number_string[0] = '\0';
 
     if (!(*is_comment)) {
         /* '.' must follow context name */
@@ -885,7 +905,7 @@ static gboolean parse_line(gchar *linebuff, gint line_length,
              (linebuff[n] != '/') && (port_digits <= MAX_PORT_DIGITS) && (n+1 < line_length);
              n++, port_digits++) {
 
-            if (!isdigit((guchar)linebuff[n])) {
+            if (!g_ascii_isdigit(linebuff[n])) {
                 return FALSE;
             }
             port_number_string[port_digits] = linebuff[n];
@@ -900,7 +920,12 @@ static gboolean parse_line(gchar *linebuff, gint line_length,
             return FALSE;
         }
         port_number_string[port_digits] = '\0';
-        *context_portp = atoi(port_number_string);
+        if (port_digits == 1) {
+            *context_portp = port_number_string[0] - '0';
+        }
+        else {
+            *context_portp = atoi(port_number_string);
+        }
         /* Skip it */
         n++;
 
@@ -909,7 +934,7 @@ static gboolean parse_line(gchar *linebuff, gint line_length,
              (linebuff[n] != '/') && (protocol_chars < MAX_PROTOCOL_NAME) && (n < line_length);
              n++, protocol_chars++) {
 
-            if (!isalnum((guchar)linebuff[n]) && linebuff[n] != '_') {
+            if (!g_ascii_isalnum(linebuff[n]) && linebuff[n] != '_') {
                 return FALSE;
             }
             protocol_name[protocol_chars] = linebuff[n];
@@ -930,10 +955,10 @@ static gboolean parse_line(gchar *linebuff, gint line_length,
 
         /* 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);
+             (g_ascii_isdigit(linebuff[n])) && (variant_digits <= MAX_VARIANT_DIGITS) && (n+1 < line_length);
              n++, variant_digits++) {
 
-            if (!isdigit((guchar)linebuff[n])) {
+            if (!g_ascii_isdigit(linebuff[n])) {
                 return FALSE;
             }
             variant_name[variant_digits] = linebuff[n];
@@ -941,12 +966,19 @@ static gboolean parse_line(gchar *linebuff, gint line_length,
         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);
+            if (variant_digits == 1) {
+                variant = variant_name[0] - '0';
+            }
+            else {
+                variant = atoi(variant_name);
+            }
         }
         else {
-            g_strlcpy(variant_name, "1", MAX_VARIANT_DIGITS+1);
+            variant_name[0] = '1';
+            variant_name[1] = '\0';
         }
 
 
@@ -957,11 +989,11 @@ static gboolean parse_line(gchar *linebuff, gint line_length,
             n++;
 
             for (outhdr_chars = 0;
-                 (isdigit((guchar)linebuff[n]) || linebuff[n] == ',') &&
+                 (g_ascii_isdigit(linebuff[n]) || linebuff[n] == ',') &&
                  (outhdr_chars <= MAX_OUTHDR_NAME) && (n+1 < line_length);
                  n++, outhdr_chars++) {
 
-                if (!isdigit((guchar)linebuff[n]) && (linebuff[n] != ',')) {
+                if (!g_ascii_isdigit(linebuff[n]) && (linebuff[n] != ',')) {
                     return FALSE;
                 }
                 outhdr_name[outhdr_chars] = linebuff[n];
@@ -990,10 +1022,7 @@ static gboolean parse_line(gchar *linebuff, gint line_length,
 
     /* FP may be carried over ATM, which has separate atm header to parse */
     if ((strcmp(protocol_name, "fp") == 0) ||
-        (strcmp(protocol_name, "fp_r4") == 0) ||
-        (strcmp(protocol_name, "fp_r5") == 0) ||
-        (strcmp(protocol_name, "fp_r6") == 0) ||
-        (strcmp(protocol_name, "fp_r7") == 0)) {
+        (strncmp(protocol_name, "fp_r", 4) == 0)) {
 
         if ((variant > 256) && (variant % 256 == 3)) {
             /* FP over udp is contained in IPPrim... */
@@ -1011,7 +1040,6 @@ static gboolean parse_line(gchar *linebuff, gint line_length,
         atm_header_present = TRUE;
     }
 
-
     else
     if (strcmp(protocol_name, "ppp") == 0) {
         *encap = WTAP_ENCAP_PPP;
@@ -1073,14 +1101,14 @@ static gboolean parse_line(gchar *linebuff, gint line_length,
 
         /* Read consecutive hex chars into atm header buffer */
         for (;
-             ((linebuff[n] >= '0') && (linebuff[n] <= '?') &&
-              (n < line_length) &&
+             ((n < line_length) &&
+              (linebuff[n] >= '0') && (linebuff[n] <= '?') &&
               (header_chars_seen < AAL_HEADER_CHARS));
              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])) {
+            if (!g_ascii_isdigit(linebuff[n])) {
                 aal_header_chars[header_chars_seen] = 'a' + (linebuff[n] - '9') -1;
             }
         }
@@ -1090,14 +1118,28 @@ static gboolean parse_line(gchar *linebuff, gint line_length,
         }
     }
 
-    /* Scan ahead to the next space */
-    for (; (linebuff[n] != ' ') && (n+1 < line_length); n++);
-    if (n+1 >= line_length) {
-        return FALSE;
-    }
-    /* Skip it */
+    /* 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 (g_ascii_isdigit(linebuff[n])) {
+        while ((n+1 < line_length) && linebuff[n] != '/') {
+            n++;
+        }
+    }
+
+    /* Skip '/' */
+    while ((n+1 < line_length) && linebuff[n] == '/') {
+        n++;
+    }
+
+    /* Skip a space that may happen here */
+    if ((n+1 < line_length) && linebuff[n] == ' ') {
+        n++;
+    }
+
     /* Next character gives direction of message (must be 's' or 'r') */
     if (!(*is_comment)) {
         if (linebuff[n] == 's') {
@@ -1129,7 +1171,7 @@ static gboolean parse_line(gchar *linebuff, gint line_length,
         return FALSE;
     }
 
-    for (; !isdigit((guchar)linebuff[n]) && (n < line_length); n++);
+    for (; (n < line_length) && !g_ascii_isdigit(linebuff[n]); n++);
     if (n >= line_length) {
         return FALSE;
     }
@@ -1143,7 +1185,7 @@ static gboolean parse_line(gchar *linebuff, gint line_length,
          (n < line_length);
          n++, seconds_chars++) {
 
-        if (!isdigit((guchar)linebuff[n])) {
+        if (!g_ascii_isdigit(linebuff[n])) {
             /* Found a non-digit before decimal point. Fail */
             return FALSE;
         }
@@ -1172,7 +1214,7 @@ static gboolean parse_line(gchar *linebuff, gint line_length,
          (n < line_length);
          n++, subsecond_decimals_chars++) {
 
-        if (!isdigit((guchar)linebuff[n])) {
+        if (!g_ascii_isdigit(linebuff[n])) {
             return FALSE;
         }
         subsecond_decimals_buff[subsecond_decimals_chars] = linebuff[n];
@@ -1190,16 +1232,26 @@ static gboolean parse_line(gchar *linebuff, gint line_length,
         return FALSE;
     }
 
-    *after_time_offset = n;
+    *after_time_offset = n++;
 
-    /* Now skip ahead to find start of data (marked by '$') */
-    /* 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;
+    /* If we have a string message, it could either be a comment (with '$') or
+       a sprint line (no '$') */
+    if (*is_comment) {
+        if (strncmp(linebuff+n, "l $", 3) != 0) {
+            *is_sprint = TRUE;
+            g_strlcpy(protocol_name, "sprint", MAX_PROTOCOL_NAME);
+        }
+    }
+
+    if (!(*is_sprint)) {
+        /* Now skip ahead to find start of data (marked by '$') */
+        for (; (linebuff[n] != '$') && (linebuff[n] != '\'') && (n+1 < line_length); n++);
+        if ((linebuff[n] == '\'') || (n+1 >= line_length)) {
+            return FALSE;
+        }
+        /* Skip it */
+        n++;
     }
-    /* Skip it */
-    n++;
 
     /* Set offset to data start within line */
     *data_offset = n;
@@ -1216,39 +1268,98 @@ static gboolean parse_line(gchar *linebuff, gint line_length,
     return TRUE;
 }
 
-/*****************************************************************/
-/* Write the stub info to the data buffer while reading a packet */
-/*****************************************************************/
-static int write_stub_header(guchar *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)
+/***********************************/
+/* Process results of parse_line() */
+/***********************************/
+static gboolean
+process_parsed_line(wtap *wth, dct2000_file_externals_t *file_externals,
+                    struct wtap_pkthdr *phdr,
+                    Buffer *buf, gint64 file_offset,
+                    char *linebuff, long dollar_offset,
+                    int seconds, int useconds, gchar *timestamp_string,
+                    packet_direction_t direction, int encap,
+                    gchar *context_name, guint8 context_port,
+                    gchar *protocol_name, gchar *variant_name,
+                    gchar *outhdr_name, gchar *aal_header_chars,
+                    gboolean is_comment, int data_chars,
+                    int *err, gchar **err_info)
 {
+    int n;
     int stub_offset = 0;
+    gsize length;
+    guint8 *frame_buffer;
+
+    phdr->rec_type = REC_TYPE_PACKET;
+    phdr->presence_flags = WTAP_HAS_TS;
+
+    /* Make sure all packets go to Catapult DCT2000 dissector */
+    phdr->pkt_encap = WTAP_ENCAP_CATAPULT_DCT2000;
+
+    /* Fill in timestamp (capture base + packet offset) */
+    phdr->ts.secs = file_externals->start_secs + seconds;
+    if ((file_externals->start_usecs + useconds) >= 1000000) {
+        phdr->ts.secs++;
+    }
+    phdr->ts.nsecs =
+        ((file_externals->start_usecs + useconds) % 1000000) *1000;
+
+    /*
+     * Calculate the length of the stub info and the packet data.
+     * The packet data length is half bytestring length.
+     */
+    phdr->caplen = (guint)strlen(context_name)+1 +     /* Context name */
+                   1 +                                 /* port */
+                   (guint)strlen(timestamp_string)+1 + /* timestamp */
+                   (guint)strlen(variant_name)+1 +     /* variant */
+                   (guint)strlen(outhdr_name)+1 +      /* outhdr */
+                   (guint)strlen(protocol_name)+1 +    /* Protocol name */
+                   1 +                                 /* direction */
+                   1 +                                 /* encap */
+                   (is_comment ? data_chars : (data_chars/2));
+    if (phdr->caplen > WTAP_MAX_PACKET_SIZE) {
+        /*
+         * Probably a corrupt capture file; return an error,
+         * so that our caller doesn't blow up trying to allocate
+         * space for an immensely-large packet.
+         */
+        *err = WTAP_ERR_BAD_FILE;
+        *err_info = g_strdup_printf("catapult dct2000: File has %u-byte packet, bigger than maximum of %u",
+                                    phdr->caplen, WTAP_MAX_PACKET_SIZE);
+        return FALSE;
+    }
+    phdr->len = phdr->caplen;
+
+    /*****************************/
+    /* Get the data buffer ready */
+    ws_buffer_assure_space(buf, phdr->caplen);
+    frame_buffer = ws_buffer_start_ptr(buf);
+
+    /******************************************/
+    /* Write the stub info to the data buffer */
 
-    g_strlcpy((char*)frame_buffer, context_name, MAX_CONTEXT_NAME+1);
-    stub_offset += (int)(strlen(context_name) + 1);
+    /* Context name */
+    length = g_strlcpy((char*)frame_buffer, context_name, MAX_CONTEXT_NAME+1);
+    stub_offset += (int)(length + 1);
 
     /* Context port number */
     frame_buffer[stub_offset] = context_port;
     stub_offset++;
 
     /* Timestamp within file */
-    g_strlcpy((char*)&frame_buffer[stub_offset], timestamp_string, MAX_TIMESTAMP_LEN+1);
-    stub_offset += (int)(strlen(timestamp_string) + 1);
+    length = g_strlcpy((char*)&frame_buffer[stub_offset], timestamp_string, MAX_TIMESTAMP_LEN+1);
+    stub_offset += (int)(length + 1);
 
     /* Protocol name */
-    g_strlcpy((char*)&frame_buffer[stub_offset], protocol_name, MAX_PROTOCOL_NAME+1);
-    stub_offset += (int)(strlen(protocol_name) + 1);
+    length = g_strlcpy((char*)&frame_buffer[stub_offset], protocol_name, MAX_PROTOCOL_NAME+1);
+    stub_offset += (int)(length + 1);
 
     /* Protocol variant number (as string) */
-    g_strlcpy((void*)&frame_buffer[stub_offset], variant_name, MAX_VARIANT_DIGITS+1);
-    stub_offset += (int)(strlen(variant_name) + 1);
+    length = g_strlcpy((gchar*)&frame_buffer[stub_offset], variant_name, MAX_VARIANT_DIGITS+1);
+    stub_offset += (int)(length + 1);
 
     /* Outhdr */
-    g_strlcpy((char*)&frame_buffer[stub_offset], outhdr_name, MAX_OUTHDR_NAME+1);
-    stub_offset += (int)(strlen(outhdr_name) + 1);
+    length = g_strlcpy((char*)&frame_buffer[stub_offset], outhdr_name, MAX_OUTHDR_NAME+1);
+    stub_offset += (int)(length + 1);
 
     /* Direction */
     frame_buffer[stub_offset] = direction;
@@ -1258,47 +1369,53 @@ static int write_stub_header(guchar *frame_buffer, char *timestamp_string,
     frame_buffer[stub_offset] = (guint8)encap;
     stub_offset++;
 
-    return stub_offset;
-}
-
+    if (!is_comment) {
+        /***********************************************************/
+        /* Copy packet 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];
+        }
+    }
 
-/**************************************************************/
-/* Set pseudo-header info depending upon packet encapsulation */
-/**************************************************************/
-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;
+    /*****************************************/
+    /* Set packet pseudo-header if necessary */
+    phdr->pseudo_header.dct2000.seek_off = file_offset;
+    phdr->pseudo_header.dct2000.wth = wth;
 
-    switch (pkt_encap) {
+    switch (encap) {
         case WTAP_ENCAP_ATM_PDUS_UNTRUNCATED:
-            set_aal_info(pseudo_header, direction, aal_header_chars);
+            set_aal_info(&phdr->pseudo_header, direction, aal_header_chars);
             break;
         case WTAP_ENCAP_ISDN:
-            set_isdn_info(pseudo_header, direction);
+            set_isdn_info(&phdr->pseudo_header, direction);
             break;
         case WTAP_ENCAP_PPP:
-            set_ppp_info(pseudo_header, direction);
+            set_ppp_info(&phdr->pseudo_header, direction);
             break;
 
         default:
             /* Other supported types don't need to set anything here... */
             break;
     }
-}
 
+    return TRUE;
+}
 
 /*********************************************/
 /* Fill in atm pseudo-header with known info */
 /*********************************************/
-static void set_aal_info(union wtap_pseudo_header *pseudo_header,
-                         packet_direction_t direction,
-                         gchar *aal_header_chars)
+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) |
@@ -1323,8 +1440,7 @@ static void set_aal_info(union wtap_pseudo_header *pseudo_header,
 
     /* 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 =
@@ -1338,14 +1454,13 @@ static void set_aal_info(union wtap_pseudo_header *pseudo_header,
 
     /* 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((guchar)aal_header_chars[11])) {
+    if (g_ascii_isalnum(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 {
         pseudo_header->dct2000.inner_pseudo_header.atm.aal2_cid =
-            (int)aal_header_chars[11] - 48;
+            (int)aal_header_chars[11] - '0';
     }
 }
 
@@ -1353,8 +1468,9 @@ static void set_aal_info(union wtap_pseudo_header *pseudo_header,
 /**********************************************/
 /* Fill in isdn pseudo-header with known info */
 /**********************************************/
-void set_isdn_info(union wtap_pseudo_header *pseudo_header,
-                   packet_direction_t direction)
+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
        'User' or 'Network'. If we assume that we're simulating the network,
@@ -1372,8 +1488,9 @@ 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,
-                         packet_direction_t direction)
+static void
+set_ppp_info(union wtap_pseudo_header *pseudo_header,
+             packet_direction_t direction)
 {
     /* Set direction. */
     pseudo_header->dct2000.inner_pseudo_header.p2p.sent = (direction == sent);
@@ -1383,7 +1500,8 @@ 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')) {
         return c - '0';
@@ -1398,12 +1516,40 @@ guchar hex_from_char(gchar c)
 }
 
 
+
+/* Table allowing fast lookup from a pair of ascii hex characters to a guint8 */
+static guint8 s_tableValues[256][256];
+
+/* Prepare table values so ready so don't need to check inside hex_byte_from_chars() */
+static void  prepare_hex_byte_from_chars_table(void)
+{
+    guchar hex_char_array[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+                                  'a', 'b', 'c', 'd', 'e', 'f' };
+
+    gint i, j;
+    for (i=0; i < 16; i++) {
+        for (j=0; j < 16; j++) {
+            s_tableValues[hex_char_array[i]][hex_char_array[j]] = i*16 + j;
+        }
+    }
+}
+
+/* Extract and return a byte value from 2 ascii hex chars, starting from the given pointer */
+static guint8 hex_byte_from_chars(gchar *c)
+{
+    /* Return value from quick table lookup */
+    return s_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] =
+    static const char hex_lookup[16] =
     { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
 
     if (hex > 15) {
@@ -1416,7 +1562,8 @@ gchar char_from_hex(guchar hex)
 /***********************************************/
 /* 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);
@@ -1426,9 +1573,10 @@ 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 */
+    /* Use low-order bits of gint64 offset value */
     return (guint)(*(const gint64*)v);
 }
 
@@ -1438,9 +1586,9 @@ 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(gchar *linebuff, time_t *secs, guint32 *usecs)
+static gboolean
+get_file_time_stamp(gchar *linebuff, time_t *secs, guint32 *usecs)
 {
-    int n;
     struct tm tm;
     #define MAX_MONTH_LETTERS 9
     char month[MAX_MONTH_LETTERS+1];
@@ -1453,12 +1601,14 @@ gboolean get_file_time_stamp(gchar *linebuff, time_t *secs, guint32 *usecs)
         return FALSE;
     }
 
-    /**************************************************************/
-    /* First is month. Read until get a space following the month */
-    for (n=0; (linebuff[n] != ' ') && (n < MAX_MONTH_LETTERS); n++) {
-        month[n] = linebuff[n];
+    /********************************************************/
+    /* Scan for all fields                                  */
+    scan_found = sscanf(linebuff, "%9s %2d, %4d     %2d:%2d:%2d.%4u",
+                        month, &day, &year, &hour, &minute, &second, usecs);
+    if (scan_found != 7) {
+        /* Give up if not all found */
+        return FALSE;
     }
-    month[n] = '\0';
 
     if      (strcmp(month, "January"  ) == 0)  tm.tm_mon = 0;
     else if (strcmp(month, "February" ) == 0)  tm.tm_mon = 1;
@@ -1476,17 +1626,6 @@ gboolean get_file_time_stamp(gchar *linebuff, time_t *secs, guint32 *usecs)
         /* Give up if not found a properly-formatted date */
         return FALSE;
     }
-    /* Skip space char */
-    n++;
-
-    /********************************************************/
-    /* Scan for remaining numerical fields                  */
-    scan_found = sscanf(linebuff+n, "%d, %d     %d:%d:%d.%u",
-                        &day, &year, &hour, &minute, &second, usecs);
-    if (scan_found != 6) {
-        /* Give up if not all found */
-        return FALSE;
-    }
 
     /******************************************************/
     /* Fill in remaining fields and return it in a time_t */
@@ -1507,8 +1646,9 @@ gboolean get_file_time_stamp(gchar *linebuff, time_t *secs, guint32 *usecs)
 }
 
 /* Free the data allocated inside a line_prefix_info_t */
-gboolean free_line_prefix_info(gpointer key, gpointer value,
-                               gpointer user_data _U_)
+static gboolean
+free_line_prefix_info(gpointer key, gpointer value,
+                      gpointer user_data _U_)
 {
     line_prefix_info_t *info = (line_prefix_info_t*)value;
 
@@ -1528,3 +1668,15 @@ gboolean free_line_prefix_info(gpointer key, gpointer value,
     return TRUE;
 }
 
+/*
+ * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */