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