Make dissection of AVP: 3GPP-User-Location-Info(22) l=15 f=V-- vnd=TGPP val=303231...
[obnox/wireshark/wip.git] / print.c
1 /* print.c
2  * Routines for printing packet analysis trees.
3  *
4  * $Id$
5  *
6  * Gilbert Ramirez <gram@alumni.rice.edu>
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
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 <glib.h>
35
36 #include <epan/epan.h>
37 #include <epan/epan_dissect.h>
38 #include <epan/tvbuff.h>
39 #include <epan/packet.h>
40 #include <epan/emem.h>
41
42 #include "packet-range.h"
43 #include "print.h"
44 #include "ps.h"
45 #include "version_info.h"
46 #include <wsutil/file_util.h>
47 #include <epan/charsets.h>
48 #include <epan/dissectors/packet-data.h>
49 #include <epan/dissectors/packet-frame.h>
50 #include <epan/filesystem.h>
51
52 #define PDML_VERSION "0"
53 #define PSML_VERSION "0"
54
55 typedef struct {
56         int                     level;
57         print_stream_t          *stream;
58         gboolean                success;
59         GSList                  *src_list;
60         print_dissections_e     print_dissections;
61         gboolean                print_hex_for_data;
62         packet_char_enc         encoding;
63         epan_dissect_t          *edt;
64 } print_data;
65
66 typedef struct {
67         int                     level;
68         FILE                    *fh;
69         GSList                  *src_list;
70         epan_dissect_t          *edt;
71 } write_pdml_data;
72
73 typedef struct {
74     output_fields_t* fields;
75         epan_dissect_t          *edt;
76 } write_field_data_t;
77
78 struct _output_fields {
79     gboolean print_header;
80     gchar separator;
81     gchar occurrence;
82     gchar aggregator;
83     GPtrArray* fields;
84     GHashTable* field_indicies;
85     emem_strbuf_t** field_values;
86     gchar quote;
87 };
88
89 GHashTable *output_only_tables = NULL;
90
91 static gboolean write_headers = FALSE;
92
93 static const gchar* get_field_hex_value(GSList* src_list, field_info *fi);
94 static void proto_tree_print_node(proto_node *node, gpointer data);
95 static void proto_tree_write_node_pdml(proto_node *node, gpointer data);
96 static const guint8 *get_field_data(GSList *src_list, field_info *fi);
97 static void write_pdml_field_hex_value(write_pdml_data *pdata, field_info *fi);
98 static gboolean print_hex_data_buffer(print_stream_t *stream, const guchar *cp,
99     guint length, packet_char_enc encoding);
100 static void ps_clean_string(unsigned char *out, const unsigned char *in,
101                         int outbuf_size);
102 static void print_escaped_xml(FILE *fh, const char *unescaped_string);
103
104 static void print_pdml_geninfo(proto_tree *tree, FILE *fh);
105
106 static void proto_tree_get_node_field_values(proto_node *node, gpointer data);
107
108 static FILE *
109 open_print_dest(int to_file, const char *dest)
110 {
111         FILE    *fh;
112
113         /* Open the file or command for output */
114         if (to_file)
115                 fh = ws_fopen(dest, "w");
116         else
117                 fh = popen(dest, "w");
118
119         return fh;
120 }
121
122 static gboolean
123 close_print_dest(int to_file, FILE *fh)
124 {
125         /* Close the file or command */
126         if (to_file)
127                 return (fclose(fh) == 0);
128         else
129                 return (pclose(fh) == 0);
130 }
131
132 #define MAX_PS_LINE_LENGTH 256
133
134 gboolean
135 proto_tree_print(print_args_t *print_args, epan_dissect_t *edt,
136     print_stream_t *stream)
137 {
138         print_data data;
139
140         /* Create the output */
141         data.level = 0;
142         data.stream = stream;
143         data.success = TRUE;
144         data.src_list = edt->pi.data_src;
145         data.encoding = edt->pi.fd->flags.encoding;
146         data.print_dissections = print_args->print_dissections;
147         /* If we're printing the entire packet in hex, don't
148            print uninterpreted data fields in hex as well. */
149         data.print_hex_for_data = !print_args->print_hex;
150         data.edt = edt;
151
152         proto_tree_children_foreach(edt->tree, proto_tree_print_node, &data);
153         return data.success;
154 }
155
156 #define MAX_INDENT      160
157
158 /* Print a tree's data, and any child nodes. */
159 static
160 void proto_tree_print_node(proto_node *node, gpointer data)
161 {
162         field_info      *fi = PNODE_FINFO(node);
163         print_data      *pdata = (print_data*) data;
164         const guint8    *pd;
165         gchar           label_str[ITEM_LABEL_LENGTH];
166         gchar           *label_ptr;
167
168         g_assert(fi && "dissection with an invisible proto tree?");
169
170         /* Don't print invisible entries. */
171         if (PROTO_ITEM_IS_HIDDEN(node))
172                 return;
173
174         /* Give up if we've already gotten an error. */
175         if (!pdata->success)
176                 return;
177
178         /* was a free format label produced? */
179         if (fi->rep) {
180                 label_ptr = fi->rep->representation;
181         }
182         else { /* no, make a generic label */
183                 label_ptr = label_str;
184                 proto_item_fill_label(fi, label_str);
185         }
186
187         if (PROTO_ITEM_IS_GENERATED(node)) {
188                 label_ptr = g_strdup_printf("[%s]", label_ptr);
189         }
190
191         if (!print_line(pdata->stream, pdata->level, label_ptr)) {
192                 pdata->success = FALSE;
193                 return;
194         }
195
196         /*
197          * If -O is specified, only display the protocols which are in the
198          * lookup table.  Only check on the first level: once we start printing
199          * a tree, print the rest of the subtree.  Otherwise we won't print
200          * subitems whose abbreviation doesn't match the protocol--for example
201          * text items (whose abbreviation is simply "text").
202          */
203         if (output_only_tables != NULL && pdata->level == 0
204          && g_hash_table_lookup(output_only_tables, fi->hfinfo->abbrev) == NULL) {
205           pdata->success = TRUE;
206           return;
207         }
208
209         if (PROTO_ITEM_IS_GENERATED(node)) {
210                 g_free(label_ptr);
211         }
212
213         /* If it's uninterpreted data, dump it (unless our caller will
214            be printing the entire packet in hex). */
215         if (fi->hfinfo->id == proto_data && pdata->print_hex_for_data) {
216                 /*
217                  * Find the data for this field.
218                  */
219                 pd = get_field_data(pdata->src_list, fi);
220                 if (pd) {
221                         if (!print_hex_data_buffer(pdata->stream, pd,
222                             fi->length, pdata->encoding)) {
223                                 pdata->success = FALSE;
224                                 return;
225                         }
226                 }
227         }
228
229         /* If we're printing all levels, or if this node is one with a
230            subtree and its subtree is expanded, recurse into the subtree,
231            if it exists. */
232         g_assert(fi->tree_type >= -1 && fi->tree_type < num_tree_types);
233         if (pdata->print_dissections == print_dissections_expanded ||
234             (pdata->print_dissections == print_dissections_as_displayed &&
235                 fi->tree_type >= 0 && tree_is_expanded[fi->tree_type])) {
236                 if (node->first_child != NULL) {
237                         pdata->level++;
238                         proto_tree_children_foreach(node,
239                                 proto_tree_print_node, pdata);
240                         pdata->level--;
241                         if (!pdata->success)
242                                 return;
243                 }
244         }
245 }
246
247 #define PDML2HTML_XSL "pdml2html.xsl"
248 void
249 write_pdml_preamble(FILE *fh, const gchar* filename)
250 {
251         time_t t=time(NULL);
252         char *ts=asctime(localtime(&t));
253         ts[strlen(ts)-1]=0; /* overwrite \n */
254
255         fputs("<?xml version=\"1.0\"?>\n", fh);
256         fputs("<?xml-stylesheet type=\"text/xsl\" href=\"" PDML2HTML_XSL "\"?>\n", fh);
257         fprintf(fh, "<!-- You can find " PDML2HTML_XSL " in %s or at http://anonsvn.wireshark.org/trunk/wireshark/" PDML2HTML_XSL ". -->\n", get_datafile_dir());
258         fputs("<pdml version=\"" PDML_VERSION "\" ", fh);
259         fprintf(fh, "creator=\"%s/%s\" time=\"%s\" capture_file=\"%s\">\n", PACKAGE, VERSION, ts, filename ? filename : "");
260 }
261
262 void
263 proto_tree_write_pdml(epan_dissect_t *edt, FILE *fh)
264 {
265         write_pdml_data data;
266
267         /* Create the output */
268         data.level = 0;
269         data.fh = fh;
270         data.src_list = edt->pi.data_src;
271         data.edt = edt;
272
273         fprintf(fh, "<packet>\n");
274
275         /* Print a "geninfo" protocol as required by PDML */
276         print_pdml_geninfo(edt->tree, fh);
277
278         proto_tree_children_foreach(edt->tree, proto_tree_write_node_pdml,
279             &data);
280
281         fprintf(fh, "</packet>\n\n");
282 }
283
284 /* Write out a tree's data, and any child nodes, as PDML */
285 static void
286 proto_tree_write_node_pdml(proto_node *node, gpointer data)
287 {
288         field_info      *fi = PNODE_FINFO(node);
289         write_pdml_data *pdata = (write_pdml_data*) data;
290         const gchar     *label_ptr;
291         gchar           label_str[ITEM_LABEL_LENGTH];
292         char            *dfilter_string;
293         size_t          chop_len;
294         int             i;
295         gboolean wrap_in_fake_protocol;
296
297         g_assert(fi && "dissection with an invisible proto tree?");
298
299         /* Will wrap up top-level field items inside a fake protocol wrapper to
300            preserve the PDML schema */
301         wrap_in_fake_protocol =
302             (((fi->hfinfo->type != FT_PROTOCOL) ||
303              (fi->hfinfo->id == proto_data)) &&
304             (pdata->level == 0));
305
306         /* Indent to the correct level */
307         for (i = -1; i < pdata->level; i++) {
308                 fputs("  ", pdata->fh);
309         }
310
311         if (wrap_in_fake_protocol) {
312                 /* Open fake protocol wrapper */
313                 fputs("<proto name=\"fake-field-wrapper\">\n", pdata->fh);
314
315                 /* Indent to increased level before writint out field */
316                 pdata->level++;
317                 for (i = -1; i < pdata->level; i++) {
318                         fputs("  ", pdata->fh);
319                 }
320         }
321
322         /* Text label. It's printed as a field with no name. */
323         if (fi->hfinfo->id == hf_text_only) {
324                 /* Get the text */
325                 if (fi->rep) {
326                         label_ptr = fi->rep->representation;
327                 }
328                 else {
329                         label_ptr = "";
330                 }
331
332                 /* Show empty name since it is a required field */
333                 fputs("<field name=\"", pdata->fh);
334                 fputs("\" show=\"", pdata->fh);
335                 print_escaped_xml(pdata->fh, label_ptr);
336
337                 fprintf(pdata->fh, "\" size=\"%d", fi->length);
338                 fprintf(pdata->fh, "\" pos=\"%d", fi->start);
339
340                 fputs("\" value=\"", pdata->fh);
341                 write_pdml_field_hex_value(pdata, fi);
342
343                 if (node->first_child != NULL) {
344                         fputs("\">\n", pdata->fh);
345                 }
346                 else {
347                         fputs("\"/>\n", pdata->fh);
348                 }
349         }
350
351         /* Uninterpreted data, i.e., the "Data" protocol, is
352          * printed as a field instead of a protocol. */
353         else if (fi->hfinfo->id == proto_data) {
354
355                 /* Write out field with data */
356                 fputs("<field name=\"data\" value=\"", pdata->fh);
357                 write_pdml_field_hex_value(pdata, fi);
358                 fputs("\"/>\n", pdata->fh);
359         }
360         /* Normal protocols and fields */
361         else {
362                 if (fi->hfinfo->type == FT_PROTOCOL) {
363                         fputs("<proto name=\"", pdata->fh);
364                 }
365                 else {
366                         fputs("<field name=\"", pdata->fh);
367                 }
368                 print_escaped_xml(pdata->fh, fi->hfinfo->abbrev);
369
370 #if 0
371         /* PDML spec, see:
372          * http://www.nbee.org/doku.php?id=netpdl:pdml_specification
373          *
374          * the show fields contains things in 'human readable' format
375          * showname: contains only the name of the field
376          * show: contains only the data of the field
377          * showdtl: contains additional details of the field data
378          * showmap: contains mappings of the field data (e.g. the hostname to an IP address)
379          *
380          * XXX - the showname shouldn't contain the field data itself
381          * (like it's contained in the fi->rep->representation).
382          * Unfortunately, we don't have the field data representation for
383          * all fields, so this isn't currently possible */
384                 fputs("\" showname=\"", pdata->fh);
385                 print_escaped_xml(pdata->fh, fi->hfinfo->name);
386 #endif
387
388                 if (fi->rep) {
389                         fputs("\" showname=\"", pdata->fh);
390                         print_escaped_xml(pdata->fh, fi->rep->representation);
391                 }
392                 else {
393                         label_ptr = label_str;
394                         proto_item_fill_label(fi, label_str);
395                         fputs("\" showname=\"", pdata->fh);
396                         print_escaped_xml(pdata->fh, label_ptr);
397                 }
398
399                 if (PROTO_ITEM_IS_HIDDEN(node))
400                         fprintf(pdata->fh, "\" hide=\"yes");
401
402                 fprintf(pdata->fh, "\" size=\"%d", fi->length);
403                 fprintf(pdata->fh, "\" pos=\"%d", fi->start);
404 /*              fprintf(pdata->fh, "\" id=\"%d", fi->hfinfo->id);*/
405
406                 /* show, value, and unmaskedvalue attributes */
407                 switch (fi->hfinfo->type)
408                 {
409                 case FT_PROTOCOL:
410                         break;
411                 case FT_NONE:
412                         fputs("\" show=\"\" value=\"",  pdata->fh);
413                         break;
414                 default:
415                         /* XXX - this is a hack until we can just call
416                          * fvalue_to_string_repr() for *all* FT_* types. */
417                         dfilter_string = proto_construct_match_selected_string(fi,
418                             pdata->edt);
419                         if (dfilter_string != NULL) {
420                                 chop_len = strlen(fi->hfinfo->abbrev) + 4; /* for " == " */
421
422                                 /* XXX - Remove double-quotes. Again, once we
423                                  * can call fvalue_to_string_repr(), we can
424                                  * ask it not to produce the version for
425                                  * display-filters, and thus, no
426                                  * double-quotes. */
427                                 if (dfilter_string[strlen(dfilter_string)-1] == '"') {
428                                         dfilter_string[strlen(dfilter_string)-1] = '\0';
429                                         chop_len++;
430                                 }
431
432                                 fputs("\" show=\"", pdata->fh);
433                                 print_escaped_xml(pdata->fh, &dfilter_string[chop_len]);
434                         }
435
436                         /*
437                          * XXX - should we omit "value" for any fields?
438                          * What should we do for fields whose length is 0?
439                          * They might come from a pseudo-header or from
440                          * the capture header (e.g., time stamps), or
441                          * they might be generated fields.
442                          */
443                         if (fi->length > 0) {
444                                 fputs("\" value=\"", pdata->fh);
445
446                                 if (fi->hfinfo->bitmask!=0) {
447                                         fprintf(pdata->fh, "%X", fvalue_get_uinteger(&fi->value));
448                                         fputs("\" unmaskedvalue=\"", pdata->fh);
449                                         write_pdml_field_hex_value(pdata, fi);
450                                 }
451                                 else {
452                                         write_pdml_field_hex_value(pdata, fi);
453                                 }
454                         }
455                 }
456
457                 if (node->first_child != NULL) {
458                         fputs("\">\n", pdata->fh);
459                 }
460                 else if (fi->hfinfo->id == proto_data) {
461                         fputs("\">\n", pdata->fh);
462                 }
463                 else {
464                         fputs("\"/>\n", pdata->fh);
465                 }
466         }
467
468         /* We always print all levels for PDML. Recurse here. */
469         if (node->first_child != NULL) {
470                 pdata->level++;
471                 proto_tree_children_foreach(node,
472                                 proto_tree_write_node_pdml, pdata);
473                 pdata->level--;
474         }
475
476         /* Take back the extra level we added for fake wrapper protocol */
477         if (wrap_in_fake_protocol) {
478                 pdata->level--;
479         }
480
481         if (node->first_child != NULL) {
482                 /* Indent to correct level */
483                 for (i = -1; i < pdata->level; i++) {
484                         fputs("  ", pdata->fh);
485                 }
486                 /* Close off current element */
487                 if (fi->hfinfo->id != proto_data) {   /* Data protocol uses simple tags */
488                         if (fi->hfinfo->type == FT_PROTOCOL) {
489                                 fputs("</proto>\n", pdata->fh);
490                         }
491                         else {
492                                 fputs("</field>\n", pdata->fh);
493                         }
494                 }
495         }
496
497         /* Close off fake wrapper protocol */
498         if (wrap_in_fake_protocol) {
499                 fputs("</proto>\n", pdata->fh);
500         }
501 }
502
503 /* Print info for a 'geninfo' pseudo-protocol. This is required by
504  * the PDML spec. The information is contained in Wireshark's 'frame' protocol,
505  * but we produce a 'geninfo' protocol in the PDML to conform to spec.
506  * The 'frame' protocol follows the 'geninfo' protocol in the PDML. */
507 static void
508 print_pdml_geninfo(proto_tree *tree, FILE *fh)
509 {
510         guint32 num, len, caplen;
511         nstime_t *timestamp;
512         GPtrArray *finfo_array;
513         field_info *frame_finfo;
514
515         /* Get frame protocol's finfo. */
516         finfo_array = proto_find_finfo(tree, proto_frame);
517         if (g_ptr_array_len(finfo_array) < 1) {
518                 return;
519         }
520         frame_finfo = (field_info *)finfo_array->pdata[0];
521         g_ptr_array_free(finfo_array, TRUE);
522
523         /* frame.number --> geninfo.num */
524         finfo_array = proto_find_finfo(tree, hf_frame_number);
525         if (g_ptr_array_len(finfo_array) < 1) {
526                 return;
527         }
528         num = fvalue_get_uinteger(&((field_info*)finfo_array->pdata[0])->value);
529         g_ptr_array_free(finfo_array, TRUE);
530
531         /* frame.frame_len --> geninfo.len */
532         finfo_array = proto_find_finfo(tree, hf_frame_len);
533         if (g_ptr_array_len(finfo_array) < 1) {
534                 return;
535         }
536         len = fvalue_get_uinteger(&((field_info*)finfo_array->pdata[0])->value);
537         g_ptr_array_free(finfo_array, TRUE);
538
539         /* frame.cap_len --> geninfo.caplen */
540         finfo_array = proto_find_finfo(tree, hf_frame_capture_len);
541         if (g_ptr_array_len(finfo_array) < 1) {
542                 return;
543         }
544         caplen = fvalue_get_uinteger(&((field_info*)finfo_array->pdata[0])->value);
545         g_ptr_array_free(finfo_array, TRUE);
546
547         /* frame.time --> geninfo.timestamp */
548         finfo_array = proto_find_finfo(tree, hf_frame_arrival_time);
549         if (g_ptr_array_len(finfo_array) < 1) {
550                 return;
551         }
552         timestamp = (nstime_t *)fvalue_get(&((field_info*)finfo_array->pdata[0])->value);
553         g_ptr_array_free(finfo_array, TRUE);
554
555         /* Print geninfo start */
556         fprintf(fh,
557 "  <proto name=\"geninfo\" pos=\"0\" showname=\"General information\" size=\"%u\">\n",
558                 frame_finfo->length);
559
560         /* Print geninfo.num */
561         fprintf(fh,
562 "    <field name=\"num\" pos=\"0\" show=\"%u\" showname=\"Number\" value=\"%x\" size=\"%u\"/>\n",
563                 num, num, frame_finfo->length);
564
565         /* Print geninfo.len */
566         fprintf(fh,
567 "    <field name=\"len\" pos=\"0\" show=\"%u\" showname=\"Frame Length\" value=\"%x\" size=\"%u\"/>\n",
568                 len, len, frame_finfo->length);
569
570         /* Print geninfo.caplen */
571         fprintf(fh,
572 "    <field name=\"caplen\" pos=\"0\" show=\"%u\" showname=\"Captured Length\" value=\"%x\" size=\"%u\"/>\n",
573                 caplen, caplen, frame_finfo->length);
574
575         /* Print geninfo.timestamp */
576         fprintf(fh,
577 "    <field name=\"timestamp\" pos=\"0\" show=\"%s\" showname=\"Captured Time\" value=\"%d.%09d\" size=\"%u\"/>\n",
578                 abs_time_to_str(timestamp, ABSOLUTE_TIME_LOCAL, TRUE), (int) timestamp->secs, timestamp->nsecs, frame_finfo->length);
579
580         /* Print geninfo end */
581         fprintf(fh,
582 "  </proto>\n");
583 }
584
585 void
586 write_pdml_finale(FILE *fh)
587 {
588         fputs("</pdml>\n", fh);
589 }
590
591 void
592 write_psml_preamble(FILE *fh)
593 {
594         fputs("<?xml version=\"1.0\"?>\n", fh);
595         fputs("<psml version=\"" PSML_VERSION "\" ", fh);
596         fprintf(fh, "creator=\"%s/%s\">\n", PACKAGE, VERSION);
597         write_headers = TRUE;
598 }
599
600 void
601 proto_tree_write_psml(epan_dissect_t *edt, FILE *fh)
602 {
603         gint    i;
604
605         /* if this is the first packet, we have to create the PSML structure output */
606         if(write_headers) {
607             fprintf(fh, "<structure>\n");
608
609             for(i=0; i < edt->pi.cinfo->num_cols; i++) {
610                 fprintf(fh, "<section>");
611                 print_escaped_xml(fh, edt->pi.cinfo->col_title[i]);
612                 fprintf(fh, "</section>\n");
613             }
614
615             fprintf(fh, "</structure>\n\n");
616
617             write_headers = FALSE;
618         }
619
620         fprintf(fh, "<packet>\n");
621
622         for(i=0; i < edt->pi.cinfo->num_cols; i++) {
623             fprintf(fh, "<section>");
624             print_escaped_xml(fh, edt->pi.cinfo->col_data[i]);
625             fprintf(fh, "</section>\n");
626         }
627
628         fprintf(fh, "</packet>\n\n");
629 }
630
631 void
632 write_psml_finale(FILE *fh)
633 {
634         fputs("</psml>\n", fh);
635 }
636
637 void
638 write_csv_preamble(FILE *fh _U_)
639 {
640         write_headers = TRUE;
641 }
642
643 static gchar *csv_massage_str(const gchar *source, const gchar *exceptions)
644 {
645     gchar *csv_str;
646     gchar *tmp_str;
647
648     csv_str = g_strescape(source, exceptions);
649     tmp_str = csv_str;
650     while ( (tmp_str = strstr(tmp_str, "\\\"")) != NULL )
651         *tmp_str = '\"';
652     return csv_str;
653 }
654
655 static void csv_write_str(const char *str, char sep, FILE *fh)
656 {
657     gchar *csv_str;
658
659     csv_str = csv_massage_str(str, NULL);
660     fprintf(fh, "\"%s\"%c", csv_str, sep);
661     g_free(csv_str);
662 }
663
664 void
665 proto_tree_write_csv(epan_dissect_t *edt, FILE *fh)
666 {
667     gint i;
668
669     /* if this is the first packet, we have to write the CSV header */
670     if(write_headers) {
671         for(i=0; i < edt->pi.cinfo->num_cols - 1; i++)
672             csv_write_str(edt->pi.cinfo->col_title[i], ',', fh);
673         csv_write_str(edt->pi.cinfo->col_title[i], '\n', fh);
674         write_headers = FALSE;
675     }
676
677     for(i=0; i < edt->pi.cinfo->num_cols - 1; i++)
678         csv_write_str(edt->pi.cinfo->col_data[i], ',', fh);
679     csv_write_str(edt->pi.cinfo->col_data[i], '\n', fh);
680 }
681
682 void
683 write_csv_finale(FILE *fh _U_)
684 {
685
686 }
687
688 void
689 write_carrays_preamble(FILE *fh _U_)
690 {
691
692 }
693
694 void
695 proto_tree_write_carrays(const guint8 *pd, guint32 len, guint32 num, FILE *fh)
696 {
697         guint32 i = 0;
698
699         if (!len)
700                 return;
701
702         fprintf(fh, "char pkt%u[] = {\n", num);
703
704         for (i = 0; i < len; i++) {
705
706                 fprintf(fh, "0x%02x", *(pd + i));
707
708                 if (i == (len - 1)) {
709                         fprintf(fh, " };\n\n");
710                         break;
711                 }
712
713                 if (!((i + 1) % 8)) {
714                         fprintf(fh, ", \n");
715                 } else {
716                         fprintf(fh, ", ");
717                 }
718         }
719 }
720
721 void
722 write_carrays_finale(FILE *fh _U_)
723 {
724
725 }
726
727 /*
728  * Find the data source for a specified field, and return a pointer
729  * to the data in it. Returns NULL if the data is out of bounds.
730  */
731 static const guint8 *
732 get_field_data(GSList *src_list, field_info *fi)
733 {
734         GSList *src_le;
735         data_source *src;
736         tvbuff_t *src_tvb;
737         gint length, tvbuff_length;
738
739         for (src_le = src_list; src_le != NULL; src_le = src_le->next) {
740                 src = (data_source *)src_le->data;
741                 src_tvb = src->tvb;
742                 if (fi->ds_tvb == src_tvb) {
743                         /*
744                          * Found it.
745                          *
746                          * XXX - a field can have a length that runs past
747                          * the end of the tvbuff.  Ideally, that should
748                          * be fixed when adding an item to the protocol
749                          * tree, but checking the length when doing
750                          * that could be expensive.  Until we fix that,
751                          * we'll do the check here.
752                          */
753                         tvbuff_length = tvb_length_remaining(src_tvb,
754                             fi->start);
755                         if (tvbuff_length < 0) {
756                                 return NULL;
757                         }
758                         length = fi->length;
759                         if (length > tvbuff_length)
760                                 length = tvbuff_length;
761                         return tvb_get_ptr(src_tvb, fi->start, length);
762                 }
763         }
764         g_assert_not_reached();
765         return NULL;    /* not found */
766 }
767
768 /* Print a string, escaping out certain characters that need to
769  * escaped out for XML. */
770 static void
771 print_escaped_xml(FILE *fh, const char *unescaped_string)
772 {
773         const char *p;
774         char temp_str[8];
775
776         for (p = unescaped_string; *p != '\0'; p++) {
777                 switch (*p) {
778                         case '&':
779                                 fputs("&amp;", fh);
780                                 break;
781                         case '<':
782                                 fputs("&lt;", fh);
783                                 break;
784                         case '>':
785                                 fputs("&gt;", fh);
786                                 break;
787                         case '"':
788                                 fputs("&quot;", fh);
789                                 break;
790                         case '\'':
791                                 fputs("&apos;", fh);
792                                 break;
793                         default:
794                                 if (g_ascii_isprint(*p))
795                                         fputc(*p, fh);
796                                 else {
797                                         g_snprintf(temp_str, sizeof(temp_str), "\\x%x", (guint8)*p);
798                                         fputs(temp_str, fh);
799                                 }
800                 }
801         }
802 }
803
804 static void
805 write_pdml_field_hex_value(write_pdml_data *pdata, field_info *fi)
806 {
807         int i;
808         const guint8 *pd;
809
810         if (!fi->ds_tvb)
811                 return;
812
813         if (fi->length > tvb_length_remaining(fi->ds_tvb, fi->start)) {
814                 fprintf(pdata->fh, "field length invalid!");
815                 return;
816         }
817
818         /* Find the data for this field. */
819         pd = get_field_data(pdata->src_list, fi);
820
821         if (pd) {
822                 /* Print a simple hex dump */
823                 for (i = 0 ; i < fi->length; i++) {
824                         fprintf(pdata->fh, "%02x", pd[i]);
825                 }
826         }
827 }
828
829 gboolean
830 print_hex_data(print_stream_t *stream, epan_dissect_t *edt)
831 {
832         gboolean multiple_sources;
833         GSList *src_le;
834         data_source *src;
835         tvbuff_t *tvb;
836         const char *name;
837         char *line;
838         const guchar *cp;
839         guint length;
840
841         /*
842          * Set "multiple_sources" iff this frame has more than one
843          * data source; if it does, we need to print the name of
844          * the data source before printing the data from the
845          * data source.
846          */
847         multiple_sources = (edt->pi.data_src->next != NULL);
848
849         for (src_le = edt->pi.data_src; src_le != NULL;
850             src_le = src_le->next) {
851                 src = (data_source *)src_le->data;
852                 tvb = src->tvb;
853                 if (multiple_sources) {
854                         name = get_data_source_name(src);
855                         print_line(stream, 0, "");
856                         line = g_strdup_printf("%s:", name);
857                         print_line(stream, 0, line);
858                         g_free(line);
859                 }
860                 length = tvb_length(tvb);
861                 if (length == 0)
862                     return TRUE;
863                 cp = tvb_get_ptr(tvb, 0, length);
864                 if (!print_hex_data_buffer(stream, cp, length,
865                     edt->pi.fd->flags.encoding))
866                         return FALSE;
867         }
868         return TRUE;
869 }
870
871 /*
872  * This routine is based on a routine created by Dan Lasley
873  * <DLASLEY@PROMUS.com>.
874  *
875  * It was modified for Wireshark by Gilbert Ramirez and others.
876  */
877
878 #define MAX_OFFSET_LEN  8       /* max length of hex offset of bytes */
879 #define BYTES_PER_LINE  16      /* max byte values printed on a line */
880 #define HEX_DUMP_LEN    (BYTES_PER_LINE*3)
881                                 /* max number of characters hex dump takes -
882                                    2 digits plus trailing blank */
883 #define DATA_DUMP_LEN   (HEX_DUMP_LEN + 2 + BYTES_PER_LINE)
884                                 /* number of characters those bytes take;
885                                    3 characters per byte of hex dump,
886                                    2 blanks separating hex from ASCII,
887                                    1 character per byte of ASCII dump */
888 #define MAX_LINE_LEN    (MAX_OFFSET_LEN + 2 + DATA_DUMP_LEN)
889                                 /* number of characters per line;
890                                    offset, 2 blanks separating offset
891                                    from data dump, data dump */
892
893 static gboolean
894 print_hex_data_buffer(print_stream_t *stream, const guchar *cp,
895     guint length, packet_char_enc encoding)
896 {
897         register unsigned int ad, i, j, k, l;
898         guchar c;
899         guchar line[MAX_LINE_LEN + 1];
900         unsigned int use_digits;
901         static guchar binhex[16] = {
902                 '0', '1', '2', '3', '4', '5', '6', '7',
903                 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
904
905         if (!print_line(stream, 0, ""))
906                 return FALSE;
907
908         /*
909          * How many of the leading digits of the offset will we supply?
910          * We always supply at least 4 digits, but if the maximum offset
911          * won't fit in 4 digits, we use as many digits as will be needed.
912          */
913         if (((length - 1) & 0xF0000000) != 0)
914                 use_digits = 8; /* need all 8 digits */
915         else if (((length - 1) & 0x0F000000) != 0)
916                 use_digits = 7; /* need 7 digits */
917         else if (((length - 1) & 0x00F00000) != 0)
918                 use_digits = 6; /* need 6 digits */
919         else if (((length - 1) & 0x000F0000) != 0)
920                 use_digits = 5; /* need 5 digits */
921         else
922                 use_digits = 4; /* we'll supply 4 digits */
923
924         ad = 0;
925         i = 0;
926         j = 0;
927         k = 0;
928         while (i < length) {
929                 if ((i & 15) == 0) {
930                         /*
931                          * Start of a new line.
932                          */
933                         j = 0;
934                         l = use_digits;
935                         do {
936                                 l--;
937                                 c = (ad >> (l*4)) & 0xF;
938                                 line[j++] = binhex[c];
939                         } while (l != 0);
940                         line[j++] = ' ';
941                         line[j++] = ' ';
942                         memset(line+j, ' ', DATA_DUMP_LEN);
943
944                         /*
945                          * Offset in line of ASCII dump.
946                          */
947                         k = j + HEX_DUMP_LEN + 2;
948                 }
949                 c = *cp++;
950                 line[j++] = binhex[c>>4];
951                 line[j++] = binhex[c&0xf];
952                 j++;
953                 if (encoding == PACKET_CHAR_ENC_CHAR_EBCDIC) {
954                         c = EBCDIC_to_ASCII1(c);
955                 }
956                 line[k++] = c >= ' ' && c < 0x7f ? c : '.';
957                 i++;
958                 if ((i & 15) == 0 || i == length) {
959                         /*
960                          * We'll be starting a new line, or
961                          * we're finished printing this buffer;
962                          * dump out the line we've constructed,
963                          * and advance the offset.
964                          */
965                         line[k] = '\0';
966                         if (!print_line(stream, 0, line))
967                                 return FALSE;
968                         ad += 16;
969                 }
970         }
971         return TRUE;
972 }
973
974 static
975 void ps_clean_string(unsigned char *out, const unsigned char *in,
976                         int outbuf_size)
977 {
978         int rd, wr;
979         char c;
980
981         if (in == NULL) {
982                 out[0] = '\0';
983                 return;
984         }
985
986         for (rd = 0, wr = 0 ; wr < outbuf_size; rd++, wr++ ) {
987                 c = in[rd];
988                 switch (c) {
989                         case '(':
990                         case ')':
991                         case '\\':
992                                 out[wr] = '\\';
993                                 out[++wr] = c;
994                                 break;
995
996                         default:
997                                 out[wr] = c;
998                                 break;
999                 }
1000
1001                 if (c == 0) {
1002                         break;
1003                 }
1004         }
1005 }
1006
1007 /* Some formats need stuff at the beginning of the output */
1008 gboolean
1009 print_preamble(print_stream_t *self, gchar *filename)
1010 {
1011         return (self->ops->print_preamble)(self, filename);
1012 }
1013
1014 gboolean
1015 print_line(print_stream_t *self, int indent, const char *line)
1016 {
1017         return (self->ops->print_line)(self, indent, line);
1018 }
1019
1020 /* Insert bookmark */
1021 gboolean
1022 print_bookmark(print_stream_t *self, const gchar *name, const gchar *title)
1023 {
1024         return (self->ops->print_bookmark)(self, name, title);
1025 }
1026
1027 gboolean
1028 new_page(print_stream_t *self)
1029 {
1030         return (self->ops->new_page)(self);
1031 }
1032
1033 /* Some formats need stuff at the end of the output */
1034 gboolean
1035 print_finale(print_stream_t *self)
1036 {
1037         return (self->ops->print_finale)(self);
1038 }
1039
1040 gboolean
1041 destroy_print_stream(print_stream_t *self)
1042 {
1043         return (self->ops->destroy)(self);
1044 }
1045
1046 typedef struct {
1047         int to_file;
1048         FILE *fh;
1049 } output_text;
1050
1051 static gboolean
1052 print_preamble_text(print_stream_t *self _U_, gchar *filename _U_)
1053 {
1054         /* do nothing */
1055         return TRUE;    /* always succeeds */
1056 }
1057
1058 static gboolean
1059 print_line_text(print_stream_t *self, int indent, const char *line)
1060 {
1061         output_text *output = (output_text *)self->data;
1062         char space[MAX_INDENT+1];
1063         int i;
1064         int num_spaces;
1065
1066         /* Prepare the tabs for printing, depending on tree level */
1067         num_spaces = indent * 4;
1068         if (num_spaces > MAX_INDENT) {
1069                 num_spaces = MAX_INDENT;
1070         }
1071         for (i = 0; i < num_spaces; i++) {
1072                 space[i] = ' ';
1073         }
1074         /* The string is NUL-terminated */
1075         space[num_spaces] = '\0';
1076
1077         fputs(space, output->fh);
1078         fputs(line, output->fh);
1079         putc('\n', output->fh);
1080         return !ferror(output->fh);
1081 }
1082
1083 static gboolean
1084 print_bookmark_text(print_stream_t *self _U_, const gchar *name _U_,
1085     const gchar *title _U_)
1086 {
1087         /* do nothing */
1088         return TRUE;
1089 }
1090
1091 static gboolean
1092 new_page_text(print_stream_t *self)
1093 {
1094         output_text *output = (output_text *)self->data;
1095
1096         fputs("\f", output->fh);
1097         return !ferror(output->fh);
1098 }
1099
1100 static gboolean
1101 print_finale_text(print_stream_t *self _U_)
1102 {
1103         /* do nothing */
1104         return TRUE;    /* always succeeds */
1105 }
1106
1107 static gboolean
1108 destroy_text(print_stream_t *self)
1109 {
1110         output_text *output = (output_text *)self->data;
1111         gboolean ret;
1112
1113         ret = close_print_dest(output->to_file, output->fh);
1114         g_free(output);
1115         g_free(self);
1116         return ret;
1117 }
1118
1119 static const print_stream_ops_t print_text_ops = {
1120         print_preamble_text,
1121         print_line_text,
1122         print_bookmark_text,
1123         new_page_text,
1124         print_finale_text,
1125         destroy_text
1126 };
1127
1128 static print_stream_t *
1129 print_stream_text_alloc(int to_file, FILE *fh)
1130 {
1131         print_stream_t *stream;
1132         output_text *output;
1133
1134         output = (output_text *)g_malloc(sizeof *output);
1135         output->to_file = to_file;
1136         output->fh = fh;
1137         stream = (print_stream_t *)g_malloc(sizeof (print_stream_t));
1138         stream->ops = &print_text_ops;
1139         stream->data = output;
1140
1141         return stream;
1142 }
1143
1144 print_stream_t *
1145 print_stream_text_new(int to_file, const char *dest)
1146 {
1147         FILE *fh;
1148
1149         fh = open_print_dest(to_file, dest);
1150         if (fh == NULL)
1151                 return NULL;
1152
1153         return print_stream_text_alloc(to_file, fh);
1154 }
1155
1156 print_stream_t *
1157 print_stream_text_stdio_new(FILE *fh)
1158 {
1159         return print_stream_text_alloc(TRUE, fh);
1160 }
1161
1162 typedef struct {
1163         int to_file;
1164         FILE *fh;
1165 } output_ps;
1166
1167 static gboolean
1168 print_preamble_ps(print_stream_t *self, gchar *filename)
1169 {
1170         output_ps *output = (output_ps *)self->data;
1171         unsigned char psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */
1172
1173         print_ps_preamble(output->fh);
1174
1175         fputs("%% the page title\n", output->fh);
1176         ps_clean_string(psbuffer, filename, MAX_PS_LINE_LENGTH);
1177         fprintf(output->fh, "/ws_pagetitle (%s - Wireshark " VERSION "%s) def\n", psbuffer, wireshark_svnversion);
1178         fputs("\n", output->fh);
1179         return !ferror(output->fh);
1180 }
1181
1182 static gboolean
1183 print_line_ps(print_stream_t *self, int indent, const char *line)
1184 {
1185         output_ps *output = (output_ps *)self->data;
1186         unsigned char psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */
1187
1188         ps_clean_string(psbuffer, line, MAX_PS_LINE_LENGTH);
1189         fprintf(output->fh, "%d (%s) putline\n", indent, psbuffer);
1190         return !ferror(output->fh);
1191 }
1192
1193 static gboolean
1194 print_bookmark_ps(print_stream_t *self, const gchar *name, const gchar *title)
1195 {
1196         output_ps *output = (output_ps *)self->data;
1197         unsigned char psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */
1198
1199         /*
1200          * See the Adobe "pdfmark reference":
1201          *
1202          *      http://partners.adobe.com/asn/acrobat/docs/pdfmark.pdf
1203          *
1204          * The pdfmark stuff tells code that turns PostScript into PDF
1205          * things that it should do.
1206          *
1207          * The /OUT stuff creates a bookmark that goes to the
1208          * destination with "name" as the name and "title" as the title.
1209          *
1210          * The "/DEST" creates the destination.
1211          */
1212         ps_clean_string(psbuffer, title, MAX_PS_LINE_LENGTH);
1213         fprintf(output->fh, "[/Dest /%s /Title (%s)   /OUT pdfmark\n", name,
1214             psbuffer);
1215         fputs("[/View [/XYZ -4 currentpoint matrix currentmatrix matrix defaultmatrix\n",
1216             output->fh);
1217         fputs("matrix invertmatrix matrix concatmatrix transform exch pop 20 add null]\n",
1218             output->fh);
1219         fprintf(output->fh, "/Dest /%s /DEST pdfmark\n", name);
1220         return !ferror(output->fh);
1221 }
1222
1223 static gboolean
1224 new_page_ps(print_stream_t *self)
1225 {
1226         output_ps *output = (output_ps *)self->data;
1227
1228         fputs("formfeed\n", output->fh);
1229         return !ferror(output->fh);
1230 }
1231
1232 static gboolean
1233 print_finale_ps(print_stream_t *self)
1234 {
1235         output_ps *output = (output_ps *)self->data;
1236
1237         print_ps_finale(output->fh);
1238         return !ferror(output->fh);
1239 }
1240
1241 static gboolean
1242 destroy_ps(print_stream_t *self)
1243 {
1244         output_ps *output = (output_ps *)self->data;
1245         gboolean ret;
1246
1247         ret = close_print_dest(output->to_file, output->fh);
1248         g_free(output);
1249         g_free(self);
1250         return ret;
1251 }
1252
1253 static const print_stream_ops_t print_ps_ops = {
1254         print_preamble_ps,
1255         print_line_ps,
1256         print_bookmark_ps,
1257         new_page_ps,
1258         print_finale_ps,
1259         destroy_ps
1260 };
1261
1262 static print_stream_t *
1263 print_stream_ps_alloc(int to_file, FILE *fh)
1264 {
1265         print_stream_t *stream;
1266         output_ps *output;
1267
1268         output = (output_ps *)g_malloc(sizeof *output);
1269         output->to_file = to_file;
1270         output->fh = fh;
1271         stream = (print_stream_t *)g_malloc(sizeof (print_stream_t));
1272         stream->ops = &print_ps_ops;
1273         stream->data = output;
1274
1275         return stream;
1276 }
1277
1278 print_stream_t *
1279 print_stream_ps_new(int to_file, const char *dest)
1280 {
1281         FILE *fh;
1282
1283         fh = open_print_dest(to_file, dest);
1284         if (fh == NULL)
1285                 return NULL;
1286
1287         return print_stream_ps_alloc(to_file, fh);
1288 }
1289
1290 print_stream_t *
1291 print_stream_ps_stdio_new(FILE *fh)
1292 {
1293         return print_stream_ps_alloc(TRUE, fh);
1294 }
1295
1296 output_fields_t* output_fields_new(void)
1297 {
1298     output_fields_t* fields = g_new(output_fields_t, 1);
1299     fields->print_header = FALSE;
1300     fields->separator = '\t';
1301     fields->occurrence = 'a';
1302     fields->aggregator = ',';
1303     fields->fields = NULL; /*Do lazy initialisation */
1304     fields->field_indicies = NULL;
1305     fields->field_values = NULL;
1306     fields->quote='\0';
1307     return fields;
1308 }
1309
1310 gsize output_fields_num_fields(output_fields_t* fields)
1311 {
1312     g_assert(fields);
1313
1314     if(NULL == fields->fields) {
1315         return 0;
1316     } else {
1317         return fields->fields->len;
1318     }
1319 }
1320
1321 void output_fields_free(output_fields_t* fields)
1322 {
1323     g_assert(fields);
1324
1325     if(NULL != fields->field_indicies) {
1326         /* Keys are stored in fields->fields, values are
1327          * integers.
1328          */
1329         g_hash_table_destroy(fields->field_indicies);
1330     }
1331     if(NULL != fields->fields) {
1332         gsize i;
1333         for(i = 0; i < fields->fields->len; ++i) {
1334             gchar* field = (gchar *)g_ptr_array_index(fields->fields,i);
1335             g_free(field);
1336         }
1337         g_ptr_array_free(fields->fields, TRUE);
1338     }
1339
1340     g_free(fields);
1341 }
1342
1343 void output_fields_add(output_fields_t* fields, const gchar* field)
1344 {
1345     gchar* field_copy;
1346
1347     g_assert(fields);
1348     g_assert(field);
1349
1350
1351     if(NULL == fields->fields) {
1352         fields->fields = g_ptr_array_new();
1353     }
1354
1355     field_copy = g_strdup(field);
1356
1357     g_ptr_array_add(fields->fields, field_copy);
1358 }
1359
1360 gboolean output_fields_set_option(output_fields_t* info, gchar* option)
1361 {
1362     const gchar* option_name;
1363     const gchar* option_value;
1364
1365     g_assert(info);
1366     g_assert(option);
1367
1368     if('\0' == *option) {
1369         return FALSE; /* Is this guarded against by option parsing? */
1370     }
1371     option_name = strtok(option,"=");
1372     if (!option_name) {
1373         return FALSE;
1374     }
1375     option_value = option + strlen(option_name) + 1;
1376     if(0 == strcmp(option_name, "header")) {
1377         switch(NULL == option_value ? '\0' : *option_value) {
1378         case 'n':
1379             info->print_header = FALSE;
1380             break;
1381         case 'y':
1382             info->print_header = TRUE;
1383             break;
1384         default:
1385             return FALSE;
1386         }
1387         return TRUE;
1388     }
1389
1390     if(0 == strcmp(option_name,"separator")) {
1391         switch(NULL == option_value ? '\0' : *option_value) {
1392         case '\0':
1393             return FALSE;
1394         case '/':
1395             switch(*++option_value) {
1396             case 't':
1397                 info->separator = '\t';
1398                 break;
1399             case 's':
1400                 info->separator = ' ';
1401                 break;
1402             default:
1403                 info->separator = '\\';
1404             }
1405             break;
1406         default:
1407             info->separator = *option_value;
1408             break;
1409         }
1410         return TRUE;
1411     }
1412
1413     if(0 == strcmp(option_name, "occurrence")) {
1414         switch(NULL == option_value ? '\0' : *option_value) {
1415         case 'f':
1416         case 'l':
1417         case 'a':
1418             info->occurrence = *option_value;
1419             break;
1420         default:
1421             return FALSE;
1422         }
1423         return TRUE;
1424     }
1425
1426     if(0 == strcmp(option_name,"aggregator")) {
1427         switch(NULL == option_value ? '\0' : *option_value) {
1428         case '\0':
1429             return FALSE;
1430         case '/':
1431             switch(*++option_value) {
1432             case 's':
1433                 info->aggregator = ' ';
1434                 break;
1435             default:
1436                 info->aggregator = '\\';
1437             }
1438             break;
1439         default:
1440             info->aggregator = *option_value;
1441             break;
1442         }
1443         return TRUE;
1444     }
1445
1446     if(0 == strcmp(option_name, "quote")) {
1447         switch(NULL == option_value ? '\0' : *option_value) {
1448         default: /* Fall through */
1449         case '\0':
1450             info->quote='\0';
1451             return FALSE;
1452         case 'd':
1453             info->quote='"';
1454             break;
1455         case 's':
1456             info->quote='\'';
1457             break;
1458         case 'n':
1459             info->quote='\0';
1460             break;
1461         }
1462         return TRUE;
1463     }
1464
1465     return FALSE;
1466 }
1467
1468 void output_fields_list_options(FILE *fh)
1469 {
1470     fprintf(fh, "TShark: The available options for field output \"E\" are:\n");
1471     fputs("header=y|n    Print field abbreviations as first line of output (def: N: no)\n", fh);
1472     fputs("separator=/t|/s|<character>   Set the separator to use;\n     \"/t\" = tab, \"/s\" = space (def: /t: tab)\n", fh);
1473     fputs("occurrence=f|l|a  Select the occurrence of a field to use;\n     \"f\" = first, \"l\" = last, \"a\" = all (def: a: all)\n", fh);
1474     fputs("aggregator=,|/s|<character>   Set the aggregator to use;\n     \",\" = comma, \"/s\" = space (def: ,: comma)\n", fh);
1475     fputs("quote=d|s|n   Print either d: double-quotes, s: single quotes or \n     n: no quotes around field values (def: n: none)\n", fh);
1476 }
1477
1478
1479 void write_fields_preamble(output_fields_t* fields, FILE *fh)
1480 {
1481     gsize i;
1482
1483     g_assert(fields);
1484     g_assert(fh);
1485
1486     if(!fields->print_header) {
1487         return;
1488     }
1489
1490     for(i = 0; i < fields->fields->len; ++i) {
1491         const gchar* field = (const gchar *)g_ptr_array_index(fields->fields,i);
1492         if(i != 0 ) {
1493             fputc(fields->separator, fh);
1494         }
1495         fputs(field, fh);
1496     }
1497     fputc('\n', fh);
1498 }
1499
1500 static void proto_tree_get_node_field_values(proto_node *node, gpointer data)
1501 {
1502     write_field_data_t *call_data;
1503     field_info *fi;
1504     gpointer field_index;
1505
1506     call_data = (write_field_data_t *)data;
1507     fi = PNODE_FINFO(node);
1508
1509     g_assert(fi && "dissection with an invisible proto tree?");
1510
1511     field_index = g_hash_table_lookup(call_data->fields->field_indicies, fi->hfinfo->abbrev);
1512     if(NULL != field_index) {
1513         const gchar* value;
1514
1515         value = get_node_field_value(fi, call_data->edt); /* ep_alloced string */
1516
1517         if(NULL != value && '\0' != *value) {
1518             guint actual_index;
1519             actual_index = GPOINTER_TO_UINT(field_index);
1520             /* Unwrap change made to disambiguiate zero / null */
1521             if ( call_data->fields->field_values[actual_index - 1] == NULL ) {
1522                 call_data->fields->field_values[actual_index - 1] = ep_strbuf_new(value);
1523             } else if ( call_data->fields->occurrence == 'l' ) {
1524                 /* print only the value of the last occurrence of the field */
1525                 ep_strbuf_printf(call_data->fields->field_values[actual_index - 1],"%s",value);
1526             } else if ( call_data->fields->occurrence == 'a' ) {
1527                 /* print the value of all accurrences of the field */
1528                 ep_strbuf_append_printf(call_data->fields->field_values[actual_index - 1],
1529                     "%c%s",call_data->fields->aggregator,value);
1530             }
1531         }
1532     }
1533
1534     /* Recurse here. */
1535     if (node->first_child != NULL) {
1536         proto_tree_children_foreach(node, proto_tree_get_node_field_values,
1537                                     call_data);
1538     }
1539 }
1540
1541 void proto_tree_write_fields(output_fields_t* fields, epan_dissect_t *edt, FILE *fh)
1542 {
1543     gsize i;
1544
1545     write_field_data_t data;
1546
1547     g_assert(fields);
1548     g_assert(edt);
1549     g_assert(fh);
1550
1551     data.fields = fields;
1552     data.edt = edt;
1553
1554     if(NULL == fields->field_indicies) {
1555         /* Prepare a lookup table from string abbreviation for field to its index. */
1556         fields->field_indicies = g_hash_table_new(g_str_hash, g_str_equal);
1557
1558         i = 0;
1559         while( i < fields->fields->len) {
1560             gchar* field = (gchar *)g_ptr_array_index(fields->fields, i);
1561              /* Store field indicies +1 so that zero is not a valid value,
1562               * and can be distinguished from NULL as a pointer.
1563               */
1564             ++i;
1565             g_hash_table_insert(fields->field_indicies, field, GUINT_TO_POINTER(i));
1566         }
1567     }
1568
1569     /* Buffer to store values for this packet */
1570     fields->field_values = ep_alloc_array0(emem_strbuf_t*, fields->fields->len);
1571
1572     proto_tree_children_foreach(edt->tree, proto_tree_get_node_field_values,
1573                                 &data);
1574
1575     for(i = 0; i < fields->fields->len; ++i) {
1576         if(0 != i) {
1577             fputc(fields->separator, fh);
1578         }
1579         if(NULL != fields->field_values[i]) {
1580             if(fields->quote != '\0') {
1581                 fputc(fields->quote, fh);
1582             }
1583             fputs(fields->field_values[i]->str, fh);
1584             if(fields->quote != '\0') {
1585                 fputc(fields->quote, fh);
1586             }
1587         }
1588     }
1589 }
1590
1591 void write_fields_finale(output_fields_t* fields _U_ , FILE *fh _U_)
1592 {
1593     /* Nothing to do */
1594 }
1595
1596 /* Returns an ep_alloced string or a static constant*/
1597 const gchar* get_node_field_value(field_info* fi, epan_dissect_t* edt)
1598 {
1599     if (fi->hfinfo->id == hf_text_only) {
1600         /* Text label.
1601          * Get the text */
1602         if (fi->rep) {
1603             return fi->rep->representation;
1604         }
1605         else {
1606             return get_field_hex_value(edt->pi.data_src, fi);
1607         }
1608     }
1609     else if (fi->hfinfo->id == proto_data) {
1610         /* Uninterpreted data, i.e., the "Data" protocol, is
1611          * printed as a field instead of a protocol. */
1612         return get_field_hex_value(edt->pi.data_src, fi);
1613     }
1614     else {
1615         /* Normal protocols and fields */
1616         gchar      *dfilter_string;
1617         size_t      chop_len;
1618
1619         switch (fi->hfinfo->type)
1620         {
1621         case FT_PROTOCOL:
1622             /* Print out the full details for the protocol. */
1623             if (fi->rep) {
1624                 return fi->rep->representation;
1625             } else {
1626                 /* Just print out the protocol abbreviation */
1627                 return fi->hfinfo->abbrev;;
1628             }
1629         case FT_NONE:
1630             /* Return "1" so that the presence of a field of type
1631              * FT_NONE can be checked when using -T fields */
1632             return "1";
1633         default:
1634             /* XXX - this is a hack until we can just call
1635              * fvalue_to_string_repr() for *all* FT_* types. */
1636             dfilter_string = proto_construct_match_selected_string(fi,
1637                 edt);
1638             if (dfilter_string != NULL) {
1639                 chop_len = strlen(fi->hfinfo->abbrev) + 4; /* for " == " */
1640
1641                 /* XXX - Remove double-quotes. Again, once we
1642                  * can call fvalue_to_string_repr(), we can
1643                  * ask it not to produce the version for
1644                  * display-filters, and thus, no
1645                  * double-quotes. */
1646                 if (dfilter_string[strlen(dfilter_string)-1] == '"') {
1647                     dfilter_string[strlen(dfilter_string)-1] = '\0';
1648                     chop_len++;
1649                 }
1650
1651                 return &(dfilter_string[chop_len]);
1652             } else {
1653                 return get_field_hex_value(edt->pi.data_src, fi);
1654             }
1655         }
1656     }
1657 }
1658
1659 static const gchar*
1660 get_field_hex_value(GSList* src_list, field_info *fi)
1661 {
1662     const guint8 *pd;
1663
1664     if (!fi->ds_tvb)
1665         return NULL;
1666
1667     if (fi->length > tvb_length_remaining(fi->ds_tvb, fi->start)) {
1668         return "field length invalid!";
1669     }
1670
1671     /* Find the data for this field. */
1672     pd = get_field_data(src_list, fi);
1673
1674     if (pd) {
1675         int i;
1676         gchar* buffer;
1677         gchar* p;
1678         int len;
1679         const int chars_per_byte = 2;
1680
1681         len = chars_per_byte * fi->length;
1682         buffer = ep_alloc_array(gchar, len + 1);
1683         buffer[len] = '\0'; /* Ensure NULL termination in bad cases */
1684         p = buffer;
1685         /* Print a simple hex dump */
1686         for (i = 0 ; i < fi->length; i++) {
1687             g_snprintf(p, chars_per_byte+1, "%02x", pd[i]);
1688             p += chars_per_byte;
1689         }
1690         return buffer;
1691     } else {
1692         return NULL;
1693     }
1694 }