add PROTO_ITEM_SET_HIDDEN() and PROTO_ITEM_SET_GENERATED(),
[obnox/wireshark/wip.git] / print.c
1 /* print.c
2  * Routines for printing packet analysis trees.
3  *
4  * $Id: print.c,v 1.81 2004/05/01 15:15:08 ulfl Exp $
5  *
6  * Gilbert Ramirez <gram@alumni.rice.edu>
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@ethereal.com>
10  * Copyright 1998 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <stdio.h>
32 #include <string.h>
33
34 #include <epan/epan.h>
35 #include <epan/epan_dissect.h>
36 #include <epan/tvbuff.h>
37 #include <epan/packet.h>
38
39 #include "range.h"
40 #include "print.h"
41 #include "ps.h"
42 #include "util.h"
43 #include "packet-data.h"
44 #include "packet-frame.h"
45
46 #define PDML_VERSION "0"
47 #define PSML_VERSION "0"
48
49 static void proto_tree_print_node(proto_node *node, gpointer data);
50 static void proto_tree_print_node_pdml(proto_node *node, gpointer data);
51 static void print_hex_data_buffer(FILE *fh, register const guchar *cp,
52     register guint length, char_enc encoding, print_format_e format);
53 static void ps_clean_string(unsigned char *out, const unsigned char *in,
54                         int outbuf_size);
55 static void print_escaped_xml(FILE *fh, char *unescaped_string);
56
57 typedef struct {
58         int                         level;
59         FILE                    *fh;
60         GSList                  *src_list;
61         print_dissections_e print_dissections;
62         gboolean                print_hex_for_data;
63         char_enc                encoding;
64         gint                    format;
65         epan_dissect_t      *edt;
66 } print_data;
67
68 static void print_pdml_geninfo(proto_tree *tree, print_data *pdata);
69
70 FILE *open_print_dest(int to_file, const char *dest)
71 {
72         FILE    *fh;
73
74         /* Open the file or command for output */
75         if (to_file)
76                 fh = fopen(dest, "w");
77         else
78                 fh = popen(dest, "w");
79
80         return fh;
81 }
82
83 gboolean close_print_dest(int to_file, FILE *fh)
84 {
85         /* Close the file or command */
86         if (to_file)
87                 return (fclose(fh) == 0);
88         else
89                 return (pclose(fh) == 0);
90 }
91
92
93 void
94 proto_tree_print(print_args_t *print_args, epan_dissect_t *edt,
95     FILE *fh)
96 {
97         print_data data;
98         gint    i;
99
100         /* Create the output */
101         data.level = 0;
102         data.fh = fh;
103         data.src_list = edt->pi.data_src;
104         data.encoding = edt->pi.fd->flags.encoding;
105         data.print_dissections = print_args->print_dissections;
106         data.print_hex_for_data = !print_args->print_hex;
107             /* If we're printing the entire packet in hex, don't
108                print uninterpreted data fields in hex as well. */
109         data.format = print_args->format;
110         data.edt = edt;
111
112     switch(data.format) {
113     case(PR_FMT_TEXT):  /* fall through */
114     case(PR_FMT_PS):
115                 proto_tree_children_foreach(edt->tree, proto_tree_print_node, &data);
116         break;
117     case(PR_FMT_PDML):
118                 fprintf(fh, "<packet>\n");
119
120                 /* Print a "geninfo" protocol as required by PDML */
121                 print_pdml_geninfo(edt->tree, &data);
122
123                 proto_tree_children_foreach(edt->tree, proto_tree_print_node_pdml, &data);
124
125                 fprintf(fh, "</packet>\n\n");
126         break;
127     case(PR_FMT_PSML):
128         /* if this is the first packet, we have to create the PSML structure output */
129         if(edt->pi.fd->num == 1) {
130             fprintf(fh, "<structure>\n");
131
132             for(i=0; i < edt->pi.cinfo->num_cols; i++) {
133                 fprintf(fh, "<section>");
134                 print_escaped_xml(fh, edt->pi.cinfo->col_title[i]);
135                 fprintf(fh, "</section>\n");
136             }
137
138             fprintf(fh, "</structure>\n\n");
139         }
140
141                 fprintf(fh, "<packet>\n");
142
143         for(i=0; i < edt->pi.cinfo->num_cols; i++) {
144             fprintf(fh, "<section>");
145             print_escaped_xml(fh, edt->pi.cinfo->col_data[i]);
146             fprintf(fh, "</section>\n");
147         }
148
149                 fprintf(fh, "</packet>\n\n");
150         break;
151     default:
152         g_assert_not_reached();
153         }
154 }
155
156 /*
157  * Find the data source for a specified field, and return a pointer
158  * to the data in it. Returns NULL if the data is out of bounds.
159  */
160 static const guint8 *
161 get_field_data(GSList *src_list, field_info *fi)
162 {
163         GSList *src_le;
164         data_source *src;
165         tvbuff_t *src_tvb;
166         gint length, tvbuff_length;
167
168         for (src_le = src_list; src_le != NULL; src_le = src_le->next) {
169                 src = src_le->data;
170                 src_tvb = src->tvb;
171                 if (fi->ds_tvb == src_tvb) {
172                         /*
173                          * Found it.
174                          *
175                          * XXX - a field can have a length that runs past
176                          * the end of the tvbuff.  Ideally, that should
177                          * be fixed when adding an item to the protocol
178                          * tree, but checking the length when doing
179                          * that could be expensive.  Until we fix that,
180                          * we'll do the check here.
181                          */
182                         tvbuff_length = tvb_length_remaining(src_tvb,
183                             fi->start);
184                         if (tvbuff_length < 0) {
185                                 return NULL;
186                         }
187                         length = fi->length;
188                         if (length > tvbuff_length)
189                                 length = tvbuff_length;
190                         return tvb_get_ptr(src_tvb, fi->start, length);
191                 }
192         }
193         g_assert_not_reached();
194         return NULL;    /* not found */
195 }
196
197 #define MAX_INDENT      160
198
199 #define MAX_PS_LINE_LENGTH 256
200
201 /* Print a tree's data, and any child nodes. */
202 static
203 void proto_tree_print_node(proto_node *node, gpointer data)
204 {
205         field_info      *fi = PITEM_FINFO(node);
206         print_data      *pdata = (print_data*) data;
207         const guint8    *pd;
208         gchar           label_str[ITEM_LABEL_LENGTH];
209         gchar           *label_ptr;
210
211         /* Don't print invisible entries. */
212         if (PROTO_ITEM_IS_HIDDEN(node))
213                 return;
214
215     /* was a free format label produced? */
216         if (fi->rep) {
217                 label_ptr = fi->rep->representation;
218         }
219         else { /* no, make a generic label */
220                 label_ptr = label_str;
221                 proto_item_fill_label(fi, label_str);
222         }
223
224         print_line(pdata->fh, pdata->level, pdata->format, label_ptr);
225
226         /* If it's uninterpreted data, dump it (unless our caller will
227            be printing the entire packet in hex). */
228         if (fi->hfinfo->id == proto_data && pdata->print_hex_for_data) {
229                 /*
230                  * Find the data for this field.
231                  */
232                 pd = get_field_data(pdata->src_list, fi);
233                 if (pd) {
234                         print_hex_data_buffer(pdata->fh, pd, fi->length,
235                             pdata->encoding, pdata->format);
236                 }
237         }
238
239         /* If we're printing all levels, or if this node is one with a
240            subtree and its subtree is expanded, recurse into the subtree,
241            if it exists. */
242         g_assert(fi->tree_type >= -1 && fi->tree_type < num_tree_types);
243         if (pdata->print_dissections == print_dissections_expanded ||
244             (pdata->print_dissections == print_dissections_as_displayed &&
245         fi->tree_type >= 0 && tree_is_expanded[fi->tree_type])) {
246                 if (node->first_child != NULL) {
247                         pdata->level++;
248                         proto_tree_children_foreach(node,
249                                 proto_tree_print_node, pdata);
250                         pdata->level--;
251                 }
252         }
253 }
254
255 /* Print a string, escaping out certain characters that need to
256  * escaped out for XML. */
257 static void
258 print_escaped_xml(FILE *fh, char *unescaped_string)
259 {
260         unsigned char *p;
261
262         for (p = unescaped_string; *p != '\0'; p++) {
263                 switch (*p) {
264                         case '&':
265                                 fputs("&amp;", fh);
266                                 break;
267                         case '<':
268                                 fputs("&lt;", fh);
269                                 break;
270                         case '>':
271                                 fputs("&gt;", fh);
272                                 break;
273                         case '"':
274                                 fputs("&quot;", fh);
275                                 break;
276                         default:
277                                 fputc(*p, fh);
278                 }
279         }
280 }
281
282 static void
283 print_field_hex_value(print_data *pdata, field_info *fi)
284 {
285         int i;
286         const guint8 *pd;
287
288         /* Find the data for this field. */
289         pd = get_field_data(pdata->src_list, fi);
290
291         if (pd) {
292                 /* Print a simple hex dump */
293                 for (i = 0 ; i < fi->length; i++) {
294                         fprintf(pdata->fh, "%02x", pd[i]);
295                 }
296         }
297 }
298
299
300 /* Print a tree's data, and any child nodes, as PDML */
301 static void
302 proto_tree_print_node_pdml(proto_node *node, gpointer data)
303 {
304         field_info      *fi = PITEM_FINFO(node);
305         print_data      *pdata = (print_data*) data;
306         gchar           *label_ptr;
307         gchar           label_str[ITEM_LABEL_LENGTH];
308         char            *dfilter_string;
309         int             chop_len;
310         int             i;
311
312         for (i = -1; i < pdata->level; i++) {
313                 fputs("  ", pdata->fh);
314         }
315
316         /* Text label. It's printed as a field with no name. */
317         if (fi->hfinfo->id == hf_text_only) {
318                 /* Get the text */
319                 if (fi->rep) {
320                         label_ptr = fi->rep->representation;
321                 }
322                 else {
323                         label_ptr = "";
324                 }
325
326                 fputs("<field show=\"", pdata->fh);
327                 print_escaped_xml(pdata->fh, label_ptr);
328
329                 fprintf(pdata->fh, "\" size=\"%d", fi->length);
330                 fprintf(pdata->fh, "\" pos=\"%d", fi->start);
331
332                 fputs("\" value=\"", pdata->fh);
333                 print_field_hex_value(pdata, fi);
334
335                 if (node->first_child != NULL) {
336                         fputs("\">\n", pdata->fh);
337                 }
338                 else {
339                         fputs("\"/>\n", pdata->fh);
340                 }
341         }
342         /* Uninterpreted data, i.e., the "Data" protocol, is
343          * printed as a field instead of a protocol. */
344         else if (fi->hfinfo->id == proto_data) {
345
346                 fputs("<field name=\"data\" value=\"", pdata->fh);
347
348                 print_field_hex_value(pdata, fi);
349
350                 fputs("\"/>\n", pdata->fh);
351
352         }
353         /* Normal protocols and fields */
354         else {
355                 if (fi->hfinfo->type == FT_PROTOCOL) {
356                         fputs("<proto name=\"", pdata->fh);
357                 }
358                 else {
359                         fputs("<field name=\"", pdata->fh);
360                 }
361                 print_escaped_xml(pdata->fh, fi->hfinfo->abbrev);
362
363 #if 0
364         /* PDML spec, see: 
365          * http://analyzer.polito.it/30alpha/docs/dissectors/PDMLSpec.htm
366          *
367          * the show fields contains things in 'human readable' format
368          * showname: contains only the name of the field
369          * show: contains only the data of the field
370          * showdtl: contains additional details of the field data
371          * showmap: contains mappings of the field data (e.g. the hostname to an IP address)
372          *
373          * XXX - the showname shouldn't contain the field data itself 
374          * (like it's contained in the fi->rep->representation). 
375          * Unfortunately, we don't have the field data representation for 
376          * all fields, so this isn't currently possible */
377                 fputs("\" showname=\"", pdata->fh);
378                 print_escaped_xml(pdata->fh, fi->hfinfo->name);
379 #endif
380
381                 if (fi->rep) {
382                         fputs("\" showname=\"", pdata->fh);
383                         print_escaped_xml(pdata->fh, fi->rep->representation);
384                 }
385                 else {
386                         label_ptr = label_str;
387                         proto_item_fill_label(fi, label_str);
388                         fputs("\" showname=\"", pdata->fh);
389                         print_escaped_xml(pdata->fh, label_ptr);
390                 }
391
392         if(PROTO_ITEM_IS_HIDDEN(node)) {
393                 fprintf(pdata->fh, "\" hide=\"yes");
394         }
395
396                 fprintf(pdata->fh, "\" size=\"%d", fi->length);
397                 fprintf(pdata->fh, "\" pos=\"%d", fi->start);
398 /*              fprintf(pdata->fh, "\" id=\"%d", fi->hfinfo->id);*/
399
400                 if (fi->hfinfo->type != FT_PROTOCOL) {
401                         /* Field */
402
403                         /* XXX - this is a hack until we can just call
404                          * fvalue_to_string_repr() for *all* FT_* types. */
405                         dfilter_string = proto_construct_dfilter_string(fi,
406                                         pdata->edt);
407                         if (dfilter_string != NULL) {
408                                 chop_len = strlen(fi->hfinfo->abbrev) + 4; /* for " == " */
409
410                                 /* XXX - Remove double-quotes. Again, once we
411                                  * can call fvalue_to_string_repr(), we can
412                                  * ask it not to produce the version for
413                                  * display-filters, and thus, no
414                                  * double-quotes. */
415                                 if (dfilter_string[strlen(dfilter_string)-1] == '"') {
416                                         dfilter_string[strlen(dfilter_string)-1] = '\0';
417                                         chop_len++;
418                                 }
419
420                                 fputs("\" show=\"", pdata->fh);
421                                 print_escaped_xml(pdata->fh, &dfilter_string[chop_len]);
422                         }
423                         if (fi->length > 0) {
424                                 fputs("\" value=\"", pdata->fh);
425                                 print_field_hex_value(pdata, fi);
426                         }
427                 }
428
429                 if (node->first_child != NULL) {
430                         fputs("\">\n", pdata->fh);
431                 }
432                 else if (fi->hfinfo->id == proto_data) {
433                         fputs("\">\n", pdata->fh);
434                 }
435                 else {
436                         fputs("\"/>\n", pdata->fh);
437                 }
438         }
439
440         /* We always print all levels for PDML. Recurse here. */
441         if (node->first_child != NULL) {
442                 pdata->level++;
443                 proto_tree_children_foreach(node,
444                                 proto_tree_print_node_pdml, pdata);
445                 pdata->level--;
446         }
447
448         if (node->first_child != NULL) {
449                 for (i = -1; i < pdata->level; i++) {
450                         fputs("  ", pdata->fh);
451                 }
452                 if (fi->hfinfo->type == FT_PROTOCOL) {
453                         fputs("</proto>\n", pdata->fh);
454                 }
455                 else {
456                         fputs("</field>\n", pdata->fh);
457                 }
458         }
459 }
460
461 /* Print info for a 'geninfo' pseudo-protocol. This is required by
462  * the PDML spec. The information is contained in Ethereal's 'frame' protocol,
463  * but we produce a 'geninfo' protocol in the PDML to conform to spec.
464  * The 'frame' protocol follows the 'geninfo' protocol in the PDML. */
465 static void
466 print_pdml_geninfo(proto_tree *tree, print_data *pdata)
467 {
468         guint32 num, len, caplen;
469         nstime_t *timestamp;
470         GPtrArray *finfo_array;
471         field_info *frame_finfo;
472
473         /* Get frame protocol's finfo. */
474         finfo_array = proto_find_finfo(tree, proto_frame);
475         if (g_ptr_array_len(finfo_array) < 1) {
476                 return;
477         }
478         frame_finfo = finfo_array->pdata[0];
479         g_ptr_array_free(finfo_array, FALSE);
480
481         /* frame.number --> geninfo.num */
482         finfo_array = proto_find_finfo(tree, hf_frame_number);
483         if (g_ptr_array_len(finfo_array) < 1) {
484                 return;
485         }
486         num = fvalue_get_integer(&((field_info*)finfo_array->pdata[0])->value);
487         g_ptr_array_free(finfo_array, FALSE);
488
489         /* frame.pkt_len --> geninfo.len */
490         finfo_array = proto_find_finfo(tree, hf_frame_packet_len);
491         if (g_ptr_array_len(finfo_array) < 1) {
492                 return;
493         }
494         len = fvalue_get_integer(&((field_info*)finfo_array->pdata[0])->value);
495         g_ptr_array_free(finfo_array, FALSE);
496
497         /* frame.cap_len --> geninfo.caplen */
498         finfo_array = proto_find_finfo(tree, hf_frame_capture_len);
499         if (g_ptr_array_len(finfo_array) < 1) {
500                 return;
501         }
502         caplen = fvalue_get_integer(&((field_info*)finfo_array->pdata[0])->value);
503         g_ptr_array_free(finfo_array, FALSE);
504
505         /* frame.time --> geninfo.timestamp */
506         finfo_array = proto_find_finfo(tree, hf_frame_arrival_time);
507         if (g_ptr_array_len(finfo_array) < 1) {
508                 return;
509         }
510         timestamp = fvalue_get(&((field_info*)finfo_array->pdata[0])->value);
511         g_ptr_array_free(finfo_array, FALSE);
512
513         /* Print geninfo start */
514         fprintf(pdata->fh,
515 "  <proto name=\"geninfo\" pos=\"0\" showname=\"General information\" size=\"%u\">\n",
516                 frame_finfo->length);
517
518         /* Print geninfo.num */
519         fprintf(pdata->fh,
520 "    <field name=\"num\" pos=\"0\" show=\"%u\" showname=\"Number\" value=\"%x\" size=\"%u\"/>\n",
521                 num, num, frame_finfo->length);
522
523         /* Print geninfo.len */
524         fprintf(pdata->fh,
525 "    <field name=\"len\" pos=\"0\" show=\"%u\" showname=\"Packet Length\" value=\"%x\" size=\"%u\"/>\n",
526                 len, len, frame_finfo->length);
527
528         /* Print geninfo.caplen */
529         fprintf(pdata->fh,
530 "    <field name=\"caplen\" pos=\"0\" show=\"%u\" showname=\"Captured Length\" value=\"%x\" size=\"%u\"/>\n",
531                 caplen, caplen, frame_finfo->length);
532
533         /* Print geninfo.timestamp */
534         fprintf(pdata->fh,
535 "    <field name=\"timestamp\" pos=\"0\" show=\"%s\" showname=\"Captured Time\" value=\"%d.%09d\" size=\"%u\"/>\n",
536                 abs_time_to_str(timestamp), (int) timestamp->secs, timestamp->nsecs, frame_finfo->length);
537
538         /* Print geninfo end */
539         fprintf(pdata->fh,
540 "  </proto>\n");
541 }
542
543
544 void print_hex_data(FILE *fh, print_format_e format, epan_dissect_t *edt)
545 {
546         gboolean multiple_sources;
547         GSList *src_le;
548         data_source *src;
549         tvbuff_t *tvb;
550         char *name;
551         char *line;
552         const guchar *cp;
553         guint length;
554
555         /*
556          * Set "multiple_sources" iff this frame has more than one
557          * data source; if it does, we need to print the name of
558          * the data source before printing the data from the
559          * data source.
560          */
561         multiple_sources = (edt->pi.data_src->next != NULL);
562
563         for (src_le = edt->pi.data_src; src_le != NULL;
564             src_le = src_le->next) {
565                 src = src_le->data;
566                 tvb = src->tvb;
567                 if (multiple_sources) {
568                         name = src->name;
569                         print_line(fh, 0, format, "");
570                         line = g_malloc(strlen(name) + 2);      /* <name>:\0 */
571                         strcpy(line, name);
572                         strcat(line, ":");
573                         print_line(fh, 0, format, line);
574                         g_free(line);
575                 }
576                 length = tvb_length(tvb);
577                 cp = tvb_get_ptr(tvb, 0, length);
578                 print_hex_data_buffer(fh, cp, length,
579                     edt->pi.fd->flags.encoding, format);
580         }
581 }
582
583 /*
584  * This routine is based on a routine created by Dan Lasley
585  * <DLASLEY@PROMUS.com>.
586  *
587  * It was modified for Ethereal by Gilbert Ramirez and others.
588  */
589
590 #define MAX_OFFSET_LEN  8       /* max length of hex offset of bytes */
591 #define BYTES_PER_LINE  16      /* max byte values printed on a line */
592 #define HEX_DUMP_LEN    (BYTES_PER_LINE*3)
593                                 /* max number of characters hex dump takes -
594                                    2 digits plus trailing blank */
595 #define DATA_DUMP_LEN   (HEX_DUMP_LEN + 2 + BYTES_PER_LINE)
596                                 /* number of characters those bytes take;
597                                    3 characters per byte of hex dump,
598                                    2 blanks separating hex from ASCII,
599                                    1 character per byte of ASCII dump */
600 #define MAX_LINE_LEN    (MAX_OFFSET_LEN + 2 + DATA_DUMP_LEN)
601                                 /* number of characters per line;
602                                    offset, 2 blanks separating offset
603                                    from data dump, data dump */
604
605 static void
606 print_hex_data_buffer(FILE *fh, register const guchar *cp,
607     register guint length, char_enc encoding, print_format_e format)
608 {
609         register unsigned int ad, i, j, k, l;
610         guchar c;
611         guchar line[MAX_LINE_LEN + 1];
612         unsigned int use_digits;
613         static guchar binhex[16] = {
614                 '0', '1', '2', '3', '4', '5', '6', '7',
615                 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
616
617         print_line(fh, 0, format, "");
618
619         /*
620          * How many of the leading digits of the offset will we supply?
621          * We always supply at least 4 digits, but if the maximum offset
622          * won't fit in 4 digits, we use as many digits as will be needed.
623          */
624         if (((length - 1) & 0xF0000000) != 0)
625                 use_digits = 8; /* need all 8 digits */
626         else if (((length - 1) & 0x0F000000) != 0)
627                 use_digits = 7; /* need 7 digits */
628         else if (((length - 1) & 0x00F00000) != 0)
629                 use_digits = 6; /* need 6 digits */
630         else if (((length - 1) & 0x000F0000) != 0)
631                 use_digits = 5; /* need 5 digits */
632         else
633                 use_digits = 4; /* we'll supply 4 digits */
634
635         ad = 0;
636         i = 0;
637         j = 0;
638         k = 0;
639         while (i < length) {
640                 if ((i & 15) == 0) {
641                         /*
642                          * Start of a new line.
643                          */
644                         j = 0;
645                         k = 0;
646                         l = use_digits;
647                         do {
648                                 l--;
649                                 c = (ad >> (l*4)) & 0xF;
650                                 line[j++] = binhex[c];
651                         } while (l != 0);
652                         line[j++] = ' ';
653                         line[j++] = ' ';
654                         memset(line+j, ' ', DATA_DUMP_LEN);
655
656                         /*
657                          * Offset in line of ASCII dump.
658                          */
659                         k = j + HEX_DUMP_LEN + 2;
660                 }
661                 c = *cp++;
662                 line[j++] = binhex[c>>4];
663                 line[j++] = binhex[c&0xf];
664                 j++;
665                 if (encoding == CHAR_EBCDIC) {
666                         c = EBCDIC_to_ASCII1(c);
667                 }
668                 line[k++] = c >= ' ' && c < 0x7f ? c : '.';
669                 i++;
670                 if ((i & 15) == 0 || i == length) {
671                         /*
672                          * We'll be starting a new line, or
673                          * we're finished printing this buffer;
674                          * dump out the line we've constructed,
675                          * and advance the offset.
676                          */
677                         line[k] = '\0';
678                         print_line(fh, 0, format, line);
679                         ad += 16;
680                 }
681         }
682 }
683
684 static
685 void ps_clean_string(unsigned char *out, const unsigned char *in,
686                         int outbuf_size)
687 {
688         int rd, wr;
689         char c;
690
691         for (rd = 0, wr = 0 ; wr < outbuf_size; rd++, wr++ ) {
692                 c = in[rd];
693                 switch (c) {
694                         case '(':
695                         case ')':
696                         case '\\':
697                                 out[wr] = '\\';
698                                 out[++wr] = c;
699                                 break;
700
701                         default:
702                                 out[wr] = c;
703                                 break;
704                 }
705
706                 if (c == 0) {
707                         break;
708                 }
709         }
710 }
711
712 /* Some formats need stuff at the beginning of the output */
713 void
714 print_preamble(FILE *fh, print_format_e format, gchar *filename)
715 {
716         char            psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */
717
718     
719     switch(format) {
720     case(PR_FMT_TEXT):
721         /* do nothing */
722         break;
723     case(PR_FMT_PS):
724                 print_ps_preamble(fh);
725
726                 fputs("%% Set the font to 10 point\n", fh);
727                 fputs("/Courier findfont 10 scalefont setfont\n", fh);
728                 fputs("\n", fh);
729                 fputs("%% the page title\n", fh);
730                 ps_clean_string(psbuffer, filename, MAX_PS_LINE_LENGTH);
731                 fprintf(fh, "/eth_pagetitle (%s - Ethereal) def\n", psbuffer);
732                 fputs("\n", fh);
733         break;
734     case(PR_FMT_PDML):
735                 fputs("<?xml version=\"1.0\"?>\n", fh);
736                 fputs("<pdml version=\"" PDML_VERSION "\" ", fh);
737                 fprintf(fh, "creator=\"%s/%s\">\n", PACKAGE, VERSION);
738         break;
739     case(PR_FMT_PSML):
740                 fputs("<?xml version=\"1.0\"?>\n", fh);
741                 fputs("<psml version=\"" PSML_VERSION "\" ", fh);
742                 fprintf(fh, "creator=\"%s/%s\">\n", PACKAGE, VERSION);
743         break;
744     default:
745                 g_assert_not_reached();
746         }
747 }
748
749 void
750 print_packet_header(FILE *fh, print_format_e format, guint32 number, gchar *summary) {
751         char            psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */
752
753     
754     switch(format) {
755     case(PR_FMT_TEXT):
756         /* do nothing */
757         break;
758     case(PR_FMT_PS):
759                 ps_clean_string(psbuffer, summary, MAX_PS_LINE_LENGTH);
760         fprintf(fh, "[/Dest /__frame%u__ /Title (%s)   /OUT pdfmark\n", number, psbuffer);
761         fputs("[/View [/XYZ -4 currentpoint matrix currentmatrix matrix defaultmatrix\n", fh);
762         fputs("matrix invertmatrix matrix concatmatrix transform exch pop 20 add null]\n", fh);
763         fprintf(fh, "/Dest /__frame%u__ /DEST pdfmark\n", number);
764         break;
765     case(PR_FMT_PDML):
766         /* do nothing */
767         break;
768     case(PR_FMT_PSML):
769         /* do nothing */
770         break;
771     default:
772                 g_assert_not_reached();
773         }
774 }
775
776 void
777 print_formfeed(FILE *fh, print_format_e format) {
778     switch(format) {
779     case(PR_FMT_TEXT):
780                 fputs("\f", fh);
781         break;
782     case(PR_FMT_PS):
783                 fputs("formfeed\n", fh);
784         break;
785     case(PR_FMT_PDML):
786         /* do nothing */
787         break;
788     case(PR_FMT_PSML):
789         /* do nothing */
790         break;
791     default:
792                 g_assert_not_reached();
793         }
794 }
795
796 /* Some formats need stuff at the end of the output */
797 void
798 print_finale(FILE *fh, print_format_e format)
799 {
800     switch(format) {
801     case(PR_FMT_TEXT):
802         /* do nothing */
803         break;
804     case(PR_FMT_PS):
805                 print_ps_finale(fh);
806         break;
807     case(PR_FMT_PDML):
808                 fputs("</pdml>\n", fh);
809         break;
810     case(PR_FMT_PSML):
811                 fputs("</psml>\n", fh);
812         break;
813     default:
814                 g_assert_not_reached();
815         }
816 }
817
818 void
819 print_line(FILE *fh, int indent, print_format_e format, char *line)
820 {
821         char            space[MAX_INDENT+1];
822         int             i;
823         int             num_spaces;
824         char            psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */
825
826     switch(format) {
827     case(PR_FMT_TEXT):
828                 /* Prepare the tabs for printing, depending on tree level */
829                 num_spaces = indent * 4;
830                 if (num_spaces > MAX_INDENT) {
831                         num_spaces = MAX_INDENT;
832                 }
833                 for (i = 0; i < num_spaces; i++) {
834                         space[i] = ' ';
835                 }
836                 /* The string is NUL-terminated */
837                 space[num_spaces] = '\0';
838
839                 fputs(space, fh);
840                 fputs(line, fh);
841                 putc('\n', fh);
842         break;
843     case(PR_FMT_PS):
844                 ps_clean_string(psbuffer, line, MAX_PS_LINE_LENGTH);
845                 fprintf(fh, "%d (%s) putline\n", indent, psbuffer);
846         break;
847     case(PR_FMT_PDML):
848         /* do nothing */
849         break;
850     case(PR_FMT_PSML):
851         /* do nothing */
852         break;
853     default:
854                 g_assert_not_reached();
855     }
856 }