additions to tns dissector - sns and connect started
[obnox/wireshark/wip.git] / print.c
1 /* print.c
2  * Routines for printing packet analysis trees.
3  *
4  * $Id: print.c,v 1.24 1999/11/22 08:03:31 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 #include "util.h"
45
46 static void proto_tree_print_node_text(GNode *node, gpointer data);
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 print_hex_data_ps(FILE *fh, register const u_char *cp,
51                 register u_int length, char_enc encoding);
52 static void print_ps_file(FILE* target_fh, FILE* source_fh);
53 static void print_text_file(FILE* target_fh, FILE* source_fh);
54
55 extern int proto_data; /* in packet-data.c */
56
57
58 typedef struct {
59         int             level;
60         FILE            *fh;
61         const guint8    *pd;
62         gboolean        print_all_levels;
63         gboolean        print_hex_for_data;
64         char_enc        encoding;
65 } print_data;
66
67 FILE *open_print_dest(int to_file, const char *dest)
68 {
69         FILE    *fh;
70
71         /* Open the file or command for output */
72         if (to_file)
73                 fh = fopen(dest, "w");
74         else
75                 fh = popen(dest, "w");
76
77         return fh;
78 }
79
80 void close_print_dest(int to_file, FILE *fh)
81 {
82         /* Close the file or command */
83         if (to_file)
84                 fclose(fh);
85         else
86                 pclose(fh);
87 }
88
89 void print_preamble(FILE *fh)
90 {
91         if (prefs.pr_format == PR_FMT_PS)
92                 print_ps_preamble(fh);
93 }
94
95 void print_finale(FILE *fh)
96 {
97         if (prefs.pr_format == PR_FMT_PS)
98                 print_ps_finale(fh);
99 }
100
101 void print_file(FILE* fh, const char* filename)
102 {
103        FILE* fh2 = fopen(filename, "r");
104        if (fh2 == NULL) {
105                fprintf(stderr, "Could not open file %s for reading.\n", filename);
106                return;
107        }
108
109        if (prefs.pr_format == PR_FMT_PS)
110                print_ps_file(fh, fh2);
111        else
112                print_text_file(fh, fh2);
113 }
114
115 void proto_tree_print(gboolean print_one_packet, print_args_t *print_args,
116     GNode *protocol_tree, const u_char *pd, frame_data *fd, FILE *fh)
117 {
118         print_data data;
119
120         /* Create the output */
121         data.level = 0;
122         data.fh = fh;
123         data.pd = pd;
124         data.encoding = fd->encoding;
125         data.print_all_levels = print_args->expand_all;
126         data.print_hex_for_data = !print_args->print_hex;
127             /* If we're printing the entire packet in hex, don't
128                print uninterpreted data fields in hex as well. */
129
130         /* XXX - printing multiple frames in PostScript looks as if it's
131            tricky - you have to deal with page boundaries, I think -
132            and I'll have to spend some time learning enough about
133            PostScript to figure it out, so, for now, we only print
134            multiple frames as text. */
135         if (prefs.pr_format == PR_FMT_TEXT || !print_one_packet) {
136                 g_node_children_foreach((GNode*) protocol_tree, G_TRAVERSE_ALL,
137                         proto_tree_print_node_text, &data);
138         } else {
139                 g_node_children_foreach((GNode*) protocol_tree, G_TRAVERSE_ALL,
140                         proto_tree_print_node_ps, &data);
141         }
142 }
143
144 /* Print a tree's data, and any child nodes, in plain text */
145 static
146 void proto_tree_print_node_text(GNode *node, gpointer data)
147 {
148         field_info      *fi = (field_info*) (node->data);
149         print_data      *pdata = (print_data*) data;
150         int             i;
151         int             num_spaces;
152         char            space[41];
153         gchar           label_str[ITEM_LABEL_LENGTH];
154         gchar           *label_ptr;
155
156         /* Don't print invisible entries. */
157         if (!fi->visible)
158                 return;
159
160         /* was a free format label produced? */
161         if (fi->representation) {
162                 label_ptr = fi->representation;
163         }
164         else { /* no, make a generic label */
165                 label_ptr = label_str;
166                 proto_item_fill_label(fi, label_str);
167         }
168                 
169         /* Prepare the tabs for printing, depending on tree level */
170         num_spaces = pdata->level * 4;
171         if (num_spaces > 40) {
172                 num_spaces = 40;
173         }
174         for (i = 0; i < num_spaces; i++) {
175                 space[i] = ' ';
176         }
177         /* The string is NUL-terminated */
178         space[num_spaces] = 0;
179
180         /* Print the text */
181         fprintf(pdata->fh, "%s%s\n", space, label_ptr);
182
183         /* If it's uninterpreted data, dump it (unless our caller will
184            be printing the entire packet in hex). */
185         if (fi->hfinfo->id == proto_data && pdata->print_hex_for_data)
186                 print_hex_data(pdata->fh, &pdata->pd[fi->start], fi->length,
187                                 pdata->encoding);
188
189         /* If we're printing all levels, or if this level is expanded,
190            recurse into the subtree, if it exists. */
191         if (pdata->print_all_levels || tree_is_expanded[fi->tree_type]) {
192                 if (g_node_n_children(node) > 0) {
193                         pdata->level++;
194                         g_node_children_foreach(node, G_TRAVERSE_ALL,
195                                 proto_tree_print_node_text, pdata);
196                         pdata->level--;
197                 }
198         }
199 }
200
201 /* This routine was created by Dan Lasley <DLASLEY@PROMUS.com>, and
202 only slightly modified for ethereal by Gilbert Ramirez. */
203 void print_hex_data(FILE *fh, register const u_char *cp, register u_int length,
204                 char_enc encoding)
205 {
206         register int ad, i, j, k;
207         u_char c;
208         u_char line[60];
209                 static u_char binhex[16] = {
210                         '0', '1', '2', '3', '4', '5', '6', '7',
211                         '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
212
213         memset (line, ' ', sizeof line);
214         line[sizeof (line)-1] = 0;
215         for (ad=i=j=k=0; i<length; i++) {
216                 c = *cp++;
217                 line[j++] = binhex[c>>4];
218                 line[j++] = binhex[c&0xf];
219                 if (i&1) j++;
220                 if (encoding == CHAR_EBCDIC) {
221                         c = EBCDIC_to_ASCII1(c);
222                 }
223                 line[42+k++] = c >= ' ' && c < 0x7f ? c : '.';
224                 if ((i & 15) == 15) {
225                         fprintf (fh, "\n%4x  %s", ad, line);
226                         /*if (i==15) printf (" %d", length);*/
227                         memset (line, ' ', sizeof line);
228                         line[sizeof (line)-1] = j = k = 0;
229                         ad += 16;
230                 }
231         }
232
233         if (line[0] != ' ') fprintf (fh, "\n%4x  %s", ad, line);
234         fprintf(fh, "\n");
235         return;
236
237 }
238
239 #define MAX_LINE_LENGTH 256
240
241 /* Print a node's data, and any child nodes, in PostScript */
242 static
243 void proto_tree_print_node_ps(GNode *node, gpointer data)
244 {
245         field_info      *fi = (field_info*) (node->data);
246         print_data      *pdata = (print_data*) data;
247         gchar           label_str[ITEM_LABEL_LENGTH];
248         gchar           *label_ptr;
249         char            psbuffer[MAX_LINE_LENGTH]; /* static sized buffer! */
250
251         if (!fi->visible)
252                 return;
253
254         /* was a free format label produced? */
255         if (fi->representation) {
256                 label_ptr = fi->representation;
257         }
258         else { /* no, make a generic label */
259                 label_ptr = label_str;
260                 proto_item_fill_label(fi, label_str);
261         }
262                 
263         /* Print the text */
264         ps_clean_string(psbuffer, label_ptr, MAX_LINE_LENGTH);
265         fprintf(pdata->fh, "%d (%s) putline\n", pdata->level, psbuffer);
266
267         /* If it's uninterpreted data, dump it. */
268         if (fi->hfinfo->id == proto_data) {
269                 print_ps_hex(pdata->fh);
270                 print_hex_data_ps(pdata->fh, &pdata->pd[fi->start], fi->length,
271                                 pdata->encoding);
272         }
273
274         /* Recurse into the subtree, if it exists */
275         if (g_node_n_children(node) > 0) {
276                 pdata->level++;
277                 g_node_children_foreach(node, G_TRAVERSE_ALL,
278                         proto_tree_print_node_ps, pdata);
279                 pdata->level--;
280         }
281 }
282
283 static
284 void ps_clean_string(unsigned char *out, const unsigned char *in,
285                         int outbuf_size)
286 {
287         int rd, wr;
288         char c;
289
290         for (rd = 0, wr = 0 ; wr < outbuf_size; rd++, wr++ ) {
291                 c = in[rd];
292                 switch (c) {
293                         case '(':
294                         case ')':
295                         case '\\':
296                                 out[wr] = '\\';
297                                 out[++wr] = c;
298                                 break;
299
300                         default:
301                                 out[wr] = c;
302                                 break;
303                 }
304
305                 if (c == 0) {
306                         break;
307                 }
308         }
309 }
310
311 static
312 void print_hex_data_ps(FILE *fh, register const u_char *cp, register u_int length,
313                 char_enc encoding)
314 {
315         register int ad, i, j, k;
316         u_char c;
317         u_char line[60];
318                 static u_char binhex[16] = {
319                         '0', '1', '2', '3', '4', '5', '6', '7',
320                         '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
321                 u_char psline[MAX_LINE_LENGTH];
322
323         memset (line, ' ', sizeof line);
324         line[sizeof (line)-1] = 0;
325         for (ad=i=j=k=0; i<length; i++) {
326                 c = *cp++;
327                 line[j++] = binhex[c>>4];
328                 line[j++] = binhex[c&0xf];
329                 if (i&1) j++;
330                 if (encoding == CHAR_EBCDIC) {
331                         c = EBCDIC_to_ASCII1(c);
332                 }
333                 line[42+k++] = c >= ' ' && c < 0x7f ? c : '.';
334                 if ((i & 15) == 15) {
335                         ps_clean_string(psline, line, MAX_LINE_LENGTH);
336                         fprintf (fh, "(%4x  %s) hexdump\n", ad, psline);
337                         memset (line, ' ', sizeof line);
338                         line[sizeof (line)-1] = j = k = 0;
339                         ad += 16;
340                 }
341         }
342
343         if (line[0] != ' ') {
344                         ps_clean_string(psline, line, MAX_LINE_LENGTH);
345                         fprintf (fh, "(%4x  %s) hexdump\n", ad, psline);
346                 }
347         return;
348
349 }
350
351 static 
352 void print_text_file(FILE* target_fh, FILE* source_fh)
353 {
354        gchar buffer[MAX_LINE_LENGTH];
355        while (fgets(buffer, sizeof(buffer), source_fh) != NULL) {
356                fputs(buffer, target_fh);
357        }
358 }
359
360 static 
361 void print_ps_file(FILE* target_fh, FILE* source_fh)
362 {
363        gchar buffer[MAX_LINE_LENGTH];
364        gchar ps_buffer[MAX_LINE_LENGTH];
365
366        while (fgets(buffer, sizeof(buffer), source_fh) != NULL) {
367                ps_clean_string(ps_buffer, buffer, MAX_LINE_LENGTH);
368                fputs(ps_buffer, target_fh);
369        }
370 }
371