0d0ecd3d02d6f1addb2c7607602db96603232e15
[obnox/wireshark/wip.git] / print.c
1 /* print.c
2  * Routines for printing packet analysis trees.
3  *
4  * $Id: print.c,v 1.17 1999/09/01 03:04:12 gram 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 "ethereal.h"*/
41 #include "packet.h"
42 #include "prefs.h"
43 #include "print.h"
44 #include "ps.h"
45
46 static void proto_tree_print_node_text(GNode *node, gpointer data);
47 static void dumpit (FILE *fh, register const u_char *cp, register u_int length);
48 static void proto_tree_print_node_ps(GNode *node, gpointer data);
49 static void ps_clean_string(unsigned char *out, const unsigned char *in,
50                         int outbuf_size);
51 static void dumpit_ps (FILE *fh, register const u_char *cp, register u_int length);
52
53 extern int proto_data; /* in packet-data.c */
54
55
56 typedef struct {
57         int             level;
58         FILE            *fh;
59         const guint8    *pd;
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(int frame_num, GNode *protocol_tree,
97     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
106         /* XXX - printing multiple frames in PostScript looks as if it's
107            tricky - you have to deal with page boundaries, I think -
108            and I'll have to spend some time learning enough about
109            PostScript to figure it out, so, for now, we only print
110            multiple frames as text. */
111         if (prefs.pr_format == PR_FMT_TEXT || frame_num != -1) {
112                 if (frame_num != -1)
113                         fprintf(fh, "Frame %d:\n\n", frame_num);
114                 g_node_children_foreach((GNode*) protocol_tree, G_TRAVERSE_ALL,
115                         proto_tree_print_node_text, &data);
116                 if (frame_num != -1)
117                         fprintf(fh, "\n");
118         } else {
119                 if (frame_num != -1) {
120                         fprintf(fh, "0 (Frame %d:) putline\n", frame_num);
121                         fprintf(fh, "0 () putline\n");
122                 }
123                 g_node_children_foreach((GNode*) protocol_tree, G_TRAVERSE_ALL,
124                         proto_tree_print_node_ps, &data);
125                 if (frame_num != -1)
126                         fprintf(fh, "0 () putline\n");
127         }
128 }
129
130 /* Print a tree's data, and any child nodes, in plain text */
131 static
132 void proto_tree_print_node_text(GNode *node, gpointer data)
133 {
134         field_info      *fi = (field_info*) (node->data);
135         print_data      *pdata = (print_data*) data;
136         int             i;
137         int              num_spaces;
138         char            space[41];
139         gchar           label_str[ITEM_LABEL_LENGTH];
140         gchar           *label_ptr;
141
142         if (!fi->visible)
143                 return;
144
145         /* was a free format label produced? */
146         if (fi->representation) {
147                 label_ptr = fi->representation;
148         }
149         else { /* no, make a generic label */
150                 label_ptr = label_str;
151                 proto_item_fill_label(fi, label_str);
152         }
153                 
154         /* Prepare the tabs for printing, depending on tree level */
155         num_spaces = pdata->level * 4;
156         if (num_spaces > 40) {
157                 num_spaces = 40;
158         }
159         for (i = 0; i < num_spaces; i++) {
160                 space[i] = ' ';
161         }
162         /* The string is NUL-terminated */
163         space[num_spaces] = 0;
164
165         /* Print the text */
166         fprintf(pdata->fh, "%s%s\n", space, label_ptr);
167
168         /* If it's uninterpreted data, dump it. */
169         if (fi->hfinfo->id == proto_data)
170                 dumpit(pdata->fh, &pdata->pd[fi->start], fi->length);
171
172         /* Recurse into the subtree, if it exists */
173         if (g_node_n_children(node) > 0) {
174                 pdata->level++;
175                 g_node_children_foreach(node, G_TRAVERSE_ALL,
176                         proto_tree_print_node_text, pdata);
177                 pdata->level--;
178         }
179 }
180
181 /* This routine was created by Dan Lasley <DLASLEY@PROMUS.com>, and
182 only slightly modified for ethereal by Gilbert Ramirez. */
183 static
184 void dumpit (FILE *fh, register const u_char *cp, register u_int length)
185 {
186         register int ad, i, j, k;
187         u_char c;
188         u_char line[60];
189                 static u_char binhex[16] = {
190                         '0', '1', '2', '3', '4', '5', '6', '7',
191                         '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
192
193         memset (line, ' ', sizeof line);
194         line[sizeof (line)-1] = 0;
195         for (ad=i=j=k=0; i<length; i++) {
196                 c = *cp++;
197                 line[j++] = binhex[c>>4];
198                 line[j++] = binhex[c&0xf];
199                 if (i&1) j++;
200                 line[42+k++] = c >= ' ' && c < 0x7f ? c : '.';
201                 if ((i & 15) == 15) {
202                         fprintf (fh, "\n%4x  %s", ad, line);
203                         /*if (i==15) printf (" %d", length);*/
204                         memset (line, ' ', sizeof line);
205                         line[sizeof (line)-1] = j = k = 0;
206                         ad += 16;
207                 }
208         }
209
210         if (line[0] != ' ') fprintf (fh, "\n%4x  %s", ad, line);
211         fprintf(fh, "\n");
212         return;
213
214 }
215
216 #define MAX_LINE_LENGTH 256
217
218 /* Print a node's data, and any child nodes, in PostScript */
219 static
220 void proto_tree_print_node_ps(GNode *node, gpointer data)
221 {
222         field_info      *fi = (field_info*) (node->data);
223         print_data      *pdata = (print_data*) data;
224         gchar           label_str[ITEM_LABEL_LENGTH];
225         gchar           *label_ptr;
226         char            psbuffer[MAX_LINE_LENGTH]; /* static sized buffer! */
227
228         if (!fi->visible)
229                 return;
230
231         /* was a free format label produced? */
232         if (fi->representation) {
233                 label_ptr = fi->representation;
234         }
235         else { /* no, make a generic label */
236                 label_ptr = label_str;
237                 proto_item_fill_label(fi, label_str);
238         }
239                 
240         /* Print the text */
241         ps_clean_string(psbuffer, label_ptr, MAX_LINE_LENGTH);
242         fprintf(pdata->fh, "%d (%s) putline\n", pdata->level, psbuffer);
243
244         /* If it's uninterpreted data, dump it. */
245         if (fi->hfinfo->id == proto_data) {
246                 print_ps_hex(pdata->fh);
247                 dumpit_ps(pdata->fh, &pdata->pd[fi->start], fi->length);
248         }
249
250         /* Recurse into the subtree, if it exists */
251         if (g_node_n_children(node) > 0) {
252                 pdata->level++;
253                 g_node_children_foreach(node, G_TRAVERSE_ALL,
254                         proto_tree_print_node_ps, pdata);
255                 pdata->level--;
256         }
257 }
258
259 static
260 void ps_clean_string(unsigned char *out, const unsigned char *in,
261                         int outbuf_size)
262 {
263         int rd, wr;
264         char c;
265
266         for (rd = 0, wr = 0 ; wr < outbuf_size; rd++, wr++ ) {
267                 c = in[rd];
268                 switch (c) {
269                         case '(':
270                         case ')':
271                         case '\\':
272                                 out[wr] = '\\';
273                                 out[++wr] = c;
274                                 break;
275
276                         default:
277                                 out[wr] = c;
278                                 break;
279                 }
280
281                 if (c == 0) {
282                         break;
283                 }
284         }
285 }
286
287 static
288 void dumpit_ps (FILE *fh, register const u_char *cp, register u_int length)
289 {
290         register int ad, i, j, k;
291         u_char c;
292         u_char line[60];
293                 static u_char binhex[16] = {
294                         '0', '1', '2', '3', '4', '5', '6', '7',
295                         '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
296                 u_char psline[MAX_LINE_LENGTH];
297
298         memset (line, ' ', sizeof line);
299         line[sizeof (line)-1] = 0;
300         for (ad=i=j=k=0; i<length; i++) {
301                 c = *cp++;
302                 line[j++] = binhex[c>>4];
303                 line[j++] = binhex[c&0xf];
304                 if (i&1) j++;
305                 line[42+k++] = c >= ' ' && c < 0x7f ? c : '.';
306                 if ((i & 15) == 15) {
307                                                 ps_clean_string(psline, line, MAX_LINE_LENGTH);
308                         fprintf (fh, "(%4x  %s) hexdump\n", ad, psline);
309                         memset (line, ' ', sizeof line);
310                         line[sizeof (line)-1] = j = k = 0;
311                         ad += 16;
312                 }
313         }
314
315         if (line[0] != ' ') {
316                         ps_clean_string(psline, line, MAX_LINE_LENGTH);
317                         fprintf (fh, "(%4x  %s) hexdump\n", ad, psline);
318                 }
319         return;
320
321 }