Fixed assert error reported by Dewi Morgan <dewim@sco.com>.
[obnox/wireshark/wip.git] / print.c
1 /* print.c
2  * Routines for printing packet analysis trees.
3  *
4  * $Id: print.c,v 1.20 1999/09/12 20:23:33 guy Exp $
5  *
6  * Gilbert Ramirez <gram@verdict.uthscsa.edu>
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@zing.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * 
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  * 
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  * 
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <stdio.h>
33 #include <string.h>
34 #include <gtk/gtk.h>
35
36 #ifdef HAVE_SYS_TYPES_H
37 # include <sys/types.h>
38 #endif
39
40 #include "packet.h"
41 #include "prefs.h"
42 #include "print.h"
43 #include "ps.h"
44
45 static void proto_tree_print_node_text(GNode *node, gpointer data);
46 static void dumpit (FILE *fh, register const u_char *cp, register u_int length);
47 static void proto_tree_print_node_ps(GNode *node, gpointer data);
48 static void ps_clean_string(unsigned char *out, const unsigned char *in,
49                         int outbuf_size);
50 static void dumpit_ps (FILE *fh, register const u_char *cp, register u_int length);
51
52 extern int proto_data; /* in packet-data.c */
53
54
55 typedef struct {
56         int             level;
57         FILE            *fh;
58         const guint8    *pd;
59         gboolean        print_all_levels;
60 } print_data;
61
62 FILE *open_print_dest(int to_file, const char *dest)
63 {
64         FILE    *fh;
65
66         /* Open the file or command for output */
67         if (to_file)
68                 fh = fopen(dest, "w");
69         else
70                 fh = popen(dest, "w");
71
72         return fh;
73 }
74
75 void close_print_dest(int to_file, FILE *fh)
76 {
77         /* Close the file or command */
78         if (to_file)
79                 fclose(fh);
80         else
81                 pclose(fh);
82 }
83
84 void print_preamble(FILE *fh)
85 {
86         if (prefs.pr_format == PR_FMT_PS)
87                 print_ps_preamble(fh);
88 }
89
90 void print_finale(FILE *fh)
91 {
92         if (prefs.pr_format == PR_FMT_PS)
93                 print_ps_finale(fh);
94 }
95
96 void proto_tree_print(gboolean print_one_packet, gboolean print_all_levels,
97     GNode *protocol_tree, const u_char *pd, frame_data *fd, FILE *fh)
98 {
99         print_data data;
100
101         /* Create the output */
102         data.level = 0;
103         data.fh = fh;
104         data.pd = pd;
105         data.print_all_levels = print_all_levels;
106
107         /* XXX - printing multiple frames in PostScript looks as if it's
108            tricky - you have to deal with page boundaries, I think -
109            and I'll have to spend some time learning enough about
110            PostScript to figure it out, so, for now, we only print
111            multiple frames as text. */
112         if (prefs.pr_format == PR_FMT_TEXT || !print_one_packet) {
113                 g_node_children_foreach((GNode*) protocol_tree, G_TRAVERSE_ALL,
114                         proto_tree_print_node_text, &data);
115         } else {
116                 g_node_children_foreach((GNode*) protocol_tree, G_TRAVERSE_ALL,
117                         proto_tree_print_node_ps, &data);
118         }
119 }
120
121 /* Print a tree's data, and any child nodes, in plain text */
122 static
123 void proto_tree_print_node_text(GNode *node, gpointer data)
124 {
125         field_info      *fi = (field_info*) (node->data);
126         print_data      *pdata = (print_data*) data;
127         int             i;
128         int             num_spaces;
129         char            space[41];
130         gchar           label_str[ITEM_LABEL_LENGTH];
131         gchar           *label_ptr;
132
133         /* Don't print invisible entries. */
134         if (!fi->visible)
135                 return;
136
137         /* was a free format label produced? */
138         if (fi->representation) {
139                 label_ptr = fi->representation;
140         }
141         else { /* no, make a generic label */
142                 label_ptr = label_str;
143                 proto_item_fill_label(fi, label_str);
144         }
145                 
146         /* Prepare the tabs for printing, depending on tree level */
147         num_spaces = pdata->level * 4;
148         if (num_spaces > 40) {
149                 num_spaces = 40;
150         }
151         for (i = 0; i < num_spaces; i++) {
152                 space[i] = ' ';
153         }
154         /* The string is NUL-terminated */
155         space[num_spaces] = 0;
156
157         /* Print the text */
158         fprintf(pdata->fh, "%s%s\n", space, label_ptr);
159
160         /* If it's uninterpreted data, dump it. */
161         if (fi->hfinfo->id == proto_data)
162                 dumpit(pdata->fh, &pdata->pd[fi->start], fi->length);
163
164         /* If we're printing all levels, or if this level is expanded,
165            recurse into the subtree, if it exists. */
166         if (pdata->print_all_levels || tree_is_expanded[fi->tree_type]) {
167                 if (g_node_n_children(node) > 0) {
168                         pdata->level++;
169                         g_node_children_foreach(node, G_TRAVERSE_ALL,
170                                 proto_tree_print_node_text, pdata);
171                         pdata->level--;
172                 }
173         }
174 }
175
176 /* This routine was created by Dan Lasley <DLASLEY@PROMUS.com>, and
177 only slightly modified for ethereal by Gilbert Ramirez. */
178 static
179 void dumpit (FILE *fh, register const u_char *cp, register u_int length)
180 {
181         register int ad, i, j, k;
182         u_char c;
183         u_char line[60];
184                 static u_char binhex[16] = {
185                         '0', '1', '2', '3', '4', '5', '6', '7',
186                         '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
187
188         memset (line, ' ', sizeof line);
189         line[sizeof (line)-1] = 0;
190         for (ad=i=j=k=0; i<length; i++) {
191                 c = *cp++;
192                 line[j++] = binhex[c>>4];
193                 line[j++] = binhex[c&0xf];
194                 if (i&1) j++;
195                 line[42+k++] = c >= ' ' && c < 0x7f ? c : '.';
196                 if ((i & 15) == 15) {
197                         fprintf (fh, "\n%4x  %s", ad, line);
198                         /*if (i==15) printf (" %d", length);*/
199                         memset (line, ' ', sizeof line);
200                         line[sizeof (line)-1] = j = k = 0;
201                         ad += 16;
202                 }
203         }
204
205         if (line[0] != ' ') fprintf (fh, "\n%4x  %s", ad, line);
206         fprintf(fh, "\n");
207         return;
208
209 }
210
211 #define MAX_LINE_LENGTH 256
212
213 /* Print a node's data, and any child nodes, in PostScript */
214 static
215 void proto_tree_print_node_ps(GNode *node, gpointer data)
216 {
217         field_info      *fi = (field_info*) (node->data);
218         print_data      *pdata = (print_data*) data;
219         gchar           label_str[ITEM_LABEL_LENGTH];
220         gchar           *label_ptr;
221         char            psbuffer[MAX_LINE_LENGTH]; /* static sized buffer! */
222
223         if (!fi->visible)
224                 return;
225
226         /* was a free format label produced? */
227         if (fi->representation) {
228                 label_ptr = fi->representation;
229         }
230         else { /* no, make a generic label */
231                 label_ptr = label_str;
232                 proto_item_fill_label(fi, label_str);
233         }
234                 
235         /* Print the text */
236         ps_clean_string(psbuffer, label_ptr, MAX_LINE_LENGTH);
237         fprintf(pdata->fh, "%d (%s) putline\n", pdata->level, psbuffer);
238
239         /* If it's uninterpreted data, dump it. */
240         if (fi->hfinfo->id == proto_data) {
241                 print_ps_hex(pdata->fh);
242                 dumpit_ps(pdata->fh, &pdata->pd[fi->start], fi->length);
243         }
244
245         /* Recurse into the subtree, if it exists */
246         if (g_node_n_children(node) > 0) {
247                 pdata->level++;
248                 g_node_children_foreach(node, G_TRAVERSE_ALL,
249                         proto_tree_print_node_ps, pdata);
250                 pdata->level--;
251         }
252 }
253
254 static
255 void ps_clean_string(unsigned char *out, const unsigned char *in,
256                         int outbuf_size)
257 {
258         int rd, wr;
259         char c;
260
261         for (rd = 0, wr = 0 ; wr < outbuf_size; rd++, wr++ ) {
262                 c = in[rd];
263                 switch (c) {
264                         case '(':
265                         case ')':
266                         case '\\':
267                                 out[wr] = '\\';
268                                 out[++wr] = c;
269                                 break;
270
271                         default:
272                                 out[wr] = c;
273                                 break;
274                 }
275
276                 if (c == 0) {
277                         break;
278                 }
279         }
280 }
281
282 static
283 void dumpit_ps (FILE *fh, register const u_char *cp, register u_int length)
284 {
285         register int ad, i, j, k;
286         u_char c;
287         u_char line[60];
288                 static u_char binhex[16] = {
289                         '0', '1', '2', '3', '4', '5', '6', '7',
290                         '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
291                 u_char psline[MAX_LINE_LENGTH];
292
293         memset (line, ' ', sizeof line);
294         line[sizeof (line)-1] = 0;
295         for (ad=i=j=k=0; i<length; i++) {
296                 c = *cp++;
297                 line[j++] = binhex[c>>4];
298                 line[j++] = binhex[c&0xf];
299                 if (i&1) j++;
300                 line[42+k++] = c >= ' ' && c < 0x7f ? c : '.';
301                 if ((i & 15) == 15) {
302                                                 ps_clean_string(psline, line, MAX_LINE_LENGTH);
303                         fprintf (fh, "(%4x  %s) hexdump\n", ad, psline);
304                         memset (line, ' ', sizeof line);
305                         line[sizeof (line)-1] = j = k = 0;
306                         ad += 16;
307                 }
308         }
309
310         if (line[0] != ' ') {
311                         ps_clean_string(psline, line, MAX_LINE_LENGTH);
312                         fprintf (fh, "(%4x  %s) hexdump\n", ad, psline);
313                 }
314         return;
315
316 }