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