Use "proto_tree_add_item()" whenever possible; this fixes some bugs
[obnox/wireshark/wip.git] / print.c
diff --git a/print.c b/print.c
index fd89b2c2675dc44320e00353cb2a02a683652ac1..787a700643013f3884efa370ecf244415b165ed9 100644 (file)
--- a/print.c
+++ b/print.c
@@ -1,14 +1,13 @@
 /* print.c
  * Routines for printing packet analysis trees.
  *
- * $Id: print.c,v 1.21 1999/09/29 22:19:13 guy Exp $
+ * $Id: print.c,v 1.38 2001/12/18 21:31:02 gram Exp $
  *
- * Gilbert Ramirez <gram@verdict.uthscsa.edu>
+ * Gilbert Ramirez <gram@alumni.rice.edu>
  *
  * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@zing.org>
+ * By Gerald Combs <gerald@ethereal.com>
  * Copyright 1998 Gerald Combs
- *
  * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
 
 #include <stdio.h>
 #include <string.h>
-#include <gtk/gtk.h>
 
 #ifdef HAVE_SYS_TYPES_H
 # include <sys/types.h>
 #endif
 
 #include "packet.h"
-#include "prefs.h"
 #include "print.h"
 #include "ps.h"
+#include "util.h"
+#include "tvbuff.h"
 
 static void proto_tree_print_node_text(GNode *node, gpointer data);
 static void proto_tree_print_node_ps(GNode *node, gpointer data);
 static void ps_clean_string(unsigned char *out, const unsigned char *in,
                        int outbuf_size);
-static void print_hex_data_ps(FILE *fh, register const u_char *cp, register u_int length);
+static void print_hex_data_text(FILE *fh, register const u_char *cp,
+               register u_int length, char_enc encoding);
+static void print_hex_data_ps(FILE *fh, register const u_char *cp,
+               register u_int length, char_enc encoding);
 
 extern int proto_data; /* in packet-data.c */
 
@@ -54,9 +56,10 @@ extern int proto_data; /* in packet-data.c */
 typedef struct {
        int             level;
        FILE            *fh;
-       const guint8    *pd;
+       GSList          *src_list;
        gboolean        print_all_levels;
        gboolean        print_hex_for_data;
+       char_enc        encoding;
 } print_data;
 
 FILE *open_print_dest(int to_file, const char *dest)
@@ -81,38 +84,34 @@ void close_print_dest(int to_file, FILE *fh)
                pclose(fh);
 }
 
-void print_preamble(FILE *fh)
+void print_preamble(FILE *fh, gint format)
 {
-       if (prefs.pr_format == PR_FMT_PS)
+       if (format == PR_FMT_PS)
                print_ps_preamble(fh);
 }
 
-void print_finale(FILE *fh)
+void print_finale(FILE *fh, gint format)
 {
-       if (prefs.pr_format == PR_FMT_PS)
+       if (format == PR_FMT_PS)
                print_ps_finale(fh);
 }
 
 void proto_tree_print(gboolean print_one_packet, print_args_t *print_args,
-    GNode *protocol_tree, const u_char *pd, frame_data *fd, FILE *fh)
+    GNode *protocol_tree, frame_data *fd, FILE *fh)
 {
        print_data data;
 
        /* Create the output */
        data.level = 0;
        data.fh = fh;
-       data.pd = pd;
+       data.src_list = fd->data_src;
+       data.encoding = fd->flags.encoding;
        data.print_all_levels = print_args->expand_all;
        data.print_hex_for_data = !print_args->print_hex;
            /* If we're printing the entire packet in hex, don't
               print uninterpreted data fields in hex as well. */
 
-       /* XXX - printing multiple frames in PostScript looks as if it's
-          tricky - you have to deal with page boundaries, I think -
-          and I'll have to spend some time learning enough about
-          PostScript to figure it out, so, for now, we only print
-          multiple frames as text. */
-       if (prefs.pr_format == PR_FMT_TEXT || !print_one_packet) {
+       if (print_args->format == PR_FMT_TEXT) {
                g_node_children_foreach((GNode*) protocol_tree, G_TRAVERSE_ALL,
                        proto_tree_print_node_text, &data);
        } else {
@@ -121,15 +120,39 @@ void proto_tree_print(gboolean print_one_packet, print_args_t *print_args,
        }
 }
 
+/*
+ * Find the data source tvbuff with a specified name, and return a
+ * pointer to the data in it.
+ */
+static const guint8 *
+get_field_data(GSList *src_list, field_info *fi)
+{
+       GSList *src;
+       tvbuff_t *src_tvb;
+
+       for (src = src_list; src != NULL; src = g_slist_next(src)) {
+               src_tvb = src->data;
+               if (strcmp(fi->ds_name, tvb_get_name(src_tvb)) == 0) {
+                       /*
+                        * Found it.
+                        */
+                       return tvb_get_ptr(src_tvb, fi->start, fi->length);
+               }
+       }
+       g_assert_not_reached();
+       return NULL;    /* not found */
+}
+
 /* Print a tree's data, and any child nodes, in plain text */
 static
 void proto_tree_print_node_text(GNode *node, gpointer data)
 {
-       field_info      *fi = (field_info*) (node->data);
+       field_info      *fi = PITEM_FINFO(node);
        print_data      *pdata = (print_data*) data;
        int             i;
        int             num_spaces;
        char            space[41];
+       const guint8    *pd;
        gchar           label_str[ITEM_LABEL_LENGTH];
        gchar           *label_ptr;
 
@@ -162,8 +185,13 @@ void proto_tree_print_node_text(GNode *node, gpointer data)
 
        /* If it's uninterpreted data, dump it (unless our caller will
           be printing the entire packet in hex). */
-       if (fi->hfinfo->id == proto_data && pdata->print_hex_for_data)
-               print_hex_data(pdata->fh, &pdata->pd[fi->start], fi->length);
+       if (fi->hfinfo->id == proto_data && pdata->print_hex_for_data) {
+               /*
+                * Find the data for this field.
+                */
+               pd = get_field_data(pdata->src_list, fi);
+               print_hex_data_text(pdata->fh, pd, fi->length, pdata->encoding);
+       }
 
        /* If we're printing all levels, or if this level is expanded,
           recurse into the subtree, if it exists. */
@@ -177,16 +205,56 @@ void proto_tree_print_node_text(GNode *node, gpointer data)
        }
 }
 
+void print_hex_data(FILE *fh, gint format, frame_data *fd)
+{
+       gboolean multiple_sources;
+       GSList *src;
+       tvbuff_t *tvb;
+       char *name;
+       char *line;
+       const u_char *cp;
+       guint length;
+
+       /*
+        * Set "multiple_sources" iff this frame has more than one
+        * data source; if it does, we need to print the name of
+        * the data source before printing the data from the
+        * data source.
+        */
+       multiple_sources = (fd->data_src->next != NULL);
+
+       for (src = fd->data_src; src != NULL; src = src->next) {
+               tvb = src->data;
+               if (multiple_sources) {
+                       name = tvb_get_name(tvb);
+                       print_line(fh, format, "\n");
+                       line = g_malloc(strlen(name) + 3);      /* <name>:\n\0 */
+                       strcpy(line, name);
+                       strcat(line, ":\n");
+                       print_line(fh, format, line);
+                       g_free(line);
+               }
+               length = tvb_length(tvb);
+               cp = tvb_get_ptr(tvb, 0, length);
+               if (format == PR_FMT_PS)
+                       print_hex_data_ps(fh, cp, length, fd->flags.encoding);
+               else
+                       print_hex_data_text(fh, cp, length, fd->flags.encoding);
+       }
+}
+
 /* This routine was created by Dan Lasley <DLASLEY@PROMUS.com>, and
 only slightly modified for ethereal by Gilbert Ramirez. */
-void print_hex_data(FILE *fh, register const u_char *cp, register u_int length)
+static
+void print_hex_data_text(FILE *fh, register const u_char *cp,
+               register u_int length, char_enc encoding)
 {
-        register int ad, i, j, k;
+        register unsigned int ad, i, j, k;
         u_char c;
-        u_char line[60];
-               static u_char binhex[16] = {
-                       '0', '1', '2', '3', '4', '5', '6', '7',
-                       '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+        u_char line[80];
+       static u_char binhex[16] = {
+               '0', '1', '2', '3', '4', '5', '6', '7',
+               '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
 
         memset (line, ' ', sizeof line);
         line[sizeof (line)-1] = 0;
@@ -194,10 +262,13 @@ void print_hex_data(FILE *fh, register const u_char *cp, register u_int length)
                 c = *cp++;
                 line[j++] = binhex[c>>4];
                 line[j++] = binhex[c&0xf];
-                if (i&1) j++;
-                line[42+k++] = c >= ' ' && c < 0x7f ? c : '.';
+                j++;
+               if (encoding == CHAR_EBCDIC) {
+                       c = EBCDIC_to_ASCII1(c);
+               }
+                line[50+k++] = c >= ' ' && c < 0x7f ? c : '.';
                 if ((i & 15) == 15) {
-                        fprintf (fh, "\n%4x  %s", ad, line);
+                        fprintf (fh, "\n%04x  %s", ad, line);
                         /*if (i==15) printf (" %d", length);*/
                         memset (line, ' ', sizeof line);
                         line[sizeof (line)-1] = j = k = 0;
@@ -205,7 +276,7 @@ void print_hex_data(FILE *fh, register const u_char *cp, register u_int length)
                 }
         }
 
-        if (line[0] != ' ') fprintf (fh, "\n%4x  %s", ad, line);
+        if (line[0] != ' ') fprintf (fh, "\n%04x  %s", ad, line);
         fprintf(fh, "\n");
         return;
 
@@ -217,10 +288,11 @@ void print_hex_data(FILE *fh, register const u_char *cp, register u_int length)
 static
 void proto_tree_print_node_ps(GNode *node, gpointer data)
 {
-       field_info      *fi = (field_info*) (node->data);
+       field_info      *fi = PITEM_FINFO(node);
        print_data      *pdata = (print_data*) data;
        gchar           label_str[ITEM_LABEL_LENGTH];
        gchar           *label_ptr;
+       const guint8    *pd;
        char            psbuffer[MAX_LINE_LENGTH]; /* static sized buffer! */
 
        if (!fi->visible)
@@ -239,10 +311,14 @@ void proto_tree_print_node_ps(GNode *node, gpointer data)
        ps_clean_string(psbuffer, label_ptr, MAX_LINE_LENGTH);
        fprintf(pdata->fh, "%d (%s) putline\n", pdata->level, psbuffer);
 
-       /* If it's uninterpreted data, dump it. */
-       if (fi->hfinfo->id == proto_data) {
-               print_ps_hex(pdata->fh);
-               print_hex_data_ps(pdata->fh, &pdata->pd[fi->start], fi->length);
+       /* If it's uninterpreted data, dump it (unless our caller will
+          be printing the entire packet in hex). */
+       if (fi->hfinfo->id == proto_data && pdata->print_hex_for_data) {
+               /*
+                * Find the data for this field.
+                */
+               pd = get_field_data(pdata->src_list, fi);
+               print_hex_data_ps(pdata->fh, pd, fi->length, pdata->encoding);
        }
 
        /* Recurse into the subtree, if it exists */
@@ -283,16 +359,18 @@ void ps_clean_string(unsigned char *out, const unsigned char *in,
 }
 
 static
-void print_hex_data_ps(FILE *fh, register const u_char *cp, register u_int length)
+void print_hex_data_ps(FILE *fh, register const u_char *cp,
+               register u_int length, char_enc encoding)
 {
-        register int ad, i, j, k;
+        register unsigned int ad, i, j, k;
         u_char c;
         u_char line[60];
-               static u_char binhex[16] = {
-                       '0', '1', '2', '3', '4', '5', '6', '7',
-                       '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
-               u_char psline[MAX_LINE_LENGTH];
+       static u_char binhex[16] = {
+               '0', '1', '2', '3', '4', '5', '6', '7',
+               '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+       u_char psline[MAX_LINE_LENGTH];
 
+       print_ps_hex(fh);
         memset (line, ' ', sizeof line);
         line[sizeof (line)-1] = 0;
         for (ad=i=j=k=0; i<length; i++) {
@@ -300,9 +378,12 @@ void print_hex_data_ps(FILE *fh, register const u_char *cp, register u_int lengt
                 line[j++] = binhex[c>>4];
                 line[j++] = binhex[c&0xf];
                 if (i&1) j++;
+               if (encoding == CHAR_EBCDIC) {
+                       c = EBCDIC_to_ASCII1(c);
+               }
                 line[42+k++] = c >= ' ' && c < 0x7f ? c : '.';
                 if ((i & 15) == 15) {
-                                               ps_clean_string(psline, line, MAX_LINE_LENGTH);
+                       ps_clean_string(psline, line, MAX_LINE_LENGTH);
                         fprintf (fh, "(%4x  %s) hexdump\n", ad, psline);
                         memset (line, ' ', sizeof line);
                         line[sizeof (line)-1] = j = k = 0;
@@ -311,9 +392,20 @@ void print_hex_data_ps(FILE *fh, register const u_char *cp, register u_int lengt
         }
 
         if (line[0] != ' ') {
-                       ps_clean_string(psline, line, MAX_LINE_LENGTH);
-                       fprintf (fh, "(%4x  %s) hexdump\n", ad, psline);
-               }
+               ps_clean_string(psline, line, MAX_LINE_LENGTH);
+               fprintf (fh, "(%4x  %s) hexdump\n", ad, psline);
+       }
         return;
 
 }
+
+void print_line(FILE *fh, gint format, char *line)
+{
+       char            psbuffer[MAX_LINE_LENGTH]; /* static sized buffer! */
+
+       if (format == PR_FMT_PS) {
+               ps_clean_string(psbuffer, line, MAX_LINE_LENGTH);
+               fprintf(fh, "(%s) hexdump\n", psbuffer);
+       } else
+               fputs(line, fh);
+}