added some options and enhancements to the print output:
[metze/wireshark/wip.git] / print.c
1 /* print.c
2  * Routines for printing packet analysis trees.
3  *
4  * $Id: print.c,v 1.78 2004/04/22 17:03:20 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, gint 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.
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                         length = fi->length;
183                         tvbuff_length = tvb_length_remaining(src_tvb,
184                             fi->start);
185                         if (length > tvbuff_length)
186                                 length = tvbuff_length;
187                         return tvb_get_ptr(src_tvb, fi->start, length);
188                 }
189         }
190         g_assert_not_reached();
191         return NULL;    /* not found */
192 }
193
194 #define MAX_INDENT      160
195
196 #define MAX_PS_LINE_LENGTH 256
197
198 /* Print a tree's data, and any child nodes. */
199 static
200 void proto_tree_print_node(proto_node *node, gpointer data)
201 {
202         field_info      *fi = PITEM_FINFO(node);
203         print_data      *pdata = (print_data*) data;
204         const guint8    *pd;
205         gchar           label_str[ITEM_LABEL_LENGTH];
206         gchar           *label_ptr;
207
208         /* Don't print invisible entries. */
209         if (!fi->visible)
210                 return;
211
212     /* was a free format label produced? */
213         if (fi->rep) {
214                 label_ptr = fi->rep->representation;
215         }
216         else { /* no, make a generic label */
217                 label_ptr = label_str;
218                 proto_item_fill_label(fi, label_str);
219         }
220
221         print_line(pdata->fh, pdata->level, pdata->format, label_ptr);
222
223         /* If it's uninterpreted data, dump it (unless our caller will
224            be printing the entire packet in hex). */
225         if (fi->hfinfo->id == proto_data && pdata->print_hex_for_data) {
226                 /*
227                  * Find the data for this field.
228                  */
229                 pd = get_field_data(pdata->src_list, fi);
230                 print_hex_data_buffer(pdata->fh, pd, fi->length,
231                     pdata->encoding, pdata->format);
232         }
233
234         /* If we're printing all levels, or if this node is one with a
235            subtree and its subtree is expanded, recurse into the subtree,
236            if it exists. */
237         g_assert(fi->tree_type >= -1 && fi->tree_type < num_tree_types);
238         if (pdata->print_dissections == print_dissections_expanded ||
239             (pdata->print_dissections == print_dissections_as_displayed &&
240         fi->tree_type >= 0 && tree_is_expanded[fi->tree_type])) {
241                 if (node->first_child != NULL) {
242                         pdata->level++;
243                         proto_tree_children_foreach(node,
244                                 proto_tree_print_node, pdata);
245                         pdata->level--;
246                 }
247         }
248 }
249
250 /* Print a string, escaping out certain characters that need to
251  * escaped out for XML. */
252 static void
253 print_escaped_xml(FILE *fh, char *unescaped_string)
254 {
255         unsigned char *p;
256
257         for (p = unescaped_string; *p != '\0'; p++) {
258                 switch (*p) {
259                         case '&':
260                                 fputs("&amp;", fh);
261                                 break;
262                         case '<':
263                                 fputs("&lt;", fh);
264                                 break;
265                         case '>':
266                                 fputs("&gt;", fh);
267                                 break;
268                         case '"':
269                                 fputs("&quot;", fh);
270                                 break;
271                         default:
272                                 fputc(*p, fh);
273                 }
274         }
275 }
276
277 static void
278 print_field_hex_value(print_data *pdata, field_info *fi)
279 {
280         int i;
281         const guint8 *pd;
282
283         /* Find the data for this field. */
284         pd = get_field_data(pdata->src_list, fi);
285
286         /* Print a simple hex dump */
287         for (i = 0 ; i < fi->length; i++) {
288                 fprintf(pdata->fh, "%02x", pd[i]);
289         }
290 }
291
292
293 /* Print a tree's data, and any child nodes, as PDML */
294 static void
295 proto_tree_print_node_pdml(proto_node *node, gpointer data)
296 {
297         field_info      *fi = PITEM_FINFO(node);
298         print_data      *pdata = (print_data*) data;
299         gchar           *label_ptr;
300         gchar           label_str[ITEM_LABEL_LENGTH];
301         char            *dfilter_string;
302         int             chop_len;
303         int             i;
304
305         for (i = -1; i < pdata->level; i++) {
306                 fputs("  ", pdata->fh);
307         }
308
309         /* Text label. It's printed as a field with no name. */
310         if (fi->hfinfo->id == hf_text_only) {
311                 /* Get the text */
312                 if (fi->rep) {
313                         label_ptr = fi->rep->representation;
314                 }
315                 else {
316                         label_ptr = "";
317                 }
318
319                 fputs("<field show=\"", pdata->fh);
320                 print_escaped_xml(pdata->fh, label_ptr);
321
322                 fprintf(pdata->fh, "\" size=\"%d", fi->length);
323                 fprintf(pdata->fh, "\" pos=\"%d", fi->start);
324
325                 fputs("\" value=\"", pdata->fh);
326                 print_field_hex_value(pdata, fi);
327
328                 if (node->first_child != NULL) {
329                         fputs("\">\n", pdata->fh);
330                 }
331                 else {
332                         fputs("\"/>\n", pdata->fh);
333                 }
334         }
335         /* Uninterpreted data, i.e., the "Data" protocol, is
336          * printed as a field instead of a protocol. */
337         else if (fi->hfinfo->id == proto_data) {
338
339                 fputs("<field name=\"data\" value=\"", pdata->fh);
340
341                 print_field_hex_value(pdata, fi);
342
343                 fputs("\"/>\n", pdata->fh);
344
345         }
346         /* Normal protocols and fields */
347         else {
348                 if (fi->hfinfo->type == FT_PROTOCOL) {
349                         fputs("<proto name=\"", pdata->fh);
350                 }
351                 else {
352                         fputs("<field name=\"", pdata->fh);
353                 }
354                 print_escaped_xml(pdata->fh, fi->hfinfo->abbrev);
355
356 #if 0
357         /* PDML spec, see: 
358          * http://analyzer.polito.it/30alpha/docs/dissectors/PDMLSpec.htm
359          *
360          * the show fields contains things in 'human readable' format
361          * showname: contains only the name of the field
362          * show: contains only the data of the field
363          * showdtl: contains additional details of the field data
364          * showmap: contains mappings of the field data (e.g. the hostname to an IP address)
365          *
366          * XXX - the showname shouldn't contain the field data itself 
367          * (like it's contained in the fi->rep->representation). 
368          * Unfortunately, we don't have the field data representation for 
369          * all fields, so this isn't currently possible */
370                 fputs("\" showname=\"", pdata->fh);
371                 print_escaped_xml(pdata->fh, fi->hfinfo->name);
372 #endif
373
374                 if (fi->rep) {
375                         fputs("\" showname=\"", pdata->fh);
376                         print_escaped_xml(pdata->fh, fi->rep->representation);
377                 }
378                 else {
379                         label_ptr = label_str;
380                         proto_item_fill_label(fi, label_str);
381                         fputs("\" showname=\"", pdata->fh);
382                         print_escaped_xml(pdata->fh, label_ptr);
383                 }
384
385         if(!fi->visible) {
386                 fprintf(pdata->fh, "\" hide=\"yes");
387         }
388
389                 fprintf(pdata->fh, "\" size=\"%d", fi->length);
390                 fprintf(pdata->fh, "\" pos=\"%d", fi->start);
391 /*              fprintf(pdata->fh, "\" id=\"%d", fi->hfinfo->id);*/
392
393                 if (fi->hfinfo->type != FT_PROTOCOL) {
394                         /* Field */
395
396                         /* XXX - this is a hack until we can just call
397                          * fvalue_to_string_repr() for *all* FT_* types. */
398                         dfilter_string = proto_construct_dfilter_string(fi,
399                                         pdata->edt);
400                         if (dfilter_string != NULL) {
401                                 chop_len = strlen(fi->hfinfo->abbrev) + 4; /* for " == " */
402
403                                 /* XXX - Remove double-quotes. Again, once we
404                                  * can call fvalue_to_string_repr(), we can
405                                  * ask it not to produce the version for
406                                  * display-filters, and thus, no
407                                  * double-quotes. */
408                                 if (dfilter_string[strlen(dfilter_string)-1] == '"') {
409                                         dfilter_string[strlen(dfilter_string)-1] = '\0';
410                                         chop_len++;
411                                 }
412
413                                 fputs("\" show=\"", pdata->fh);
414                                 print_escaped_xml(pdata->fh, &dfilter_string[chop_len]);
415                         }
416                         if (fi->length > 0) {
417                                 fputs("\" value=\"", pdata->fh);
418                                 print_field_hex_value(pdata, fi);
419                         }
420                 }
421
422                 if (node->first_child != NULL) {
423                         fputs("\">\n", pdata->fh);
424                 }
425                 else if (fi->hfinfo->id == proto_data) {
426                         fputs("\">\n", pdata->fh);
427                 }
428                 else {
429                         fputs("\"/>\n", pdata->fh);
430                 }
431         }
432
433         /* We always print all levels for PDML. Recurse here. */
434         if (node->first_child != NULL) {
435                 pdata->level++;
436                 proto_tree_children_foreach(node,
437                                 proto_tree_print_node_pdml, pdata);
438                 pdata->level--;
439         }
440
441         if (node->first_child != NULL) {
442                 for (i = -1; i < pdata->level; i++) {
443                         fputs("  ", pdata->fh);
444                 }
445                 if (fi->hfinfo->type == FT_PROTOCOL) {
446                         fputs("</proto>\n", pdata->fh);
447                 }
448                 else {
449                         fputs("</field>\n", pdata->fh);
450                 }
451         }
452 }
453
454 /* Print info for a 'geninfo' pseudo-protocol. This is required by
455  * the PDML spec. The information is contained in Ethereal's 'frame' protocol,
456  * but we produce a 'geninfo' protocol in the PDML to conform to spec.
457  * The 'frame' protocol follows the 'geninfo' protocol in the PDML. */
458 static void
459 print_pdml_geninfo(proto_tree *tree, print_data *pdata)
460 {
461         guint32 num, len, caplen;
462         nstime_t *timestamp;
463         GPtrArray *finfo_array;
464         field_info *frame_finfo;
465
466         /* Get frame protocol's finfo. */
467         finfo_array = proto_find_finfo(tree, proto_frame);
468         if (g_ptr_array_len(finfo_array) < 1) {
469                 return;
470         }
471         frame_finfo = finfo_array->pdata[0];
472         g_ptr_array_free(finfo_array, FALSE);
473
474         /* frame.number --> geninfo.num */
475         finfo_array = proto_find_finfo(tree, hf_frame_number);
476         if (g_ptr_array_len(finfo_array) < 1) {
477                 return;
478         }
479         num = fvalue_get_integer(&((field_info*)finfo_array->pdata[0])->value);
480         g_ptr_array_free(finfo_array, FALSE);
481
482         /* frame.pkt_len --> geninfo.len */
483         finfo_array = proto_find_finfo(tree, hf_frame_packet_len);
484         if (g_ptr_array_len(finfo_array) < 1) {
485                 return;
486         }
487         len = fvalue_get_integer(&((field_info*)finfo_array->pdata[0])->value);
488         g_ptr_array_free(finfo_array, FALSE);
489
490         /* frame.cap_len --> geninfo.caplen */
491         finfo_array = proto_find_finfo(tree, hf_frame_capture_len);
492         if (g_ptr_array_len(finfo_array) < 1) {
493                 return;
494         }
495         caplen = fvalue_get_integer(&((field_info*)finfo_array->pdata[0])->value);
496         g_ptr_array_free(finfo_array, FALSE);
497
498         /* frame.time --> geninfo.timestamp */
499         finfo_array = proto_find_finfo(tree, hf_frame_arrival_time);
500         if (g_ptr_array_len(finfo_array) < 1) {
501                 return;
502         }
503         timestamp = fvalue_get(&((field_info*)finfo_array->pdata[0])->value);
504         g_ptr_array_free(finfo_array, FALSE);
505
506         /* Print geninfo start */
507         fprintf(pdata->fh,
508 "  <proto name=\"geninfo\" pos=\"0\" showname=\"General information\" size=\"%u\">\n",
509                 frame_finfo->length);
510
511         /* Print geninfo.num */
512         fprintf(pdata->fh,
513 "    <field name=\"num\" pos=\"0\" show=\"%u\" showname=\"Number\" value=\"%x\" size=\"%u\"/>\n",
514                 num, num, frame_finfo->length);
515
516         /* Print geninfo.len */
517         fprintf(pdata->fh,
518 "    <field name=\"len\" pos=\"0\" show=\"%u\" showname=\"Packet Length\" value=\"%x\" size=\"%u\"/>\n",
519                 len, len, frame_finfo->length);
520
521         /* Print geninfo.caplen */
522         fprintf(pdata->fh,
523 "    <field name=\"caplen\" pos=\"0\" show=\"%u\" showname=\"Captured Length\" value=\"%x\" size=\"%u\"/>\n",
524                 caplen, caplen, frame_finfo->length);
525
526         /* Print geninfo.timestamp */
527         fprintf(pdata->fh,
528 "    <field name=\"timestamp\" pos=\"0\" show=\"%s\" showname=\"Captured Time\" value=\"%d.%09d\" size=\"%u\"/>\n",
529                 abs_time_to_str(timestamp), (int) timestamp->secs, timestamp->nsecs, frame_finfo->length);
530
531         /* Print geninfo end */
532         fprintf(pdata->fh,
533 "  </proto>\n");
534 }
535
536
537 void print_hex_data(FILE *fh, gint format, epan_dissect_t *edt)
538 {
539         gboolean multiple_sources;
540         GSList *src_le;
541         data_source *src;
542         tvbuff_t *tvb;
543         char *name;
544         char *line;
545         const guchar *cp;
546         guint length;
547
548         /*
549          * Set "multiple_sources" iff this frame has more than one
550          * data source; if it does, we need to print the name of
551          * the data source before printing the data from the
552          * data source.
553          */
554         multiple_sources = (edt->pi.data_src->next != NULL);
555
556         for (src_le = edt->pi.data_src; src_le != NULL;
557             src_le = src_le->next) {
558                 src = src_le->data;
559                 tvb = src->tvb;
560                 if (multiple_sources) {
561                         name = src->name;
562                         print_line(fh, 0, format, "");
563                         line = g_malloc(strlen(name) + 2);      /* <name>:\0 */
564                         strcpy(line, name);
565                         strcat(line, ":");
566                         print_line(fh, 0, format, line);
567                         g_free(line);
568                 }
569                 length = tvb_length(tvb);
570                 cp = tvb_get_ptr(tvb, 0, length);
571                 print_hex_data_buffer(fh, cp, length,
572                     edt->pi.fd->flags.encoding, format);
573         }
574 }
575
576 /*
577  * This routine is based on a routine created by Dan Lasley
578  * <DLASLEY@PROMUS.com>.
579  *
580  * It was modified for Ethereal by Gilbert Ramirez and others.
581  */
582
583 #define MAX_OFFSET_LEN  8       /* max length of hex offset of bytes */
584 #define BYTES_PER_LINE  16      /* max byte values printed on a line */
585 #define HEX_DUMP_LEN    (BYTES_PER_LINE*3)
586                                 /* max number of characters hex dump takes -
587                                    2 digits plus trailing blank */
588 #define DATA_DUMP_LEN   (HEX_DUMP_LEN + 2 + BYTES_PER_LINE)
589                                 /* number of characters those bytes take;
590                                    3 characters per byte of hex dump,
591                                    2 blanks separating hex from ASCII,
592                                    1 character per byte of ASCII dump */
593 #define MAX_LINE_LEN    (MAX_OFFSET_LEN + 2 + DATA_DUMP_LEN)
594                                 /* number of characters per line;
595                                    offset, 2 blanks separating offset
596                                    from data dump, data dump */
597
598 static void
599 print_hex_data_buffer(FILE *fh, register const guchar *cp,
600     register guint length, char_enc encoding, gint format)
601 {
602         register unsigned int ad, i, j, k, l;
603         guchar c;
604         guchar line[MAX_LINE_LEN + 1];
605         unsigned int use_digits;
606         static guchar binhex[16] = {
607                 '0', '1', '2', '3', '4', '5', '6', '7',
608                 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
609
610         print_line(fh, 0, format, "");
611
612         /*
613          * How many of the leading digits of the offset will we supply?
614          * We always supply at least 4 digits, but if the maximum offset
615          * won't fit in 4 digits, we use as many digits as will be needed.
616          */
617         if (((length - 1) & 0xF0000000) != 0)
618                 use_digits = 8; /* need all 8 digits */
619         else if (((length - 1) & 0x0F000000) != 0)
620                 use_digits = 7; /* need 7 digits */
621         else if (((length - 1) & 0x00F00000) != 0)
622                 use_digits = 6; /* need 6 digits */
623         else if (((length - 1) & 0x000F0000) != 0)
624                 use_digits = 5; /* need 5 digits */
625         else
626                 use_digits = 4; /* we'll supply 4 digits */
627
628         ad = 0;
629         i = 0;
630         j = 0;
631         k = 0;
632         while (i < length) {
633                 if ((i & 15) == 0) {
634                         /*
635                          * Start of a new line.
636                          */
637                         j = 0;
638                         k = 0;
639                         l = use_digits;
640                         do {
641                                 l--;
642                                 c = (ad >> (l*4)) & 0xF;
643                                 line[j++] = binhex[c];
644                         } while (l != 0);
645                         line[j++] = ' ';
646                         line[j++] = ' ';
647                         memset(line+j, ' ', DATA_DUMP_LEN);
648
649                         /*
650                          * Offset in line of ASCII dump.
651                          */
652                         k = j + HEX_DUMP_LEN + 2;
653                 }
654                 c = *cp++;
655                 line[j++] = binhex[c>>4];
656                 line[j++] = binhex[c&0xf];
657                 j++;
658                 if (encoding == CHAR_EBCDIC) {
659                         c = EBCDIC_to_ASCII1(c);
660                 }
661                 line[k++] = c >= ' ' && c < 0x7f ? c : '.';
662                 i++;
663                 if ((i & 15) == 0 || i == length) {
664                         /*
665                          * We'll be starting a new line, or
666                          * we're finished printing this buffer;
667                          * dump out the line we've constructed,
668                          * and advance the offset.
669                          */
670                         line[k] = '\0';
671                         print_line(fh, 0, format, line);
672                         ad += 16;
673                 }
674         }
675 }
676
677 static
678 void ps_clean_string(unsigned char *out, const unsigned char *in,
679                         int outbuf_size)
680 {
681         int rd, wr;
682         char c;
683
684         for (rd = 0, wr = 0 ; wr < outbuf_size; rd++, wr++ ) {
685                 c = in[rd];
686                 switch (c) {
687                         case '(':
688                         case ')':
689                         case '\\':
690                                 out[wr] = '\\';
691                                 out[++wr] = c;
692                                 break;
693
694                         default:
695                                 out[wr] = c;
696                                 break;
697                 }
698
699                 if (c == 0) {
700                         break;
701                 }
702         }
703 }
704
705 /* Some formats need stuff at the beginning of the output */
706 void
707 print_preamble(FILE *fh, gint format, gchar *filename)
708 {
709         char            psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */
710
711     
712     switch(format) {
713     case(PR_FMT_TEXT):
714         /* do nothing */
715         break;
716     case(PR_FMT_PS):
717                 print_ps_preamble(fh);
718
719                 fputs("%% Set the font to 10 point\n", fh);
720                 fputs("/Courier findfont 10 scalefont setfont\n", fh);
721                 fputs("\n", fh);
722                 fputs("%% the page title\n", fh);
723                 ps_clean_string(psbuffer, filename, MAX_PS_LINE_LENGTH);
724                 fprintf(fh, "/eth_pagetitle (%s - Ethereal) def\n", psbuffer);
725                 fputs("\n", fh);
726         break;
727     case(PR_FMT_PDML):
728                 fputs("<?xml version=\"1.0\"?>\n", fh);
729                 fputs("<pdml version=\"" PDML_VERSION "\" ", fh);
730                 fprintf(fh, "creator=\"%s/%s\">\n", PACKAGE, VERSION);
731         break;
732     case(PR_FMT_PSML):
733                 fputs("<?xml version=\"1.0\"?>\n", fh);
734                 fputs("<psml version=\"" PSML_VERSION "\" ", fh);
735                 fprintf(fh, "creator=\"%s/%s\">\n", PACKAGE, VERSION);
736         break;
737     default:
738                 g_assert_not_reached();
739         }
740 }
741
742 void
743 print_packet_header(FILE *fh, gint format, guint32 number, gchar *summary) {
744         char            psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */
745
746     
747     switch(format) {
748     case(PR_FMT_TEXT):
749         /* do nothing */
750         break;
751     case(PR_FMT_PS):
752                 ps_clean_string(psbuffer, summary, MAX_PS_LINE_LENGTH);
753         fprintf(fh, "[/Dest /__frame%u__ /Title (%s)   /OUT pdfmark\n", number, psbuffer);
754         fputs("[/View [/XYZ -4 currentpoint matrix currentmatrix matrix defaultmatrix\n", fh);
755         fputs("matrix invertmatrix matrix concatmatrix transform exch pop 20 add null]\n", fh);
756         fprintf(fh, "/Dest /__frame%u__ /DEST pdfmark\n", number);
757         break;
758     case(PR_FMT_PDML):
759         /* do nothing */
760         break;
761     case(PR_FMT_PSML):
762         /* do nothing */
763         break;
764     default:
765                 g_assert_not_reached();
766         }
767 }
768
769 void
770 print_formfeed(FILE *fh, gint format) {
771     switch(format) {
772     case(PR_FMT_TEXT):
773                 fputs("\f", fh);
774         break;
775     case(PR_FMT_PS):
776                 fputs("formfeed\n", fh);
777         break;
778     case(PR_FMT_PDML):
779         /* do nothing */
780         break;
781     case(PR_FMT_PSML):
782         /* do nothing */
783         break;
784     default:
785                 g_assert_not_reached();
786         }
787 }
788
789 /* Some formats need stuff at the end of the output */
790 void
791 print_finale(FILE *fh, gint format)
792 {
793     switch(format) {
794     case(PR_FMT_TEXT):
795         /* do nothing */
796         break;
797     case(PR_FMT_PS):
798                 print_ps_finale(fh);
799         break;
800     case(PR_FMT_PDML):
801                 fputs("</pdml>\n", fh);
802         break;
803     case(PR_FMT_PSML):
804                 fputs("</psml>\n", fh);
805         break;
806     default:
807                 g_assert_not_reached();
808         }
809 }
810
811 void
812 print_line(FILE *fh, int indent, gint format, char *line)
813 {
814         char            space[MAX_INDENT+1];
815         int             i;
816         int             num_spaces;
817         char            psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */
818
819     switch(format) {
820     case(PR_FMT_TEXT):
821                 /* Prepare the tabs for printing, depending on tree level */
822                 num_spaces = indent * 4;
823                 if (num_spaces > MAX_INDENT) {
824                         num_spaces = MAX_INDENT;
825                 }
826                 for (i = 0; i < num_spaces; i++) {
827                         space[i] = ' ';
828                 }
829                 /* The string is NUL-terminated */
830                 space[num_spaces] = '\0';
831
832                 fputs(space, fh);
833                 fputs(line, fh);
834                 putc('\n', fh);
835         break;
836     case(PR_FMT_PS):
837                 ps_clean_string(psbuffer, line, MAX_PS_LINE_LENGTH);
838                 fprintf(fh, "%d (%s) putline\n", indent, psbuffer);
839         break;
840     case(PR_FMT_PDML):
841         /* do nothing */
842         break;
843     case(PR_FMT_PSML):
844         /* do nothing */
845         break;
846     default:
847                 g_assert_not_reached();
848     }
849 }