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