1 /* print.c
2  * Routines for printing packet analysis trees.
3  *
4  * Gilbert Ramirez <gram@alumni.rice.edu>
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * SPDX-License-Identifier: GPL-2.0-or-later
11  */
12 
13 #include "config.h"
14 
15 #include <stdio.h>
16 #include <string.h>
17 
18 #include <epan/packet.h>
19 #include <epan/epan.h>
20 #include <epan/epan_dissect.h>
21 #include <epan/to_str.h>
22 #include <epan/to_str.h>
23 #include <epan/expert.h>
24 #include <epan/column.h>
25 #include <epan/column-info.h>
26 #include <epan/color_filters.h>
27 #include <epan/prefs.h>
28 #include <epan/print.h>
29 #include <epan/charsets.h>
30 #include <wsutil/json_dumper.h>
31 #include <wsutil/filesystem.h>
32 #include <wsutil/utf8_entities.h>
33 #include <wsutil/ws_assert.h>
34 #include <ftypes/ftypes-int.h>
35 
36 #define PDML_VERSION "0"
37 #define PSML_VERSION "0"
38 
39 typedef struct {
40     int                  level;
41     print_stream_t      *stream;
42     gboolean             success;
43     GSList              *src_list;
44     print_dissections_e  print_dissections;
45     gboolean             print_hex_for_data;
46     packet_char_enc      encoding;
47     GHashTable          *output_only_tables; /* output only these protocols */
48 } print_data;
49 
50 typedef struct {
51     int             level;
52     FILE           *fh;
53     GSList         *src_list;
54     gchar         **filter;
55     pf_flags        filter_flags;
56 } write_pdml_data;
57 
58 typedef struct {
59     GSList         *src_list;
60     gchar         **filter;
61     pf_flags        filter_flags;
62     gboolean        print_hex;
63     gboolean        print_text;
64     proto_node_children_grouper_func node_children_grouper;
65     json_dumper    *dumper;
66 } write_json_data;
67 
68 typedef struct {
69     output_fields_t *fields;
70     epan_dissect_t  *edt;
71 } write_field_data_t;
72 
73 struct _output_fields {
74     gboolean      print_bom;
75     gboolean      print_header;
76     gchar         separator;
77     gchar         occurrence;
78     gchar         aggregator;
79     GPtrArray    *fields;
80     GHashTable   *field_indicies;
81     GPtrArray   **field_values;
82     gchar         quote;
83     gboolean      includes_col_fields;
84 };
85 
86 static gchar *get_field_hex_value(GSList *src_list, field_info *fi);
87 static void proto_tree_print_node(proto_node *node, gpointer data);
88 static void proto_tree_write_node_pdml(proto_node *node, gpointer data);
89 static void proto_tree_write_node_ek(proto_node *node, write_json_data *data);
90 static const guint8 *get_field_data(GSList *src_list, field_info *fi);
91 static void pdml_write_field_hex_value(write_pdml_data *pdata, field_info *fi);
92 static void json_write_field_hex_value(write_json_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 write_specified_fields(fields_format format,
96                                    output_fields_t *fields,
97                                    epan_dissect_t *edt, column_info *cinfo,
98                                    FILE *fh,
99                                    json_dumper *dumper);
100 static void print_escaped_xml(FILE *fh, const char *unescaped_string);
101 static void print_escaped_csv(FILE *fh, const char *unescaped_string);
102 
103 typedef void (*proto_node_value_writer)(proto_node *, write_json_data *);
104 static void write_json_index(json_dumper *dumper, epan_dissect_t *edt);
105 static void write_json_proto_node_list(GSList *proto_node_list_head, write_json_data *data);
106 static void write_json_proto_node(GSList *node_values_head,
107                                   const char *suffix,
108                                   proto_node_value_writer value_writer,
109                                   write_json_data *data);
110 static void write_json_proto_node_value_list(GSList *node_values_head,
111                                              proto_node_value_writer value_writer,
112                                              write_json_data *data);
113 static void write_json_proto_node_filtered(proto_node *node, write_json_data *data);
114 static void write_json_proto_node_hex_dump(proto_node *node, write_json_data *data);
115 static void write_json_proto_node_dynamic(proto_node *node, write_json_data *data);
116 static void write_json_proto_node_children(proto_node *node, write_json_data *data);
117 static void write_json_proto_node_value(proto_node *node, write_json_data *data);
118 static void write_json_proto_node_no_value(proto_node *node, write_json_data *data);
119 static const char *proto_node_to_json_key(proto_node *node);
120 
121 static void print_pdml_geninfo(epan_dissect_t *edt, FILE *fh);
122 static void write_ek_summary(column_info *cinfo, write_json_data *pdata);
123 
124 static void proto_tree_get_node_field_values(proto_node *node, gpointer data);
125 
126 /* Cache the protocols and field handles that the print functionality needs
127    This helps break explicit dependency on the dissectors. */
128 static int proto_data = -1;
129 static int proto_frame = -1;
130 
print_cache_field_handles(void)131 void print_cache_field_handles(void)
132 {
133     proto_data = proto_get_id_by_short_name("Data");
134     proto_frame = proto_get_id_by_short_name("Frame");
135 }
136 
137 gboolean
proto_tree_print(print_dissections_e print_dissections,gboolean print_hex,epan_dissect_t * edt,GHashTable * output_only_tables,print_stream_t * stream)138 proto_tree_print(print_dissections_e print_dissections, gboolean print_hex,
139                  epan_dissect_t *edt, GHashTable *output_only_tables,
140                  print_stream_t *stream)
141 {
142     print_data data;
143 
144     /* Create the output */
145     data.level              = 0;
146     data.stream             = stream;
147     data.success            = TRUE;
148     data.src_list           = edt->pi.data_src;
149     data.encoding           = (packet_char_enc)edt->pi.fd->encoding;
150     data.print_dissections  = print_dissections;
151     /* If we're printing the entire packet in hex, don't
152        print uninterpreted data fields in hex as well. */
153     data.print_hex_for_data = !print_hex;
154     data.output_only_tables = output_only_tables;
155 
156     proto_tree_children_foreach(edt->tree, proto_tree_print_node, &data);
157     return data.success;
158 }
159 
160 /* Print a tree's data, and any child nodes. */
161 static void
proto_tree_print_node(proto_node * node,gpointer data)162 proto_tree_print_node(proto_node *node, gpointer data)
163 {
164     field_info   *fi    = PNODE_FINFO(node);
165     print_data   *pdata = (print_data*) data;
166     const guint8 *pd;
167     gchar         label_str[ITEM_LABEL_LENGTH];
168     gchar        *label_ptr;
169 
170     /* dissection with an invisible proto tree? */
171     ws_assert(fi);
172 
173     /* Don't print invisible entries. */
174     if (proto_item_is_hidden(node) && (prefs.display_hidden_proto_items == FALSE))
175         return;
176 
177     /* Give up if we've already gotten an error. */
178     if (!pdata->success)
179         return;
180 
181     /* was a free format label produced? */
182     if (fi->rep) {
183         label_ptr = fi->rep->representation;
184     }
185     else { /* no, make a generic label */
186         label_ptr = label_str;
187         proto_item_fill_label(fi, label_str);
188     }
189 
190     if (proto_item_is_generated(node))
191         label_ptr = g_strconcat("[", label_ptr, "]", NULL);
192 
193     pdata->success = print_line(pdata->stream, pdata->level, label_ptr);
194 
195     if (proto_item_is_generated(node))
196         g_free(label_ptr);
197 
198     if (!pdata->success)
199         return;
200 
201     /*
202      * If -O is specified, only display the protocols which are in the
203      * lookup table.  Only check on the first level: once we start printing
204      * a tree, print the rest of the subtree.  Otherwise we won't print
205      * subitems whose abbreviation doesn't match the protocol--for example
206      * text items (whose abbreviation is simply "text").
207      */
208     if ((pdata->output_only_tables != NULL) && (pdata->level == 0)
209         && (g_hash_table_lookup(pdata->output_only_tables, fi->hfinfo->abbrev) == NULL)) {
210         return;
211     }
212 
213     /* If it's uninterpreted data, dump it (unless our caller will
214        be printing the entire packet in hex). */
215     if ((fi->hfinfo->id == proto_data) && (pdata->print_hex_for_data)) {
216         /*
217          * Find the data for this field.
218          */
219         pd = get_field_data(pdata->src_list, fi);
220         if (pd) {
221             if (!print_line(pdata->stream, 0, "")) {
222                 pdata->success = FALSE;
223                 return;
224             }
225             if (!print_hex_data_buffer(pdata->stream, pd,
226                                        fi->length, pdata->encoding)) {
227                 pdata->success = FALSE;
228                 return;
229             }
230         }
231     }
232 
233     /* If we're printing all levels, or if this node is one with a
234        subtree and its subtree is expanded, recurse into the subtree,
235        if it exists. */
236     ws_assert((fi->tree_type >= -1) && (fi->tree_type < num_tree_types));
237     if ((pdata->print_dissections == print_dissections_expanded) ||
238         ((pdata->print_dissections == print_dissections_as_displayed) &&
239          (fi->tree_type >= 0) && tree_expanded(fi->tree_type))) {
240         if (node->first_child != NULL) {
241             pdata->level++;
242             proto_tree_children_foreach(node,
243                                         proto_tree_print_node, pdata);
244             pdata->level--;
245             if (!pdata->success)
246                 return;
247         }
248     }
249 }
250 
251 #define PDML2HTML_XSL "pdml2html.xsl"
252 void
write_pdml_preamble(FILE * fh,const gchar * filename)253 write_pdml_preamble(FILE *fh, const gchar *filename)
254 {
255     time_t t = time(NULL);
256     struct tm * timeinfo;
257     char *fmt_ts;
258     const char *ts;
259 
260     /* Create the output */
261     timeinfo = localtime(&t);
262     if (timeinfo != NULL) {
263         fmt_ts = asctime(timeinfo);
264         fmt_ts[strlen(fmt_ts)-1] = 0; /* overwrite \n */
265         ts = fmt_ts;
266     } else
267         ts = "Not representable";
268 
269     fprintf(fh, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
270     fprintf(fh, "<?xml-stylesheet type=\"text/xsl\" href=\"" PDML2HTML_XSL "\"?>\n");
271     fprintf(fh, "<!-- You can find " PDML2HTML_XSL " in %s or at https://gitlab.com/wireshark/wireshark/-/raw/master/" PDML2HTML_XSL ". -->\n", get_datafile_dir());
272     fprintf(fh, "<pdml version=\"" PDML_VERSION "\" creator=\"%s/%s\" time=\"%s\" capture_file=\"", PACKAGE, VERSION, ts);
273     if (filename) {
274         /* \todo filename should be converted to UTF-8. */
275         print_escaped_xml(fh, filename);
276     }
277     fprintf(fh, "\">\n");
278 }
279 
280 /* Check if the str match the protocolfilter. json_filter is space
281    delimited string and str need to exact-match to one of the value. */
check_protocolfilter(gchar ** protocolfilter,const char * str)282 static gboolean check_protocolfilter(gchar **protocolfilter, const char *str)
283 {
284     gboolean res = FALSE;
285     gchar **ptr;
286 
287     if (str == NULL || protocolfilter == NULL) {
288         return FALSE;
289     }
290 
291     for (ptr = protocolfilter; *ptr; ptr++) {
292         if (strcmp(*ptr, str) == 0) {
293             res = TRUE;
294             break;
295         }
296     }
297 
298     return res;
299 }
300 
301 void
write_pdml_proto_tree(output_fields_t * fields,gchar ** protocolfilter,pf_flags protocolfilter_flags,epan_dissect_t * edt,column_info * cinfo,FILE * fh,gboolean use_color)302 write_pdml_proto_tree(output_fields_t* fields, gchar **protocolfilter, pf_flags protocolfilter_flags, epan_dissect_t *edt, column_info *cinfo, FILE *fh, gboolean use_color)
303 {
304     write_pdml_data data;
305     const color_filter_t *cfp;
306 
307     ws_assert(edt);
308     ws_assert(fh);
309 
310     cfp = edt->pi.fd->color_filter;
311 
312     /* Create the output */
313     if (use_color && (cfp != NULL)) {
314         fprintf(fh, "<packet foreground='#%06x' background='#%06x'>\n",
315             color_t_to_rgb(&cfp->fg_color),
316             color_t_to_rgb(&cfp->bg_color));
317     } else {
318         fprintf(fh, "<packet>\n");
319     }
320 
321     /* Print a "geninfo" protocol as required by PDML */
322     print_pdml_geninfo(edt, fh);
323 
324     if (fields == NULL || fields->fields == NULL) {
325         /* Write out all fields */
326         data.level    = 0;
327         data.fh       = fh;
328         data.src_list = edt->pi.data_src;
329         data.filter   = protocolfilter;
330         data.filter_flags   = protocolfilter_flags;
331 
332         proto_tree_children_foreach(edt->tree, proto_tree_write_node_pdml,
333                                     &data);
334     } else {
335         /* Write out specified fields */
336         write_specified_fields(FORMAT_XML, fields, edt, cinfo, fh, NULL);
337     }
338 
339     fprintf(fh, "</packet>\n\n");
340 }
341 
342 void
write_ek_proto_tree(output_fields_t * fields,gboolean print_summary,gboolean print_hex,gchar ** protocolfilter,pf_flags protocolfilter_flags,epan_dissect_t * edt,column_info * cinfo,FILE * fh)343 write_ek_proto_tree(output_fields_t* fields,
344                     gboolean print_summary, gboolean print_hex,
345                     gchar **protocolfilter,
346                     pf_flags protocolfilter_flags, epan_dissect_t *edt,
347                     column_info *cinfo,
348                     FILE *fh)
349 {
350     ws_assert(edt);
351     ws_assert(fh);
352 
353     write_json_data data;
354 
355     json_dumper dumper = {
356         .output_file = fh,
357         .flags = JSON_DUMPER_DOT_TO_UNDERSCORE
358     };
359 
360     data.dumper = &dumper;
361 
362     json_dumper_begin_object(&dumper);
363     json_dumper_set_member_name(&dumper, "index");
364     json_dumper_begin_object(&dumper);
365     write_json_index(&dumper, edt);
366     json_dumper_set_member_name(&dumper, "_type");
367     json_dumper_value_string(&dumper, "doc");
368     json_dumper_end_object(&dumper);
369     json_dumper_end_object(&dumper);
370     json_dumper_finish(&dumper);
371     json_dumper_begin_object(&dumper);
372 
373     /* Timestamp added for time indexing in Elasticsearch */
374     json_dumper_set_member_name(&dumper, "timestamp");
375     json_dumper_value_anyf(&dumper, "\"%" G_GUINT64_FORMAT "%03d\"", (guint64)edt->pi.abs_ts.secs, edt->pi.abs_ts.nsecs/1000000);
376 
377     if (print_summary)
378         write_ek_summary(edt->pi.cinfo, &data);
379 
380     if (edt->tree) {
381         json_dumper_set_member_name(&dumper, "layers");
382         json_dumper_begin_object(&dumper);
383 
384         if (fields == NULL || fields->fields == NULL) {
385             /* Write out all fields */
386             data.src_list = edt->pi.data_src;
387             data.filter = protocolfilter;
388             data.filter_flags = protocolfilter_flags;
389             data.print_hex = print_hex;
390             proto_tree_write_node_ek(edt->tree, &data);
391         } else {
392             /* Write out specified fields */
393             write_specified_fields(FORMAT_EK, fields, edt, cinfo, NULL, data.dumper);
394         }
395 
396         json_dumper_end_object(&dumper);
397     }
398     json_dumper_end_object(&dumper);
399     json_dumper_finish(&dumper);
400 }
401 
402 void
write_fields_proto_tree(output_fields_t * fields,epan_dissect_t * edt,column_info * cinfo,FILE * fh)403 write_fields_proto_tree(output_fields_t* fields, epan_dissect_t *edt, column_info *cinfo, FILE *fh)
404 {
405     ws_assert(edt);
406     ws_assert(fh);
407 
408     /* Create the output */
409     write_specified_fields(FORMAT_CSV, fields, edt, cinfo, fh, NULL);
410 }
411 
412 /* Indent to the correct level */
print_indent(int level,FILE * fh)413 static void print_indent(int level, FILE *fh)
414 {
415     /* Use a buffer pre-filed with spaces */
416 #define MAX_INDENT 2048
417     static char spaces[MAX_INDENT];
418     static gboolean inited = FALSE;
419     if (!inited) {
420         for (int n=0; n < MAX_INDENT; n++) {
421             spaces[n] = ' ';
422         }
423         inited = TRUE;
424     }
425 
426     if (fh == NULL) {
427         return;
428     }
429 
430     /* Temp terminate at right length and write to fh. */
431     spaces[MIN(level*2, MAX_INDENT-1)] ='\0';
432     fputs(spaces, fh);
433     spaces[MIN(level*2, MAX_INDENT-1)] =' ';
434 }
435 
436 /* Write out a tree's data, and any child nodes, as PDML */
437 static void
proto_tree_write_node_pdml(proto_node * node,gpointer data)438 proto_tree_write_node_pdml(proto_node *node, gpointer data)
439 {
440     field_info      *fi    = PNODE_FINFO(node);
441     write_pdml_data *pdata = (write_pdml_data*) data;
442     const gchar     *label_ptr;
443     gchar            label_str[ITEM_LABEL_LENGTH];
444     char            *dfilter_string;
445     gboolean         wrap_in_fake_protocol;
446 
447     /* dissection with an invisible proto tree? */
448     ws_assert(fi);
449 
450     /* Will wrap up top-level field items inside a fake protocol wrapper to
451        preserve the PDML schema */
452     wrap_in_fake_protocol =
453         (((fi->hfinfo->type != FT_PROTOCOL) ||
454           (fi->hfinfo->id == proto_data)) &&
455          (pdata->level == 0));
456 
457     print_indent(pdata->level + 1, pdata->fh);
458 
459     if (wrap_in_fake_protocol) {
460         /* Open fake protocol wrapper */
461         fputs("<proto name=\"fake-field-wrapper\">\n", pdata->fh);
462         pdata->level++;
463 
464         print_indent(pdata->level + 1, pdata->fh);
465     }
466 
467     /* Text label. It's printed as a field with no name. */
468     if (fi->hfinfo->id == hf_text_only) {
469         /* Get the text */
470         if (fi->rep) {
471             label_ptr = fi->rep->representation;
472         } else {
473             label_ptr = "";
474         }
475 
476         /* Show empty name since it is a required field */
477         fputs("<field name=\"", pdata->fh);
478         fputs("\" show=\"", pdata->fh);
479         print_escaped_xml(pdata->fh, label_ptr);
480 
481         fprintf(pdata->fh, "\" size=\"%d", fi->length);
482         if (node->parent && node->parent->finfo && (fi->start < node->parent->finfo->start)) {
483             fprintf(pdata->fh, "\" pos=\"%d", node->parent->finfo->start + fi->start);
484         } else {
485             fprintf(pdata->fh, "\" pos=\"%d", fi->start);
486         }
487 
488         if (fi->length > 0) {
489             fputs("\" value=\"", pdata->fh);
490             pdml_write_field_hex_value(pdata, fi);
491         }
492 
493         if (node->first_child != NULL) {
494             fputs("\">\n", pdata->fh);
495         } else {
496             fputs("\"/>\n", pdata->fh);
497         }
498     }
499 
500     /* Uninterpreted data, i.e., the "Data" protocol, is
501      * printed as a field instead of a protocol. */
502     else if (fi->hfinfo->id == proto_data) {
503         /* Write out field with data */
504         fputs("<field name=\"data\" value=\"", pdata->fh);
505         pdml_write_field_hex_value(pdata, fi);
506         fputs("\">\n", pdata->fh);
507     } else {
508         /* Normal protocols and fields */
509         if ((fi->hfinfo->type == FT_PROTOCOL) && (fi->hfinfo->id != proto_expert)) {
510             fputs("<proto name=\"", pdata->fh);
511         } else {
512             fputs("<field name=\"", pdata->fh);
513         }
514         print_escaped_xml(pdata->fh, fi->hfinfo->abbrev);
515 
516 #if 0
517         /* PDML spec, see:
518          * https://wayback.archive.org/web/20150330045501/http://www.nbee.org/doku.php?id=netpdl:pdml_specification
519          *
520          * the show fields contains things in 'human readable' format
521          * showname: contains only the name of the field
522          * show: contains only the data of the field
523          * showdtl: contains additional details of the field data
524          * showmap: contains mappings of the field data (e.g. the hostname to an IP address)
525          *
526          * XXX - the showname shouldn't contain the field data itself
527          * (like it's contained in the fi->rep->representation).
528          * Unfortunately, we don't have the field data representation for
529          * all fields, so this isn't currently possible */
530         fputs("\" showname=\"", pdata->fh);
531         print_escaped_xml(pdata->fh, fi->hfinfo->name);
532 #endif
533 
534         if (fi->rep) {
535             fputs("\" showname=\"", pdata->fh);
536             print_escaped_xml(pdata->fh, fi->rep->representation);
537         } else {
538             label_ptr = label_str;
539             proto_item_fill_label(fi, label_str);
540             fputs("\" showname=\"", pdata->fh);
541             print_escaped_xml(pdata->fh, label_ptr);
542         }
543 
544         if (proto_item_is_hidden(node) && (prefs.display_hidden_proto_items == FALSE))
545             fprintf(pdata->fh, "\" hide=\"yes");
546 
547         fprintf(pdata->fh, "\" size=\"%d", fi->length);
548         if (node->parent && node->parent->finfo && (fi->start < node->parent->finfo->start)) {
549             fprintf(pdata->fh, "\" pos=\"%d", node->parent->finfo->start + fi->start);
550         } else {
551             fprintf(pdata->fh, "\" pos=\"%d", fi->start);
552         }
553 /*      fprintf(pdata->fh, "\" id=\"%d", fi->hfinfo->id);*/
554 
555         /* show, value, and unmaskedvalue attributes */
556         switch (fi->hfinfo->type)
557         {
558         case FT_PROTOCOL:
559             break;
560         case FT_NONE:
561             fputs("\" show=\"\" value=\"",  pdata->fh);
562             break;
563         default:
564             dfilter_string = fvalue_to_string_repr(NULL, &fi->value, FTREPR_DISPLAY, fi->hfinfo->display);
565             if (dfilter_string != NULL) {
566 
567                 fputs("\" show=\"", pdata->fh);
568                 print_escaped_xml(pdata->fh, dfilter_string);
569             }
570             wmem_free(NULL, dfilter_string);
571 
572             /*
573              * XXX - should we omit "value" for any fields?
574              * What should we do for fields whose length is 0?
575              * They might come from a pseudo-header or from
576              * the capture header (e.g., time stamps), or
577              * they might be generated fields.
578              */
579             if (fi->length > 0) {
580                 fputs("\" value=\"", pdata->fh);
581 
582                 if (fi->hfinfo->bitmask!=0) {
583                     switch (fi->value.ftype->ftype) {
584                         case FT_INT8:
585                         case FT_INT16:
586                         case FT_INT24:
587                         case FT_INT32:
588                             fprintf(pdata->fh, "%X", (guint) fvalue_get_sinteger(&fi->value));
589                             break;
590                         case FT_CHAR:
591                         case FT_UINT8:
592                         case FT_UINT16:
593                         case FT_UINT24:
594                         case FT_UINT32:
595                             fprintf(pdata->fh, "%X", fvalue_get_uinteger(&fi->value));
596                             break;
597                         case FT_INT40:
598                         case FT_INT48:
599                         case FT_INT56:
600                         case FT_INT64:
601                             fprintf(pdata->fh, "%" G_GINT64_MODIFIER "X", fvalue_get_sinteger64(&fi->value));
602                             break;
603                         case FT_UINT40:
604                         case FT_UINT48:
605                         case FT_UINT56:
606                         case FT_UINT64:
607                         case FT_BOOLEAN:
608                             fprintf(pdata->fh, "%" G_GINT64_MODIFIER "X", fvalue_get_uinteger64(&fi->value));
609                             break;
610                         default:
611                             ws_assert_not_reached();
612                     }
613                     fputs("\" unmaskedvalue=\"", pdata->fh);
614                     pdml_write_field_hex_value(pdata, fi);
615                 } else {
616                     pdml_write_field_hex_value(pdata, fi);
617                 }
618             }
619         }
620 
621         if (node->first_child != NULL) {
622             fputs("\">\n", pdata->fh);
623         } else if (fi->hfinfo->id == proto_data) {
624             fputs("\">\n", pdata->fh);
625         } else {
626             fputs("\"/>\n", pdata->fh);
627         }
628     }
629 
630     /* We print some levels for PDML. Recurse here. */
631     if (node->first_child != NULL) {
632         if (pdata->filter == NULL || check_protocolfilter(pdata->filter, fi->hfinfo->abbrev)) {
633             gchar **_filter = NULL;
634             /* Remove protocol filter for children, if children should be included */
635             if ((pdata->filter_flags&PF_INCLUDE_CHILDREN) == PF_INCLUDE_CHILDREN) {
636                 _filter = pdata->filter;
637                 pdata->filter = NULL;
638             }
639 
640             pdata->level++;
641             proto_tree_children_foreach(node,
642                                         proto_tree_write_node_pdml, pdata);
643             pdata->level--;
644 
645             /* Put protocol filter back */
646             if ((pdata->filter_flags&PF_INCLUDE_CHILDREN) == PF_INCLUDE_CHILDREN) {
647                 pdata->filter = _filter;
648             }
649         } else {
650             print_indent(pdata->level + 2, pdata->fh);
651 
652             /* print dummy field */
653             fputs("<field name=\"filtered\" value=\"", pdata->fh);
654             print_escaped_xml(pdata->fh, fi->hfinfo->abbrev);
655             fputs("\" />\n", pdata->fh);
656         }
657     }
658 
659     /* Take back the extra level we added for fake wrapper protocol */
660     if (wrap_in_fake_protocol) {
661         pdata->level--;
662     }
663 
664     if (node->first_child != NULL) {
665         print_indent(pdata->level + 1, pdata->fh);
666 
667         /* Close off current element */
668         /* Data and expert "protocols" use simple tags */
669         if ((fi->hfinfo->id != proto_data) && (fi->hfinfo->id != proto_expert)) {
670             if (fi->hfinfo->type == FT_PROTOCOL) {
671                 fputs("</proto>\n", pdata->fh);
672             } else {
673                 fputs("</field>\n", pdata->fh);
674             }
675         } else {
676             fputs("</field>\n", pdata->fh);
677         }
678     }
679 
680     /* Close off fake wrapper protocol */
681     if (wrap_in_fake_protocol) {
682         print_indent(pdata->level + 1, pdata->fh);
683         fputs("</proto>\n", pdata->fh);
684     }
685 }
686 
687 json_dumper
write_json_preamble(FILE * fh)688 write_json_preamble(FILE *fh)
689 {
690     json_dumper dumper = {
691         .output_file = fh,
692         .flags = JSON_DUMPER_FLAGS_PRETTY_PRINT
693     };
694     json_dumper_begin_array(&dumper);
695     return dumper;
696 }
697 
698 void
write_json_finale(json_dumper * dumper)699 write_json_finale(json_dumper *dumper)
700 {
701     json_dumper_end_array(dumper);
702     json_dumper_finish(dumper);
703 }
704 
705 static void
write_json_index(json_dumper * dumper,epan_dissect_t * edt)706 write_json_index(json_dumper *dumper, epan_dissect_t *edt)
707 {
708     char ts[30];
709     struct tm * timeinfo;
710     gchar* str;
711 
712     timeinfo = localtime(&edt->pi.abs_ts.secs);
713     if (timeinfo != NULL) {
714         strftime(ts, sizeof(ts), "%Y-%m-%d", timeinfo);
715     } else {
716         (void) g_strlcpy(ts, "XXXX-XX-XX", sizeof(ts)); /* XXX - better way of saying "Not representable"? */
717     }
718     json_dumper_set_member_name(dumper, "_index");
719     str = g_strdup_printf("packets-%s", ts);
720     json_dumper_value_string(dumper, str);
721     g_free(str);
722 }
723 
724 void
write_json_proto_tree(output_fields_t * fields,print_dissections_e print_dissections,gboolean print_hex,gchar ** protocolfilter,pf_flags protocolfilter_flags,epan_dissect_t * edt,column_info * cinfo,proto_node_children_grouper_func node_children_grouper,json_dumper * dumper)725 write_json_proto_tree(output_fields_t* fields,
726                       print_dissections_e print_dissections,
727                       gboolean print_hex, gchar **protocolfilter,
728                       pf_flags protocolfilter_flags, epan_dissect_t *edt,
729                       column_info *cinfo,
730                       proto_node_children_grouper_func node_children_grouper,
731                       json_dumper *dumper)
732 {
733     write_json_data data;
734 
735     data.dumper = dumper;
736 
737     json_dumper_begin_object(dumper);
738     write_json_index(dumper, edt);
739     json_dumper_set_member_name(dumper, "_type");
740     json_dumper_value_string(dumper, "doc");
741     json_dumper_set_member_name(dumper, "_score");
742     json_dumper_value_string(dumper, NULL);
743     json_dumper_set_member_name(dumper, "_source");
744     json_dumper_begin_object(dumper);
745     json_dumper_set_member_name(dumper, "layers");
746 
747     if (fields == NULL || fields->fields == NULL) {
748         /* Write out all fields */
749         data.src_list = edt->pi.data_src;
750         data.filter = protocolfilter;
751         data.filter_flags = protocolfilter_flags;
752         data.print_hex = print_hex;
753         data.print_text = TRUE;
754         if (print_dissections == print_dissections_none) {
755             data.print_text = FALSE;
756         }
757         data.node_children_grouper = node_children_grouper;
758 
759         write_json_proto_node_children(edt->tree, &data);
760     } else {
761         write_specified_fields(FORMAT_JSON, fields, edt, cinfo, NULL, dumper);
762     }
763 
764     json_dumper_end_object(dumper);
765     json_dumper_end_object(dumper);
766 }
767 
768 /**
769  * Returns a boolean telling us whether that node list contains any node which has children
770  */
771 static gboolean
any_has_children(GSList * node_values_list)772 any_has_children(GSList *node_values_list)
773 {
774     GSList *current_node = node_values_list;
775     while (current_node != NULL) {
776         proto_node *current_value = (proto_node *) current_node->data;
777         if (current_value->first_child != NULL) {
778             return TRUE;
779         }
780         current_node = current_node->next;
781     }
782     return FALSE;
783 }
784 
785 /**
786  * Write a json object containing a list of key:value pairs where each key:value pair corresponds to a different json
787  * key and its associated nodes in the proto_tree.
788  * @param proto_node_list_head A 2-dimensional list containing a list of values for each different node json key. The
789  * elements themselves are a linked list of values associated with the same json key.
790  * @param pdata json writing metadata
791  */
792 static void
write_json_proto_node_list(GSList * proto_node_list_head,write_json_data * pdata)793 write_json_proto_node_list(GSList *proto_node_list_head, write_json_data *pdata)
794 {
795     GSList *current_node = proto_node_list_head;
796 
797     json_dumper_begin_object(pdata->dumper);
798 
799     // Loop over each list of nodes (differentiated by json key) and write the associated json key:value pair in the
800     // output.
801     while (current_node != NULL) {
802         // Get the list of values for the current json key.
803         GSList *node_values_list = (GSList *) current_node->data;
804 
805         // Retrieve the json key from the first value.
806         proto_node *first_value = (proto_node *) node_values_list->data;
807         const char *json_key = proto_node_to_json_key(first_value);
808         // Check if the current json key is filtered from the output with the "-j" cli option.
809         gboolean is_filtered = pdata->filter != NULL && !check_protocolfilter(pdata->filter, json_key);
810 
811         field_info *fi = first_value->finfo;
812         char *value_string_repr = fvalue_to_string_repr(NULL, &fi->value, FTREPR_DISPLAY, fi->hfinfo->display);
813         gboolean has_children = any_has_children(node_values_list);
814 
815         // We assume all values of a json key have roughly the same layout. Thus we can use the first value to derive
816         // attributes of all the values.
817         gboolean has_value = value_string_repr != NULL;
818         gboolean is_pseudo_text_field = fi->hfinfo->id == 0;
819 
820         wmem_free(NULL, value_string_repr); // fvalue_to_string_repr returns allocated buffer
821 
822         // "-x" command line option. A "_raw" suffix is added to the json key so the textual value can be printed
823         // with the original json key. If both hex and text writing are enabled the raw information of fields whose
824         // length is equal to 0 is not written to the output. If the field is a special text pseudo field no raw
825         // information is written either.
826         if (pdata->print_hex && (!pdata->print_text || fi->length > 0) && !is_pseudo_text_field) {
827             write_json_proto_node(node_values_list, "_raw", write_json_proto_node_hex_dump, pdata);
828         }
829 
830         if (pdata->print_text && has_value) {
831             write_json_proto_node(node_values_list, "", write_json_proto_node_value, pdata);
832         }
833 
834         if (has_children) {
835             // If a node has both a value and a set of children we print the value and the children in separate
836             // key:value pairs. These can't have the same key so whenever a value is already printed with the node
837             // json key we print the children with the same key with a "_tree" suffix added.
838             char *suffix = has_value ? "_tree": "";
839 
840             if (is_filtered) {
841                 write_json_proto_node(node_values_list, suffix, write_json_proto_node_filtered, pdata);
842             } else {
843                 // Remove protocol filter for children, if children should be included. This functionality is enabled
844                 // with the "-J" command line option. We save the filter so it can be reenabled when we are done with
845                 // the current key:value pair.
846                 gchar **_filter = NULL;
847                 if ((pdata->filter_flags&PF_INCLUDE_CHILDREN) == PF_INCLUDE_CHILDREN) {
848                     _filter = pdata->filter;
849                     pdata->filter = NULL;
850                 }
851 
852                 // has_children is TRUE if any of the nodes have children. So we're not 100% sure whether this
853                 // particular node has children or not => use the 'dynamic' version of 'write_json_proto_node'
854                 write_json_proto_node(node_values_list, suffix, write_json_proto_node_dynamic, pdata);
855 
856                 // Put protocol filter back
857                 if ((pdata->filter_flags&PF_INCLUDE_CHILDREN) == PF_INCLUDE_CHILDREN) {
858                     pdata->filter = _filter;
859                 }
860             }
861         }
862 
863         if (!has_value && !has_children && (pdata->print_text || (pdata->print_hex && is_pseudo_text_field))) {
864             write_json_proto_node(node_values_list, "", write_json_proto_node_no_value, pdata);
865         }
866 
867         current_node = current_node->next;
868     }
869     json_dumper_end_object(pdata->dumper);
870 }
871 
872 /**
873  * Writes a single node as a key:value pair. The value_writer param can be used to specify how the node's value should
874  * be written.
875  * @param node_values_head Linked list containing all nodes associated with the same json key in this object.
876  * @param suffix Suffix that should be added to the json key.
877  * @param value_writer A function which writes the actual values of the node json key.
878  * @param pdata json writing metadata
879  */
880 static void
write_json_proto_node(GSList * node_values_head,const char * suffix,proto_node_value_writer value_writer,write_json_data * pdata)881 write_json_proto_node(GSList *node_values_head,
882                       const char *suffix,
883                       proto_node_value_writer value_writer,
884                       write_json_data *pdata)
885 {
886     // Retrieve json key from first value.
887     proto_node *first_value = (proto_node *) node_values_head->data;
888     const char *json_key = proto_node_to_json_key(first_value);
889     gchar* json_key_suffix = g_strdup_printf("%s%s", json_key, suffix);
890     json_dumper_set_member_name(pdata->dumper, json_key_suffix);
891     g_free(json_key_suffix);
892     write_json_proto_node_value_list(node_values_head, value_writer, pdata);
893 }
894 
895 /**
896  * Writes a list of values of a single json key. If multiple values are passed they are wrapped in a json array.
897  * @param node_values_head Linked list containing all values that should be written.
898  * @param value_writer Function which writes the separate values.
899  * @param pdata json writing metadata
900  */
901 static void
write_json_proto_node_value_list(GSList * node_values_head,proto_node_value_writer value_writer,write_json_data * pdata)902 write_json_proto_node_value_list(GSList *node_values_head, proto_node_value_writer value_writer, write_json_data *pdata)
903 {
904     GSList *current_value = node_values_head;
905 
906     // Write directly if only a single value is passed. Wrap in json array otherwise.
907     if (current_value->next == NULL) {
908         value_writer((proto_node *) current_value->data, pdata);
909     } else {
910         json_dumper_begin_array(pdata->dumper);
911 
912         while (current_value != NULL) {
913             value_writer((proto_node *) current_value->data, pdata);
914             current_value = current_value->next;
915         }
916         json_dumper_end_array(pdata->dumper);
917     }
918 }
919 
920 /**
921  * Writes the value for a node that's filtered from the output.
922  */
923 static void
write_json_proto_node_filtered(proto_node * node,write_json_data * pdata)924 write_json_proto_node_filtered(proto_node *node, write_json_data *pdata)
925 {
926     const char *json_key = proto_node_to_json_key(node);
927 
928     json_dumper_begin_object(pdata->dumper);
929     json_dumper_set_member_name(pdata->dumper, "filtered");
930     json_dumper_value_string(pdata->dumper, json_key);
931     json_dumper_end_object(pdata->dumper);
932 }
933 
934 /**
935  * Writes the hex dump of a node. A json array is written containing the hex dump, position, length, bitmask and type of
936  * the node.
937  */
938 static void
write_json_proto_node_hex_dump(proto_node * node,write_json_data * pdata)939 write_json_proto_node_hex_dump(proto_node *node, write_json_data *pdata)
940 {
941     field_info *fi = node->finfo;
942 
943     json_dumper_begin_array(pdata->dumper);
944 
945     if (fi->hfinfo->bitmask!=0) {
946         switch (fi->value.ftype->ftype) {
947             case FT_INT8:
948             case FT_INT16:
949             case FT_INT24:
950             case FT_INT32:
951                 json_dumper_value_anyf(pdata->dumper, "\"%X\"", (guint) fvalue_get_sinteger(&fi->value));
952                 break;
953             case FT_CHAR:
954             case FT_UINT8:
955             case FT_UINT16:
956             case FT_UINT24:
957             case FT_UINT32:
958                 json_dumper_value_anyf(pdata->dumper, "\"%X\"", fvalue_get_uinteger(&fi->value));
959                 break;
960             case FT_INT40:
961             case FT_INT48:
962             case FT_INT56:
963             case FT_INT64:
964                 json_dumper_value_anyf(pdata->dumper, "\"%" G_GINT64_MODIFIER "X\"", fvalue_get_sinteger64(&fi->value));
965                 break;
966             case FT_UINT40:
967             case FT_UINT48:
968             case FT_UINT56:
969             case FT_UINT64:
970             case FT_BOOLEAN:
971                 json_dumper_value_anyf(pdata->dumper, "\"%" G_GINT64_MODIFIER "X\"", fvalue_get_uinteger64(&fi->value));
972                 break;
973             default:
974                 ws_assert_not_reached();
975         }
976     } else {
977         json_write_field_hex_value(pdata, fi);
978     }
979 
980     /* Dump raw hex-encoded dissected information including position, length, bitmask, type */
981     json_dumper_value_anyf(pdata->dumper, "%" G_GINT32_MODIFIER "d", fi->start);
982     json_dumper_value_anyf(pdata->dumper, "%" G_GINT32_MODIFIER "d", fi->length);
983     json_dumper_value_anyf(pdata->dumper, "%" G_GUINT64_FORMAT, fi->hfinfo->bitmask);
984     json_dumper_value_anyf(pdata->dumper, "%" G_GINT32_MODIFIER "d", (gint32)fi->value.ftype->ftype);
985 
986     json_dumper_end_array(pdata->dumper);
987 }
988 
989 /**
990  * Writes the value of a node, which may be a simple node with no value and no children,
991  * or a node with children -- this will be determined dynamically
992  */
993 static void
write_json_proto_node_dynamic(proto_node * node,write_json_data * data)994 write_json_proto_node_dynamic(proto_node *node, write_json_data *data)
995 {
996     if (node->first_child == NULL) {
997         write_json_proto_node_no_value(node, data);
998     } else {
999         write_json_proto_node_children(node, data);
1000     }
1001 }
1002 
1003 /**
1004  * Writes the children of a node. Calls write_json_proto_node_list internally which recursively writes children of nodes
1005  * to the output.
1006  */
1007 static void
write_json_proto_node_children(proto_node * node,write_json_data * data)1008 write_json_proto_node_children(proto_node *node, write_json_data *data)
1009 {
1010     GSList *grouped_children_list = data->node_children_grouper(node);
1011     write_json_proto_node_list(grouped_children_list, data);
1012     g_slist_free_full(grouped_children_list, (GDestroyNotify) g_slist_free);
1013 }
1014 
1015 /**
1016  * Writes the value of a node to the output.
1017  */
1018 static void
write_json_proto_node_value(proto_node * node,write_json_data * pdata)1019 write_json_proto_node_value(proto_node *node, write_json_data *pdata)
1020 {
1021     field_info *fi = node->finfo;
1022     // Get the actual value of the node as a string.
1023     char *value_string_repr = fvalue_to_string_repr(NULL, &fi->value, FTREPR_DISPLAY, fi->hfinfo->display);
1024 
1025     json_dumper_value_string(pdata->dumper, value_string_repr);
1026 
1027     wmem_free(NULL, value_string_repr);
1028 }
1029 
1030 /**
1031  * Write the value for a node that has no value and no children. This is the empty string for all nodes except those of
1032  * type FT_PROTOCOL for which the full name is written instead.
1033  */
1034 static void
write_json_proto_node_no_value(proto_node * node,write_json_data * pdata)1035 write_json_proto_node_no_value(proto_node *node, write_json_data *pdata)
1036 {
1037     field_info *fi = node->finfo;
1038 
1039     if (fi->hfinfo->type == FT_PROTOCOL) {
1040         if (fi->rep) {
1041             json_dumper_value_string(pdata->dumper, fi->rep->representation);
1042         } else {
1043             gchar label_str[ITEM_LABEL_LENGTH];
1044             proto_item_fill_label(fi, label_str);
1045             json_dumper_value_string(pdata->dumper, label_str);
1046         }
1047     } else {
1048         json_dumper_value_string(pdata->dumper, "");
1049     }
1050 }
1051 
1052 /**
1053  * Groups each child of the node separately.
1054  * @return Linked list where each element is another linked list containing a single node.
1055  */
1056 GSList *
proto_node_group_children_by_unique(proto_node * node)1057 proto_node_group_children_by_unique(proto_node *node) {
1058     GSList *unique_nodes_list = NULL;
1059     proto_node *current_child = node->first_child;
1060 
1061     while (current_child != NULL) {
1062         GSList *unique_node = g_slist_prepend(NULL, current_child);
1063         unique_nodes_list = g_slist_prepend(unique_nodes_list, unique_node);
1064         current_child = current_child->next;
1065     }
1066 
1067     return g_slist_reverse(unique_nodes_list);
1068 }
1069 
1070 /**
1071  * Groups the children of a node by their json key. Children are put in the same group if they have the same json key.
1072  * @return Linked list where each element is another linked list of nodes associated with the same json key.
1073  */
1074 GSList *
proto_node_group_children_by_json_key(proto_node * node)1075 proto_node_group_children_by_json_key(proto_node *node)
1076 {
1077     /**
1078      * For each different json key we store a linked list of values corresponding to that json key. These lists are kept
1079      * in both a linked list and a hashmap. The hashmap is used to quickly retrieve the values of a json key. The linked
1080      * list is used to preserve the ordering of keys as they are encountered which is not guaranteed when only using a
1081      * hashmap.
1082      */
1083     GSList *same_key_nodes_list = NULL;
1084     GHashTable *lookup_by_json_key = g_hash_table_new(g_str_hash, g_str_equal);
1085     proto_node *current_child = node->first_child;
1086 
1087     /**
1088      * For each child of the node get the key and get the list of values already associated with that key from the
1089      * hashmap. If no list exist yet for that key create a new one and add it to both the linked list and hashmap. If a
1090      * list already exists add the node to that list.
1091      */
1092     while (current_child != NULL) {
1093         char *json_key = (char *) proto_node_to_json_key(current_child);
1094         GSList *json_key_nodes = (GSList *) g_hash_table_lookup(lookup_by_json_key, json_key);
1095 
1096         if (json_key_nodes == NULL) {
1097             json_key_nodes = g_slist_append(json_key_nodes, current_child);
1098             // Prepending in single linked list is O(1), appending is O(n). Better to prepend here and reverse at the
1099             // end than potentially looping to the end of the linked list for each child.
1100             same_key_nodes_list = g_slist_prepend(same_key_nodes_list, json_key_nodes);
1101             g_hash_table_insert(lookup_by_json_key, json_key, json_key_nodes);
1102         } else {
1103             // Store and insert value again to circumvent unused_variable warning.
1104             // Append in this case since most value lists will only have a single value.
1105             json_key_nodes = g_slist_append(json_key_nodes, current_child);
1106             g_hash_table_insert(lookup_by_json_key, json_key, json_key_nodes);
1107         }
1108 
1109         current_child = current_child->next;
1110     }
1111 
1112     // Hash table is not needed anymore since the linked list with the correct ordering is returned.
1113     g_hash_table_destroy(lookup_by_json_key);
1114 
1115     return g_slist_reverse(same_key_nodes_list);
1116 }
1117 
1118 /**
1119  * Returns the json key of a node. Tries to use the node's abbreviated name. If the abbreviated name is not available
1120  * the representation is used instead.
1121  */
1122 static const char *
proto_node_to_json_key(proto_node * node)1123 proto_node_to_json_key(proto_node *node)
1124 {
1125     const char *json_key;
1126     // Check if node has abbreviated name.
1127     if (node->finfo->hfinfo->id != hf_text_only) {
1128         json_key = node->finfo->hfinfo->abbrev;
1129     } else if (node->finfo->rep != NULL) {
1130         json_key = node->finfo->rep->representation;
1131     } else {
1132         json_key = "";
1133     }
1134 
1135     return json_key;
1136 }
1137 
1138 static gboolean
ek_check_protocolfilter(gchar ** protocolfilter,const char * str)1139 ek_check_protocolfilter(gchar **protocolfilter, const char *str)
1140 {
1141     gchar *str_escaped = NULL;
1142     gboolean check;
1143     int i;
1144 
1145     if (check_protocolfilter(protocolfilter, str))
1146         return TRUE;
1147 
1148     /* to to thread the '.' and '_' equally. The '.' is replace by print_escaped_ek for '_' */
1149     if (str != NULL && strlen(str) > 0) {
1150         str_escaped = g_strdup(str);
1151 
1152         i = 0;
1153         while (str_escaped[i] != '\0') {
1154             if (str_escaped[i] == '.') {
1155                 str_escaped[i] = '_';
1156             }
1157             i++;
1158         }
1159     }
1160 
1161     check = check_protocolfilter(protocolfilter, str_escaped);
1162     g_free(str_escaped);
1163     return check;
1164 }
1165 
1166 /**
1167  * Finds a node's descendants to be printed as EK/JSON attributes.
1168  */
1169 static void
write_ek_summary(column_info * cinfo,write_json_data * pdata)1170 write_ek_summary(column_info *cinfo, write_json_data* pdata)
1171 {
1172     gint i;
1173 
1174     for (i = 0; i < cinfo->num_cols; i++) {
1175         if (!get_column_visible(i))
1176             continue;
1177         json_dumper_set_member_name(pdata->dumper, g_ascii_strdown(cinfo->columns[i].col_title, -1));
1178         json_dumper_value_string(pdata->dumper, cinfo->columns[i].col_data);
1179     }
1180 }
1181 
1182 /* Write out a tree's data, and any child nodes, as JSON for EK */
1183 static void
ek_fill_attr(proto_node * node,GSList ** attr_list,GHashTable * attr_table,write_json_data * pdata)1184 ek_fill_attr(proto_node *node, GSList **attr_list, GHashTable *attr_table, write_json_data *pdata)
1185 {
1186     field_info *fi         = NULL;
1187     field_info *fi_parent  = NULL;
1188     gchar *node_name       = NULL;
1189     GSList *attr_instances = NULL;
1190 
1191     proto_node *current_node = node->first_child;
1192     while (current_node != NULL) {
1193         fi        = PNODE_FINFO(current_node);
1194         fi_parent = PNODE_FINFO(current_node->parent);
1195 
1196         /* dissection with an invisible proto tree? */
1197         ws_assert(fi);
1198 
1199         if (fi_parent == NULL) {
1200             node_name = g_strdup(fi->hfinfo->abbrev);
1201         } else {
1202             node_name = g_strconcat(fi_parent->hfinfo->abbrev, "_", fi->hfinfo->abbrev, NULL);
1203         }
1204 
1205         attr_instances = (GSList *) g_hash_table_lookup(attr_table, node_name);
1206         // First time we encounter this attr
1207         if (attr_instances == NULL) {
1208             attr_instances = g_slist_append(attr_instances, current_node);
1209             *attr_list = g_slist_prepend(*attr_list, attr_instances);
1210         } else {
1211             attr_instances = g_slist_append(attr_instances, current_node);
1212         }
1213 
1214         // Update instance list for this attr in hash table
1215         g_hash_table_insert(attr_table, node_name, attr_instances);
1216 
1217         /* Field, recurse through children*/
1218         if (fi->hfinfo->type != FT_PROTOCOL && current_node->first_child != NULL) {
1219             if (pdata->filter != NULL) {
1220                 if (ek_check_protocolfilter(pdata->filter, fi->hfinfo->abbrev)) {
1221                     gchar **_filter = NULL;
1222                     /* Remove protocol filter for children, if children should be included */
1223                     if ((pdata->filter_flags&PF_INCLUDE_CHILDREN) == PF_INCLUDE_CHILDREN) {
1224                         _filter = pdata->filter;
1225                         pdata->filter = NULL;
1226                     }
1227 
1228                     ek_fill_attr(current_node, attr_list, attr_table, pdata);
1229 
1230                     /* Put protocol filter back */
1231                     if ((pdata->filter_flags&PF_INCLUDE_CHILDREN) == PF_INCLUDE_CHILDREN) {
1232                         pdata->filter = _filter;
1233                     }
1234                 } else {
1235                     // Don't traverse children if filtered out
1236                 }
1237             } else {
1238                 ek_fill_attr(current_node, attr_list, attr_table, pdata);
1239             }
1240         } else {
1241             // Will descend into object at another point
1242         }
1243 
1244         current_node = current_node->next;
1245     }
1246 }
1247 
1248 static void
ek_write_name(proto_node * pnode,gchar * suffix,write_json_data * pdata)1249 ek_write_name(proto_node *pnode, gchar* suffix, write_json_data* pdata)
1250 {
1251     field_info *fi = PNODE_FINFO(pnode);
1252     gchar      *str;
1253 
1254     if (fi->hfinfo->parent != -1) {
1255         header_field_info* parent = proto_registrar_get_nth(fi->hfinfo->parent);
1256         str = g_strdup_printf("%s_%s%s", parent->abbrev, fi->hfinfo->abbrev, suffix ? suffix : "");
1257         json_dumper_set_member_name(pdata->dumper, str);
1258     } else {
1259         str = g_strdup_printf("%s%s", fi->hfinfo->abbrev, suffix ? suffix : "");
1260         json_dumper_set_member_name(pdata->dumper, str);
1261     }
1262     g_free(str);
1263 }
1264 
1265 static void
ek_write_hex(field_info * fi,write_json_data * pdata)1266 ek_write_hex(field_info *fi, write_json_data *pdata)
1267 {
1268     if (fi->hfinfo->bitmask != 0) {
1269         switch (fi->value.ftype->ftype) {
1270             case FT_INT8:
1271             case FT_INT16:
1272             case FT_INT24:
1273             case FT_INT32:
1274                 json_dumper_value_anyf(pdata->dumper, "\"%X\"", (guint) fvalue_get_sinteger(&fi->value));
1275                 break;
1276             case FT_CHAR:
1277             case FT_UINT8:
1278             case FT_UINT16:
1279             case FT_UINT24:
1280             case FT_UINT32:
1281                 json_dumper_value_anyf(pdata->dumper, "\"%X\"", fvalue_get_uinteger(&fi->value));
1282                 break;
1283             case FT_INT40:
1284             case FT_INT48:
1285             case FT_INT56:
1286             case FT_INT64:
1287                 json_dumper_value_anyf(pdata->dumper, "\"%" G_GINT64_MODIFIER "X\"", fvalue_get_sinteger64(&fi->value));
1288                 break;
1289             case FT_UINT40:
1290             case FT_UINT48:
1291             case FT_UINT56:
1292             case FT_UINT64:
1293             case FT_BOOLEAN:
1294                 json_dumper_value_anyf(pdata->dumper, "\"%" G_GINT64_MODIFIER "X\"", fvalue_get_uinteger64(&fi->value));
1295                 break;
1296             default:
1297                 ws_assert_not_reached();
1298         }
1299     } else {
1300         json_write_field_hex_value(pdata, fi);
1301     }
1302 }
1303 
1304 static void
ek_write_field_value(field_info * fi,write_json_data * pdata)1305 ek_write_field_value(field_info *fi, write_json_data* pdata)
1306 {
1307     gchar label_str[ITEM_LABEL_LENGTH];
1308     char *dfilter_string;
1309     const nstime_t *t;
1310     struct tm *tm;
1311 #ifndef _WIN32
1312     struct tm tm_time;
1313 #endif
1314     char time_string[sizeof("YYYY-MM-DDTHH:MM:SS")];
1315 
1316     /* Text label */
1317     if (fi->hfinfo->id == hf_text_only && fi->rep) {
1318         json_dumper_value_string(pdata->dumper, fi->rep->representation);
1319     } else {
1320         /* show, value, and unmaskedvalue attributes */
1321         switch(fi->hfinfo->type) {
1322         case FT_PROTOCOL:
1323             if (fi->rep) {
1324                 json_dumper_value_string(pdata->dumper, fi->rep->representation);
1325             }
1326             else {
1327                 proto_item_fill_label(fi, label_str);
1328                 json_dumper_value_string(pdata->dumper, label_str);
1329             }
1330             break;
1331         case FT_NONE:
1332             json_dumper_value_string(pdata->dumper, NULL);
1333             break;
1334         case FT_BOOLEAN:
1335             if (fi->value.value.uinteger64)
1336                 json_dumper_value_anyf(pdata->dumper, "true");
1337             else
1338                 json_dumper_value_anyf(pdata->dumper, "false");
1339             break;
1340         case FT_ABSOLUTE_TIME:
1341             t = (const nstime_t *)fvalue_get(&fi->value);
1342 #ifdef _WIN32
1343             /*
1344              * Do not use gmtime_s(), as it will call and
1345              * exception handler if the time we're providing
1346              * is < 0, and that will, by default, exit.
1347              * ("Programmers not bothering to check return
1348              * values?  Try new Microsoft Visual Studio,
1349              * with Parameter Validation(R)!  Kill insufficiently
1350              * careful programs - *and* the processes running them -
1351              * fast!")
1352              *
1353              * We just want to report this as an unrepresentable
1354              * time.  It fills in a per-thread structure, which
1355              * is sufficiently thread-safe for our purposes.
1356              */
1357             tm = gmtime(&t->secs);
1358 #else
1359             /*
1360              * Use gmtime_r(), because the Single UNIX Specification
1361              * does *not* guarantee that gmtime() is thread-safe.
1362              * Perhaps it is on all platforms on which we run, but
1363              * this way we don't have to check.
1364              */
1365             tm = gmtime_r(&t->secs, &tm_time);
1366 #endif
1367             if (tm != NULL) {
1368                 /* Some platforms (MinGW-w64) do not support %F or %T. */
1369                 strftime(time_string, sizeof(time_string), "%Y-%m-%dT%H:%M:%S", tm);
1370                 json_dumper_value_anyf(pdata->dumper, "\"%s.%09uZ\"", time_string, t->nsecs);
1371             } else {
1372                 json_dumper_value_anyf(pdata->dumper, "\"Not representable\"");
1373             }
1374             break;
1375         default:
1376             dfilter_string = fvalue_to_string_repr(NULL, &fi->value, FTREPR_DISPLAY, fi->hfinfo->display);
1377             if (dfilter_string != NULL) {
1378                 json_dumper_value_string(pdata->dumper, dfilter_string);
1379             }
1380             wmem_free(NULL, dfilter_string);
1381             break;
1382         }
1383     }
1384 }
1385 
1386 static void
ek_write_attr_hex(GSList * attr_instances,write_json_data * pdata)1387 ek_write_attr_hex(GSList *attr_instances, write_json_data *pdata)
1388 {
1389     GSList *current_node = attr_instances;
1390     proto_node *pnode    = (proto_node *) current_node->data;
1391     field_info *fi       = NULL;
1392 
1393     // Raw name
1394     ek_write_name(pnode, "_raw", pdata);
1395 
1396     if (g_slist_length(attr_instances) > 1) {
1397         json_dumper_begin_array(pdata->dumper);
1398     }
1399 
1400     // Raw value(s)
1401     while (current_node != NULL) {
1402         pnode = (proto_node *) current_node->data;
1403         fi    = PNODE_FINFO(pnode);
1404 
1405         ek_write_hex(fi, pdata);
1406 
1407         current_node = current_node->next;
1408     }
1409 
1410     if (g_slist_length(attr_instances) > 1) {
1411         json_dumper_end_array(pdata->dumper);
1412     }
1413 }
1414 
1415 static void
ek_write_attr(GSList * attr_instances,write_json_data * pdata)1416 ek_write_attr(GSList *attr_instances, write_json_data *pdata)
1417 {
1418     GSList *current_node = attr_instances;
1419     proto_node *pnode    = (proto_node *) current_node->data;
1420     field_info *fi       = PNODE_FINFO(pnode);
1421 
1422     // Hex dump -x
1423     if (pdata->print_hex && fi && fi->length > 0 && fi->hfinfo->id != hf_text_only) {
1424         ek_write_attr_hex(attr_instances, pdata);
1425     }
1426 
1427     // Print attr name
1428     ek_write_name(pnode, NULL, pdata);
1429 
1430     if (g_slist_length(attr_instances) > 1) {
1431         json_dumper_begin_array(pdata->dumper);
1432     }
1433 
1434     while (current_node != NULL) {
1435         pnode = (proto_node *) current_node->data;
1436         fi    = PNODE_FINFO(pnode);
1437 
1438         /* Field */
1439         if (fi->hfinfo->type != FT_PROTOCOL) {
1440             if (pdata->filter != NULL
1441                 && !ek_check_protocolfilter(pdata->filter, fi->hfinfo->abbrev)) {
1442 
1443                 /* print dummy field */
1444                 json_dumper_begin_object(pdata->dumper);
1445                 json_dumper_set_member_name(pdata->dumper, "filtered");
1446                 json_dumper_value_string(pdata->dumper, fi->hfinfo->abbrev);
1447                 json_dumper_end_object(pdata->dumper);
1448             } else {
1449                 ek_write_field_value(fi, pdata);
1450             }
1451         } else {
1452             /* Object */
1453             json_dumper_begin_object(pdata->dumper);
1454 
1455             if (pdata->filter != NULL) {
1456                 if (ek_check_protocolfilter(pdata->filter, fi->hfinfo->abbrev)) {
1457                     gchar **_filter = NULL;
1458                     /* Remove protocol filter for children, if children should be included */
1459                     if ((pdata->filter_flags&PF_INCLUDE_CHILDREN) == PF_INCLUDE_CHILDREN) {
1460                         _filter = pdata->filter;
1461                         pdata->filter = NULL;
1462                     }
1463 
1464                     proto_tree_write_node_ek(pnode, pdata);
1465 
1466                     /* Put protocol filter back */
1467                     if ((pdata->filter_flags&PF_INCLUDE_CHILDREN) == PF_INCLUDE_CHILDREN) {
1468                         pdata->filter = _filter;
1469                     }
1470                 } else {
1471                     /* print dummy field */
1472                     json_dumper_set_member_name(pdata->dumper, "filtered");
1473                     json_dumper_value_string(pdata->dumper, fi->hfinfo->abbrev);
1474                 }
1475             } else {
1476                 proto_tree_write_node_ek(pnode, pdata);
1477             }
1478 
1479             json_dumper_end_object(pdata->dumper);
1480         }
1481 
1482         current_node = current_node->next;
1483     }
1484 
1485     if (g_slist_length(attr_instances) > 1) {
1486         json_dumper_end_array(pdata->dumper);
1487     }
1488 }
1489 
1490 /* Write out a tree's data, and any child nodes, as JSON for EK */
1491 static void
proto_tree_write_node_ek(proto_node * node,write_json_data * pdata)1492 proto_tree_write_node_ek(proto_node *node, write_json_data *pdata)
1493 {
1494     GSList *attr_list  = NULL;
1495     GHashTable *attr_table  = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
1496 
1497     ek_fill_attr(node, &attr_list, attr_table, pdata);
1498 
1499     g_hash_table_destroy(attr_table);
1500 
1501     // Print attributes
1502     attr_list = g_slist_reverse(attr_list);
1503     GSList *current_attr = attr_list;
1504     while (current_attr != NULL) {
1505         GSList *attr_instances = (GSList *) current_attr->data;
1506 
1507         ek_write_attr(attr_instances, pdata);
1508 
1509         current_attr = current_attr->next;
1510     }
1511 
1512     g_slist_free_full(attr_list, (GDestroyNotify) g_slist_free);
1513 }
1514 
1515 /* Print info for a 'geninfo' pseudo-protocol. This is required by
1516  * the PDML spec. The information is contained in Wireshark's 'frame' protocol,
1517  * but we produce a 'geninfo' protocol in the PDML to conform to spec.
1518  * The 'frame' protocol follows the 'geninfo' protocol in the PDML. */
1519 static void
print_pdml_geninfo(epan_dissect_t * edt,FILE * fh)1520 print_pdml_geninfo(epan_dissect_t *edt, FILE *fh)
1521 {
1522     guint32     num, len, caplen;
1523     GPtrArray  *finfo_array;
1524     field_info *frame_finfo;
1525     gchar      *tmp;
1526 
1527     /* Get frame protocol's finfo. */
1528     finfo_array = proto_find_first_finfo(edt->tree, proto_frame);
1529     if (g_ptr_array_len(finfo_array) < 1) {
1530         return;
1531     }
1532     frame_finfo = (field_info *)finfo_array->pdata[0];
1533     g_ptr_array_free(finfo_array, TRUE);
1534 
1535     /* frame.number, packet_info.num */
1536     num = edt->pi.num;
1537 
1538     /* frame.frame_len, packet_info.frame_data->pkt_len */
1539     len = edt->pi.fd->pkt_len;
1540 
1541     /* frame.cap_len --> packet_info.frame_data->cap_len */
1542     caplen = edt->pi.fd->cap_len;
1543 
1544     /* Print geninfo start */
1545     fprintf(fh,
1546             "  <proto name=\"geninfo\" pos=\"0\" showname=\"General information\" size=\"%d\">\n",
1547             frame_finfo->length);
1548 
1549     /* Print geninfo.num */
1550     fprintf(fh,
1551             "    <field name=\"num\" pos=\"0\" show=\"%u\" showname=\"Number\" value=\"%x\" size=\"%d\"/>\n",
1552             num, num, frame_finfo->length);
1553 
1554     /* Print geninfo.len */
1555     fprintf(fh,
1556             "    <field name=\"len\" pos=\"0\" show=\"%u\" showname=\"Frame Length\" value=\"%x\" size=\"%d\"/>\n",
1557             len, len, frame_finfo->length);
1558 
1559     /* Print geninfo.caplen */
1560     fprintf(fh,
1561             "    <field name=\"caplen\" pos=\"0\" show=\"%u\" showname=\"Captured Length\" value=\"%x\" size=\"%d\"/>\n",
1562             caplen, caplen, frame_finfo->length);
1563 
1564     tmp = abs_time_to_str(NULL, &edt->pi.abs_ts, ABSOLUTE_TIME_LOCAL, TRUE);
1565 
1566     /* Print geninfo.timestamp */
1567     fprintf(fh,
1568             "    <field name=\"timestamp\" pos=\"0\" show=\"%s\" showname=\"Captured Time\" value=\"%d.%09d\" size=\"%d\"/>\n",
1569             tmp, (int)edt->pi.abs_ts.secs, edt->pi.abs_ts.nsecs, frame_finfo->length);
1570 
1571     wmem_free(NULL, tmp);
1572 
1573     /* Print geninfo end */
1574     fprintf(fh,
1575             "  </proto>\n");
1576 }
1577 
1578 void
write_pdml_finale(FILE * fh)1579 write_pdml_finale(FILE *fh)
1580 {
1581     fputs("</pdml>\n", fh);
1582 }
1583 
1584 void
write_psml_preamble(column_info * cinfo,FILE * fh)1585 write_psml_preamble(column_info *cinfo, FILE *fh)
1586 {
1587     gint i;
1588 
1589     fprintf(fh, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
1590     fprintf(fh, "<psml version=\"" PSML_VERSION "\" creator=\"%s/%s\">\n", PACKAGE, VERSION);
1591     fprintf(fh, "<structure>\n");
1592 
1593     for (i = 0; i < cinfo->num_cols; i++) {
1594         if (!get_column_visible(i))
1595             continue;
1596         fprintf(fh, "<section>");
1597         print_escaped_xml(fh, cinfo->columns[i].col_title);
1598         fprintf(fh, "</section>\n");
1599     }
1600 
1601     fprintf(fh, "</structure>\n\n");
1602 }
1603 
1604 void
write_psml_columns(epan_dissect_t * edt,FILE * fh,gboolean use_color)1605 write_psml_columns(epan_dissect_t *edt, FILE *fh, gboolean use_color)
1606 {
1607     gint i;
1608     const color_filter_t *cfp = edt->pi.fd->color_filter;
1609 
1610     if (use_color && (cfp != NULL)) {
1611         fprintf(fh, "<packet foreground='#%06x' background='#%06x'>\n",
1612             color_t_to_rgb(&cfp->fg_color),
1613             color_t_to_rgb(&cfp->bg_color));
1614     } else {
1615         fprintf(fh, "<packet>\n");
1616     }
1617 
1618     for (i = 0; i < edt->pi.cinfo->num_cols; i++) {
1619         if (!get_column_visible(i))
1620             continue;
1621         fprintf(fh, "<section>");
1622         print_escaped_xml(fh, edt->pi.cinfo->columns[i].col_data);
1623         fprintf(fh, "</section>\n");
1624     }
1625 
1626     fprintf(fh, "</packet>\n\n");
1627 }
1628 
1629 void
write_psml_finale(FILE * fh)1630 write_psml_finale(FILE *fh)
1631 {
1632     fputs("</psml>\n", fh);
1633 }
1634 
csv_massage_str(const gchar * source,const gchar * exceptions)1635 static gchar *csv_massage_str(const gchar *source, const gchar *exceptions)
1636 {
1637     gchar *csv_str;
1638     gchar *tmp_str;
1639 
1640     /* In general, our output for any field can contain Unicode characters,
1641        so g_strescape (which escapes any non-ASCII) is the wrong thing to do.
1642        Unfortunately glib doesn't appear to provide g_unicode_strescape()... */
1643     csv_str = g_strescape(source, exceptions);
1644     tmp_str = csv_str;
1645     /* Locate the UTF-8 right arrow character and replace it by an ASCII equivalent */
1646     while ( (tmp_str = strstr(tmp_str, UTF8_RIGHTWARDS_ARROW)) != NULL ) {
1647         tmp_str[0] = ' ';
1648         tmp_str[1] = '>';
1649         tmp_str[2] = ' ';
1650     }
1651     tmp_str = csv_str;
1652     while ( (tmp_str = strstr(tmp_str, "\\\"")) != NULL )
1653         *tmp_str = '\"';
1654     return csv_str;
1655 }
1656 
csv_write_str(const char * str,char sep,FILE * fh)1657 static void csv_write_str(const char *str, char sep, FILE *fh)
1658 {
1659     gchar *csv_str;
1660 
1661     /* Do not escape the UTF-8 right arrow character */
1662     csv_str = csv_massage_str(str, UTF8_RIGHTWARDS_ARROW);
1663     fprintf(fh, "\"%s\"%c", csv_str, sep);
1664     g_free(csv_str);
1665 }
1666 
1667 void
write_csv_column_titles(column_info * cinfo,FILE * fh)1668 write_csv_column_titles(column_info *cinfo, FILE *fh)
1669 {
1670     gint i;
1671 
1672     for (i = 0; i < cinfo->num_cols - 1; i++) {
1673         if (!get_column_visible(i))
1674             continue;
1675         csv_write_str(cinfo->columns[i].col_title, ',', fh);
1676     }
1677     csv_write_str(cinfo->columns[i].col_title, '\n', fh);
1678 }
1679 
1680 void
write_csv_columns(epan_dissect_t * edt,FILE * fh)1681 write_csv_columns(epan_dissect_t *edt, FILE *fh)
1682 {
1683     gint i;
1684 
1685     for (i = 0; i < edt->pi.cinfo->num_cols - 1; i++) {
1686         if (!get_column_visible(i))
1687             continue;
1688         csv_write_str(edt->pi.cinfo->columns[i].col_data, ',', fh);
1689     }
1690     csv_write_str(edt->pi.cinfo->columns[i].col_data, '\n', fh);
1691 }
1692 
1693 void
write_carrays_hex_data(guint32 num,FILE * fh,epan_dissect_t * edt)1694 write_carrays_hex_data(guint32 num, FILE *fh, epan_dissect_t *edt)
1695 {
1696     guint32       i = 0, src_num = 0;
1697     GSList       *src_le;
1698     tvbuff_t     *tvb;
1699     char         *name;
1700     const guchar *cp;
1701     guint         length;
1702     char          ascii[9];
1703     struct data_source *src;
1704 
1705     for (src_le = edt->pi.data_src; src_le != NULL; src_le = src_le->next) {
1706         memset(ascii, 0, sizeof(ascii));
1707         src = (struct data_source *)src_le->data;
1708         tvb = get_data_source_tvb(src);
1709         length = tvb_captured_length(tvb);
1710         if (length == 0)
1711             continue;
1712 
1713         cp = tvb_get_ptr(tvb, 0, length);
1714 
1715         name = get_data_source_name(src);
1716         if (name) {
1717             fprintf(fh, "/* %s */\n", name);
1718             wmem_free(NULL, name);
1719         }
1720         if (src_num) {
1721             fprintf(fh, "static const unsigned char pkt%u_%u[%u] = {\n",
1722                     num, src_num, length);
1723         } else {
1724             fprintf(fh, "static const unsigned char pkt%u[%u] = {\n",
1725                     num, length);
1726         }
1727         src_num++;
1728 
1729         for (i = 0; i < length; i++) {
1730             fprintf(fh, "0x%02x", *(cp + i));
1731             ascii[i % 8] = g_ascii_isprint(*(cp + i)) ? *(cp + i) : '.';
1732 
1733             if (i == (length - 1)) {
1734                 guint rem;
1735                 rem = length % 8;
1736                 if (rem) {
1737                     guint j;
1738                     for ( j = 0; j < 8 - rem; j++ )
1739                         fprintf(fh, "      ");
1740                 }
1741                 fprintf(fh, "  /* %s */\n};\n\n", ascii);
1742                 break;
1743             }
1744 
1745             if (!((i + 1) % 8)) {
1746                 fprintf(fh, ", /* %s */\n", ascii);
1747                 memset(ascii, 0, sizeof(ascii));
1748             } else {
1749                 fprintf(fh, ", ");
1750             }
1751         }
1752     }
1753 }
1754 
1755 /*
1756  * Find the data source for a specified field, and return a pointer
1757  * to the data in it. Returns NULL if the data is out of bounds.
1758  */
1759 /* XXX: What am I missing ?
1760  *      Why bother searching for fi->ds_tvb for the matching tvb
1761  *       in the data_source list ?
1762  *      IOW: Why not just use fi->ds_tvb for the arg to tvb_get_ptr() ?
1763  */
1764 
1765 static const guint8 *
get_field_data(GSList * src_list,field_info * fi)1766 get_field_data(GSList *src_list, field_info *fi)
1767 {
1768     GSList   *src_le;
1769     tvbuff_t *src_tvb;
1770     gint      length, tvbuff_length;
1771     struct data_source *src;
1772 
1773     for (src_le = src_list; src_le != NULL; src_le = src_le->next) {
1774         src = (struct data_source *)src_le->data;
1775         src_tvb = get_data_source_tvb(src);
1776         if (fi->ds_tvb == src_tvb) {
1777             /*
1778              * Found it.
1779              *
1780              * XXX - a field can have a length that runs past
1781              * the end of the tvbuff.  Ideally, that should
1782              * be fixed when adding an item to the protocol
1783              * tree, but checking the length when doing
1784              * that could be expensive.  Until we fix that,
1785              * we'll do the check here.
1786              */
1787             tvbuff_length = tvb_captured_length_remaining(src_tvb,
1788                                                  fi->start);
1789             if (tvbuff_length < 0) {
1790                 return NULL;
1791             }
1792             length = fi->length;
1793             if (length > tvbuff_length)
1794                 length = tvbuff_length;
1795             return tvb_get_ptr(src_tvb, fi->start, length);
1796         }
1797     }
1798     return NULL;  /* not found */
1799 }
1800 
1801 /* Print a string, escaping out certain characters that need to
1802  * escaped out for XML. */
1803 static void
print_escaped_xml(FILE * fh,const char * unescaped_string)1804 print_escaped_xml(FILE *fh, const char *unescaped_string)
1805 {
1806     const char *p;
1807 
1808 #define ESCAPED_BUFFER_MAX 256
1809     static char temp_buffer[ESCAPED_BUFFER_MAX];
1810     gint        offset = 0;
1811 
1812     if (fh == NULL || unescaped_string == NULL) {
1813         return;
1814     }
1815 
1816     for (p = unescaped_string; *p != '\0' && (offset<(ESCAPED_BUFFER_MAX-1)); p++) {
1817         switch (*p) {
1818         case '&':
1819             (void) g_strlcpy(&temp_buffer[offset], "&amp;", ESCAPED_BUFFER_MAX-offset);
1820             offset += 5;
1821             break;
1822         case '<':
1823             (void) g_strlcpy(&temp_buffer[offset], "&lt;", ESCAPED_BUFFER_MAX-offset);
1824             offset += 4;
1825             break;
1826         case '>':
1827             (void) g_strlcpy(&temp_buffer[offset], "&gt;", ESCAPED_BUFFER_MAX-offset);
1828             offset += 4;
1829             break;
1830         case '"':
1831             (void) g_strlcpy(&temp_buffer[offset], "&quot;", ESCAPED_BUFFER_MAX-offset);
1832             offset += 6;
1833             break;
1834         case '\'':
1835             (void) g_strlcpy(&temp_buffer[offset], "&#x27;", ESCAPED_BUFFER_MAX-offset);
1836             offset += 6;
1837             break;
1838         default:
1839             temp_buffer[offset++] = *p;
1840         }
1841         if (offset > ESCAPED_BUFFER_MAX-8) {
1842             /* Getting close to end of buffer so flush to fh */
1843             temp_buffer[offset] = '\0';
1844             fputs(temp_buffer, fh);
1845             offset = 0;
1846         }
1847     }
1848     if (offset) {
1849         /* Flush any outstanding data */
1850         temp_buffer[offset] = '\0';
1851         fputs(temp_buffer, fh);
1852     }
1853 }
1854 
1855 static void
print_escaped_csv(FILE * fh,const char * unescaped_string)1856 print_escaped_csv(FILE *fh, const char *unescaped_string)
1857 {
1858     const char *p;
1859 
1860     if (fh == NULL || unescaped_string == NULL) {
1861         return;
1862     }
1863 
1864     for (p = unescaped_string; *p != '\0'; p++) {
1865         switch (*p) {
1866         case '\b':
1867             fputs("\\b", fh);
1868             break;
1869         case '\f':
1870             fputs("\\f", fh);
1871             break;
1872         case '\n':
1873             fputs("\\n", fh);
1874             break;
1875         case '\r':
1876             fputs("\\r", fh);
1877             break;
1878         case '\t':
1879             fputs("\\t", fh);
1880             break;
1881         default:
1882             fputc(*p, fh);
1883         }
1884     }
1885 }
1886 
1887 static void
pdml_write_field_hex_value(write_pdml_data * pdata,field_info * fi)1888 pdml_write_field_hex_value(write_pdml_data *pdata, field_info *fi)
1889 {
1890     int           i;
1891     const guint8 *pd;
1892 
1893     if (!fi->ds_tvb)
1894         return;
1895 
1896     if (fi->length > tvb_captured_length_remaining(fi->ds_tvb, fi->start)) {
1897         fprintf(pdata->fh, "field length invalid!");
1898         return;
1899     }
1900 
1901     /* Find the data for this field. */
1902     pd = get_field_data(pdata->src_list, fi);
1903 
1904     if (pd) {
1905         /* Used fixed buffer where can, otherwise temp malloc */
1906         static gchar str_static[129];
1907         gchar *str = str_static;
1908         gchar* str_heap = NULL;
1909         if (fi->length > 64) {
1910             str_heap = (gchar*)g_malloc0(fi->length*2+1);
1911             str = str_heap;
1912         }
1913 
1914         static const char hex[] = "0123456789abcdef";
1915 
1916         /* Print a simple hex dump */
1917         for (i = 0 ; i < fi->length; i++) {
1918             str[2*i] =   hex[pd[i] >> 4];
1919             str[2*i+1] = hex[pd[i] & 0xf];
1920         }
1921         str[2 * fi->length] = '\0';
1922         fputs(str, pdata->fh);
1923         g_free(str_heap);
1924 
1925     }
1926 }
1927 
1928 static void
json_write_field_hex_value(write_json_data * pdata,field_info * fi)1929 json_write_field_hex_value(write_json_data *pdata, field_info *fi)
1930 {
1931     const guint8 *pd;
1932 
1933     if (!fi->ds_tvb)
1934         return;
1935 
1936     if (fi->length > tvb_captured_length_remaining(fi->ds_tvb, fi->start)) {
1937         json_dumper_value_string(pdata->dumper, "field length invalid!");
1938         return;
1939     }
1940 
1941     /* Find the data for this field. */
1942     pd = get_field_data(pdata->src_list, fi);
1943 
1944     if (pd) {
1945         gint i;
1946         guint len = fi->length * 2 + 1;
1947         gchar* str = (gchar*)g_malloc0(len);
1948         static const char hex[] = "0123456789abcdef";
1949         /* Print a simple hex dump */
1950         for (i = 0; i < fi->length; i++) {
1951             guint8 c = pd[i];
1952             str[2 * i] = hex[c >> 4];
1953             str[2 * i + 1] = hex[c & 0xf];
1954         }
1955         str[2 * fi->length] = '\0';
1956         json_dumper_value_string(pdata->dumper, str);
1957         g_free(str);
1958     } else {
1959         json_dumper_value_string(pdata->dumper, "");
1960     }
1961 }
1962 
1963 gboolean
print_hex_data(print_stream_t * stream,epan_dissect_t * edt)1964 print_hex_data(print_stream_t *stream, epan_dissect_t *edt)
1965 {
1966     gboolean      multiple_sources;
1967     GSList       *src_le;
1968     tvbuff_t     *tvb;
1969     char         *line, *name;
1970     const guchar *cp;
1971     guint         length;
1972     struct data_source *src;
1973 
1974     /*
1975      * Set "multiple_sources" iff this frame has more than one
1976      * data source; if it does, we need to print the name of
1977      * the data source before printing the data from the
1978      * data source.
1979      */
1980     multiple_sources = (edt->pi.data_src->next != NULL);
1981 
1982     for (src_le = edt->pi.data_src; src_le != NULL;
1983          src_le = src_le->next) {
1984         src = (struct data_source *)src_le->data;
1985         tvb = get_data_source_tvb(src);
1986         if (multiple_sources) {
1987             name = get_data_source_name(src);
1988             line = g_strdup_printf("%s:", name);
1989             wmem_free(NULL, name);
1990             print_line(stream, 0, line);
1991             g_free(line);
1992         }
1993         length = tvb_captured_length(tvb);
1994         if (length == 0)
1995             return TRUE;
1996         cp = tvb_get_ptr(tvb, 0, length);
1997         if (!print_hex_data_buffer(stream, cp, length,
1998                                    (packet_char_enc)edt->pi.fd->encoding))
1999             return FALSE;
2000     }
2001     return TRUE;
2002 }
2003 
2004 /*
2005  * This routine is based on a routine created by Dan Lasley
2006  * <DLASLEY@PROMUS.com>.
2007  *
2008  * It was modified for Wireshark by Gilbert Ramirez and others.
2009  */
2010 
2011 #define MAX_OFFSET_LEN   8       /* max length of hex offset of bytes */
2012 #define BYTES_PER_LINE  16      /* max byte values printed on a line */
2013 #define HEX_DUMP_LEN    (BYTES_PER_LINE*3)
2014                                 /* max number of characters hex dump takes -
2015                                    2 digits plus trailing blank */
2016 #define DATA_DUMP_LEN   (HEX_DUMP_LEN + 2 + BYTES_PER_LINE)
2017                                 /* number of characters those bytes take;
2018                                    3 characters per byte of hex dump,
2019                                    2 blanks separating hex from ASCII,
2020                                    1 character per byte of ASCII dump */
2021 #define MAX_LINE_LEN    (MAX_OFFSET_LEN + 2 + DATA_DUMP_LEN)
2022                                 /* number of characters per line;
2023                                    offset, 2 blanks separating offset
2024                                    from data dump, data dump */
2025 
2026 static gboolean
print_hex_data_buffer(print_stream_t * stream,const guchar * cp,guint length,packet_char_enc encoding)2027 print_hex_data_buffer(print_stream_t *stream, const guchar *cp,
2028                       guint length, packet_char_enc encoding)
2029 {
2030     register unsigned int ad, i, j, k, l;
2031     guchar                c;
2032     gchar                 line[MAX_LINE_LEN + 1];
2033     unsigned int          use_digits;
2034 
2035     static gchar binhex[16] = {
2036         '0', '1', '2', '3', '4', '5', '6', '7',
2037         '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
2038 
2039     /*
2040      * How many of the leading digits of the offset will we supply?
2041      * We always supply at least 4 digits, but if the maximum offset
2042      * won't fit in 4 digits, we use as many digits as will be needed.
2043      */
2044     if (((length - 1) & 0xF0000000) != 0)
2045         use_digits = 8; /* need all 8 digits */
2046     else if (((length - 1) & 0x0F000000) != 0)
2047         use_digits = 7; /* need 7 digits */
2048     else if (((length - 1) & 0x00F00000) != 0)
2049         use_digits = 6; /* need 6 digits */
2050     else if (((length - 1) & 0x000F0000) != 0)
2051         use_digits = 5; /* need 5 digits */
2052     else
2053         use_digits = 4; /* we'll supply 4 digits */
2054 
2055     ad = 0;
2056     i = 0;
2057     j = 0;
2058     k = 0;
2059     while (i < length) {
2060         if ((i & 15) == 0) {
2061             /*
2062              * Start of a new line.
2063              */
2064             j = 0;
2065             l = use_digits;
2066             do {
2067                 l--;
2068                 c = (ad >> (l*4)) & 0xF;
2069                 line[j++] = binhex[c];
2070             } while (l != 0);
2071             line[j++] = ' ';
2072             line[j++] = ' ';
2073             memset(line+j, ' ', DATA_DUMP_LEN);
2074 
2075             /*
2076              * Offset in line of ASCII dump.
2077              */
2078             k = j + HEX_DUMP_LEN + 2;
2079         }
2080         c = *cp++;
2081         line[j++] = binhex[c>>4];
2082         line[j++] = binhex[c&0xf];
2083         j++;
2084         if (encoding == PACKET_CHAR_ENC_CHAR_EBCDIC) {
2085             c = EBCDIC_to_ASCII1(c);
2086         }
2087         line[k++] = ((c >= ' ') && (c < 0x7f)) ? c : '.';
2088         i++;
2089         if (((i & 15) == 0) || (i == length)) {
2090             /*
2091              * We'll be starting a new line, or
2092              * we're finished printing this buffer;
2093              * dump out the line we've constructed,
2094              * and advance the offset.
2095              */
2096             line[k] = '\0';
2097             if (!print_line(stream, 0, line))
2098                 return FALSE;
2099             ad += 16;
2100         }
2101     }
2102     return TRUE;
2103 }
2104 
output_fields_num_fields(output_fields_t * fields)2105 gsize output_fields_num_fields(output_fields_t* fields)
2106 {
2107     ws_assert(fields);
2108 
2109     if (NULL == fields->fields) {
2110         return 0;
2111     } else {
2112         return fields->fields->len;
2113     }
2114 }
2115 
output_fields_free(output_fields_t * fields)2116 void output_fields_free(output_fields_t* fields)
2117 {
2118     ws_assert(fields);
2119 
2120     if (NULL != fields->fields) {
2121         gsize i;
2122 
2123         if (NULL != fields->field_indicies) {
2124             /* Keys are stored in fields->fields, values are
2125              * integers.
2126              */
2127             g_hash_table_destroy(fields->field_indicies);
2128         }
2129 
2130         if (NULL != fields->field_values) {
2131             g_free(fields->field_values);
2132         }
2133 
2134         for (i = 0; i < fields->fields->len; ++i) {
2135             gchar* field = (gchar *)g_ptr_array_index(fields->fields,i);
2136             g_free(field);
2137         }
2138         g_ptr_array_free(fields->fields, TRUE);
2139     }
2140 
2141     g_free(fields);
2142 }
2143 
2144 #define COLUMN_FIELD_FILTER  "_ws.col."
2145 
output_fields_add(output_fields_t * fields,const gchar * field)2146 void output_fields_add(output_fields_t *fields, const gchar *field)
2147 {
2148     gchar *field_copy;
2149 
2150     ws_assert(fields);
2151     ws_assert(field);
2152 
2153 
2154     if (NULL == fields->fields) {
2155         fields->fields = g_ptr_array_new();
2156     }
2157 
2158     field_copy = g_strdup(field);
2159 
2160     g_ptr_array_add(fields->fields, field_copy);
2161 
2162     /* See if we have a column as a field entry */
2163     if (!strncmp(field, COLUMN_FIELD_FILTER, strlen(COLUMN_FIELD_FILTER)))
2164         fields->includes_col_fields = TRUE;
2165 
2166 }
2167 
2168 static void
output_field_check(void * data,void * user_data)2169 output_field_check(void *data, void *user_data)
2170 {
2171     gchar *field = (gchar *)data;
2172     GSList **invalid_fields = (GSList **)user_data;
2173 
2174     if (!strncmp(field, COLUMN_FIELD_FILTER, strlen(COLUMN_FIELD_FILTER)))
2175         return;
2176 
2177     if (!proto_registrar_get_byname(field)) {
2178         *invalid_fields = g_slist_prepend(*invalid_fields, field);
2179     }
2180 
2181 }
2182 
2183 GSList *
output_fields_valid(output_fields_t * fields)2184 output_fields_valid(output_fields_t *fields)
2185 {
2186     GSList *invalid_fields = NULL;
2187     if (fields->fields == NULL) {
2188         return NULL;
2189     }
2190 
2191     g_ptr_array_foreach(fields->fields, output_field_check, &invalid_fields);
2192 
2193     return invalid_fields;
2194 }
2195 
output_fields_set_option(output_fields_t * info,gchar * option)2196 gboolean output_fields_set_option(output_fields_t *info, gchar *option)
2197 {
2198     const gchar *option_name;
2199     const gchar *option_value;
2200 
2201     ws_assert(info);
2202     ws_assert(option);
2203 
2204     if ('\0' == *option) {
2205         return FALSE; /* this happens if we're called from tshark -E '' */
2206     }
2207     option_name = strtok(option, "=");
2208     if (!option_name) {
2209         return FALSE;
2210     }
2211     option_value = option + strlen(option_name) + 1;
2212     if (*option_value == '\0') {
2213         return FALSE;
2214     }
2215 
2216     if (0 == strcmp(option_name, "header")) {
2217         switch (*option_value) {
2218         case 'n':
2219             info->print_header = FALSE;
2220             break;
2221         case 'y':
2222             info->print_header = TRUE;
2223             break;
2224         default:
2225             return FALSE;
2226         }
2227         return TRUE;
2228     }
2229     else if (0 == strcmp(option_name, "separator")) {
2230         switch (*option_value) {
2231         case '/':
2232             switch (*++option_value) {
2233             case 't':
2234                 info->separator = '\t';
2235                 break;
2236             case 's':
2237                 info->separator = ' ';
2238                 break;
2239             default:
2240                 info->separator = '\\';
2241             }
2242             break;
2243         default:
2244             info->separator = *option_value;
2245             break;
2246         }
2247         return TRUE;
2248     }
2249     else if (0 == strcmp(option_name, "occurrence")) {
2250         switch (*option_value) {
2251         case 'f':
2252         case 'l':
2253         case 'a':
2254             info->occurrence = *option_value;
2255             break;
2256         default:
2257             return FALSE;
2258         }
2259         return TRUE;
2260     }
2261     else if (0 == strcmp(option_name, "aggregator")) {
2262         switch (*option_value) {
2263         case '/':
2264             switch (*++option_value) {
2265             case 's':
2266                 info->aggregator = ' ';
2267                 break;
2268             default:
2269                 info->aggregator = '\\';
2270             }
2271             break;
2272         default:
2273             info->aggregator = *option_value;
2274             break;
2275         }
2276         return TRUE;
2277     }
2278     else if (0 == strcmp(option_name, "quote")) {
2279         switch (*option_value) {
2280         case 'd':
2281             info->quote = '"';
2282             break;
2283         case 's':
2284             info->quote = '\'';
2285             break;
2286         case 'n':
2287             info->quote = '\0';
2288             break;
2289         default:
2290             info->quote = '\0';
2291             return FALSE;
2292         }
2293         return TRUE;
2294     }
2295     else if (0 == strcmp(option_name, "bom")) {
2296         switch (*option_value) {
2297         case 'n':
2298             info->print_bom = FALSE;
2299             break;
2300         case 'y':
2301             info->print_bom = TRUE;
2302             break;
2303         default:
2304             return FALSE;
2305         }
2306         return TRUE;
2307     }
2308 
2309     return FALSE;
2310 }
2311 
output_fields_list_options(FILE * fh)2312 void output_fields_list_options(FILE *fh)
2313 {
2314     fprintf(fh, "TShark: The available options for field output \"E\" are:\n");
2315     fputs("bom=y|n    Prepend output with the UTF-8 BOM (def: N: no)\n", fh);
2316     fputs("header=y|n    Print field abbreviations as first line of output (def: N: no)\n", fh);
2317     fputs("separator=/t|/s|<character>   Set the separator to use;\n     \"/t\" = tab, \"/s\" = space (def: /t: tab)\n", fh);
2318     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);
2319     fputs("aggregator=,|/s|<character>   Set the aggregator to use;\n     \",\" = comma, \"/s\" = space (def: ,: comma)\n", fh);
2320     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);
2321 }
2322 
output_fields_has_cols(output_fields_t * fields)2323 gboolean output_fields_has_cols(output_fields_t* fields)
2324 {
2325     ws_assert(fields);
2326     return fields->includes_col_fields;
2327 }
2328 
write_fields_preamble(output_fields_t * fields,FILE * fh)2329 void write_fields_preamble(output_fields_t* fields, FILE *fh)
2330 {
2331     gsize i;
2332 
2333     ws_assert(fields);
2334     ws_assert(fh);
2335     ws_assert(fields->fields);
2336 
2337     if (fields->print_bom) {
2338         fputs(UTF8_BOM, fh);
2339     }
2340 
2341 
2342     if (!fields->print_header) {
2343         return;
2344     }
2345 
2346     for(i = 0; i < fields->fields->len; ++i) {
2347         const gchar* field = (const gchar *)g_ptr_array_index(fields->fields,i);
2348         if (i != 0 ) {
2349             fputc(fields->separator, fh);
2350         }
2351         fputs(field, fh);
2352     }
2353     fputc('\n', fh);
2354 }
2355 
format_field_values(output_fields_t * fields,gpointer field_index,gchar * value)2356 static void format_field_values(output_fields_t* fields, gpointer field_index, gchar* value)
2357 {
2358     guint      indx;
2359     GPtrArray* fv_p;
2360 
2361     if (NULL == value)
2362         return;
2363 
2364     /* Unwrap change made to disambiguiate zero / null */
2365     indx = GPOINTER_TO_UINT(field_index) - 1;
2366 
2367     if (fields->field_values[indx] == NULL) {
2368         fields->field_values[indx] = g_ptr_array_new();
2369     }
2370 
2371     /* Essentially: fieldvalues[indx] is a 'GPtrArray *' with each array entry */
2372     /*  pointing to a string which is (part of) the final output string.       */
2373 
2374     fv_p = fields->field_values[indx];
2375 
2376     switch (fields->occurrence) {
2377     case 'f':
2378         /* print the value of only the first occurrence of the field */
2379         if (g_ptr_array_len(fv_p) != 0) {
2380             /*
2381              * This isn't the first occurrence, so the value won't be used;
2382              * free it.
2383              */
2384             g_free(value);
2385             return;
2386         }
2387         break;
2388     case 'l':
2389         /* print the value of only the last occurrence of the field */
2390         if (g_ptr_array_len(fv_p) != 0) {
2391             /*
2392              * This isn't the first occurrence, so there's already a
2393              * value in the array, which won't be used; free the
2394              * first (only) element in the array, and then remove
2395              * it - this value will replace it.
2396              */
2397             g_free(g_ptr_array_index(fv_p, 0));
2398             g_ptr_array_set_size(fv_p, 0);
2399         }
2400         break;
2401     case 'a':
2402         /* print the value of all accurrences of the field */
2403         if (g_ptr_array_len(fv_p) != 0) {
2404             /*
2405              * This isn't the first occurrence. so add the "aggregator"
2406              * character as a separator between the previous element
2407              * and this element.
2408              */
2409             g_ptr_array_add(fv_p, (gpointer)g_strdup_printf("%c", fields->aggregator));
2410         }
2411         break;
2412     default:
2413         ws_assert_not_reached();
2414         break;
2415     }
2416 
2417     g_ptr_array_add(fv_p, (gpointer)value);
2418 }
2419 
proto_tree_get_node_field_values(proto_node * node,gpointer data)2420 static void proto_tree_get_node_field_values(proto_node *node, gpointer data)
2421 {
2422     write_field_data_t *call_data;
2423     field_info *fi;
2424     gpointer    field_index;
2425 
2426     call_data = (write_field_data_t *)data;
2427     fi = PNODE_FINFO(node);
2428 
2429     /* dissection with an invisible proto tree? */
2430     ws_assert(fi);
2431 
2432     field_index = g_hash_table_lookup(call_data->fields->field_indicies, fi->hfinfo->abbrev);
2433     if (NULL != field_index) {
2434         format_field_values(call_data->fields, field_index,
2435                             get_node_field_value(fi, call_data->edt) /* g_ alloc'd string */
2436             );
2437     }
2438 
2439     /* Recurse here. */
2440     if (node->first_child != NULL) {
2441         proto_tree_children_foreach(node, proto_tree_get_node_field_values,
2442                                     call_data);
2443     }
2444 }
2445 
write_specified_fields(fields_format format,output_fields_t * fields,epan_dissect_t * edt,column_info * cinfo,FILE * fh,json_dumper * dumper)2446 static void write_specified_fields(fields_format format, output_fields_t *fields, epan_dissect_t *edt, column_info *cinfo, FILE *fh, json_dumper *dumper)
2447 {
2448     gsize     i;
2449     gint      col;
2450     gchar    *col_name;
2451     gpointer  field_index;
2452 
2453     write_field_data_t data;
2454 
2455     ws_assert(fields);
2456     ws_assert(fields->fields);
2457     ws_assert(edt);
2458     /* JSON formats must go through json_dumper */
2459     if (format == FORMAT_JSON || format == FORMAT_EK) {
2460         ws_assert(!fh && dumper);
2461     } else {
2462         ws_assert(fh && !dumper);
2463     }
2464 
2465     data.fields = fields;
2466     data.edt = edt;
2467 
2468     if (NULL == fields->field_indicies) {
2469         /* Prepare a lookup table from string abbreviation for field to its index. */
2470         fields->field_indicies = g_hash_table_new(g_str_hash, g_str_equal);
2471 
2472         i = 0;
2473         while (i < fields->fields->len) {
2474             gchar *field = (gchar *)g_ptr_array_index(fields->fields, i);
2475             /* Store field indicies +1 so that zero is not a valid value,
2476              * and can be distinguished from NULL as a pointer.
2477              */
2478             ++i;
2479             g_hash_table_insert(fields->field_indicies, field, GUINT_TO_POINTER(i));
2480         }
2481     }
2482 
2483     /* Array buffer to store values for this packet              */
2484     /*  Allocate an array for the 'GPtrarray *' the first time   */
2485     /*   ths function is invoked for a file;                     */
2486     /*  Any and all 'GPtrArray *' are freed (after use) each     */
2487     /*   time (each packet) this function is invoked for a flle. */
2488     /* XXX: ToDo: use packet-scope'd memory & (if/when implemented) wmem ptr_array */
2489     if (NULL == fields->field_values)
2490         fields->field_values = g_new0(GPtrArray*, fields->fields->len);  /* free'd in output_fields_free() */
2491 
2492     proto_tree_children_foreach(edt->tree, proto_tree_get_node_field_values,
2493                                 &data);
2494 
2495     /* Add columns to fields */
2496     if (fields->includes_col_fields) {
2497         for (col = 0; col < cinfo->num_cols; col++) {
2498             if (!get_column_visible(col))
2499                 continue;
2500             /* Prepend COLUMN_FIELD_FILTER as the field name */
2501             col_name = g_strdup_printf("%s%s", COLUMN_FIELD_FILTER, cinfo->columns[col].col_title);
2502             field_index = g_hash_table_lookup(fields->field_indicies, col_name);
2503             g_free(col_name);
2504 
2505             if (NULL != field_index) {
2506                 format_field_values(fields, field_index, g_strdup(cinfo->columns[col].col_data));
2507             }
2508         }
2509     }
2510 
2511     switch (format) {
2512     case FORMAT_CSV:
2513         for(i = 0; i < fields->fields->len; ++i) {
2514             if (0 != i) {
2515                 fputc(fields->separator, fh);
2516             }
2517             if (NULL != fields->field_values[i]) {
2518                 GPtrArray *fv_p;
2519                 gchar * str;
2520                 gsize j;
2521                 fv_p = fields->field_values[i];
2522                 if (fields->quote != '\0') {
2523                     fputc(fields->quote, fh);
2524                 }
2525 
2526                 /* Output the array of (partial) field values */
2527                 for (j = 0; j < g_ptr_array_len(fv_p); j++ ) {
2528                     str = (gchar *)g_ptr_array_index(fv_p, j);
2529                     print_escaped_csv(fh, str);
2530                     g_free(str);
2531                 }
2532                 if (fields->quote != '\0') {
2533                     fputc(fields->quote, fh);
2534                 }
2535                 g_ptr_array_free(fv_p, TRUE);  /* get ready for the next packet */
2536                 fields->field_values[i] = NULL;
2537             }
2538         }
2539         break;
2540     case FORMAT_XML:
2541         for(i = 0; i < fields->fields->len; ++i) {
2542             gchar *field = (gchar *)g_ptr_array_index(fields->fields, i);
2543 
2544             if (NULL != fields->field_values[i]) {
2545                 GPtrArray *fv_p;
2546                 gchar * str;
2547                 gsize j;
2548                 fv_p = fields->field_values[i];
2549 
2550                 /* Output the array of (partial) field values */
2551                 for (j = 0; j < (g_ptr_array_len(fv_p)); j+=2 ) {
2552                     str = (gchar *)g_ptr_array_index(fv_p, j);
2553 
2554                     fprintf(fh, "  <field name=\"%s\" value=", field);
2555                     fputs("\"", fh);
2556                     print_escaped_xml(fh, str);
2557                     fputs("\"/>\n", fh);
2558                     g_free(str);
2559                 }
2560                 g_ptr_array_free(fv_p, TRUE);  /* get ready for the next packet */
2561                 fields->field_values[i] = NULL;
2562             }
2563         }
2564         break;
2565     case FORMAT_JSON:
2566         json_dumper_begin_object(dumper);
2567         for(i = 0; i < fields->fields->len; ++i) {
2568             gchar *field = (gchar *)g_ptr_array_index(fields->fields, i);
2569 
2570             if (NULL != fields->field_values[i]) {
2571                 GPtrArray *fv_p;
2572                 gchar * str;
2573                 gsize j;
2574                 fv_p = fields->field_values[i];
2575 
2576                 json_dumper_set_member_name(dumper, field);
2577                 json_dumper_begin_array(dumper);
2578 
2579                 /* Output the array of (partial) field values */
2580                 for (j = 0; j < (g_ptr_array_len(fv_p)); j += 2) {
2581                     str = (gchar *) g_ptr_array_index(fv_p, j);
2582                     json_dumper_value_string(dumper, str);
2583                     g_free(str);
2584                 }
2585 
2586                 json_dumper_end_array(dumper);
2587 
2588                 g_ptr_array_free(fv_p, TRUE);  /* get ready for the next packet */
2589                 fields->field_values[i] = NULL;
2590             }
2591         }
2592         json_dumper_end_object(dumper);
2593         break;
2594     case FORMAT_EK:
2595         for(i = 0; i < fields->fields->len; ++i) {
2596             gchar *field = (gchar *)g_ptr_array_index(fields->fields, i);
2597 
2598             if (NULL != fields->field_values[i]) {
2599                 GPtrArray *fv_p;
2600                 gchar * str;
2601                 gsize j;
2602                 fv_p = fields->field_values[i];
2603 
2604                 json_dumper_set_member_name(dumper, field);
2605                 json_dumper_begin_array(dumper);
2606 
2607                 /* Output the array of (partial) field values */
2608                 for (j = 0; j < (g_ptr_array_len(fv_p)); j += 2) {
2609                     str = (gchar *)g_ptr_array_index(fv_p, j);
2610                     json_dumper_value_string(dumper, str);
2611                     g_free(str);
2612                 }
2613 
2614                 json_dumper_end_array(dumper);
2615 
2616                 g_ptr_array_free(fv_p, TRUE);  /* get ready for the next packet */
2617                 fields->field_values[i] = NULL;
2618             }
2619         }
2620         break;
2621 
2622     default:
2623         fprintf(stderr, "Unknown fields format %d\n", format);
2624         ws_assert_not_reached();
2625         break;
2626     }
2627 }
2628 
write_fields_finale(output_fields_t * fields _U_,FILE * fh _U_)2629 void write_fields_finale(output_fields_t* fields _U_ , FILE *fh _U_)
2630 {
2631     /* Nothing to do */
2632 }
2633 
2634 /* Returns an g_malloced string */
get_node_field_value(field_info * fi,epan_dissect_t * edt)2635 gchar* get_node_field_value(field_info* fi, epan_dissect_t* edt)
2636 {
2637     if (fi->hfinfo->id == hf_text_only) {
2638         /* Text label.
2639          * Get the text */
2640         if (fi->rep) {
2641             return g_strdup(fi->rep->representation);
2642         }
2643         else {
2644             return get_field_hex_value(edt->pi.data_src, fi);
2645         }
2646     }
2647     else if (fi->hfinfo->id == proto_data) {
2648         /* Uninterpreted data, i.e., the "Data" protocol, is
2649          * printed as a field instead of a protocol. */
2650         return get_field_hex_value(edt->pi.data_src, fi);
2651     }
2652     else {
2653         /* Normal protocols and fields */
2654         gchar      *dfilter_string;
2655 
2656         switch (fi->hfinfo->type)
2657         {
2658         case FT_PROTOCOL:
2659             /* Print out the full details for the protocol. */
2660             if (fi->rep) {
2661                 return g_strdup(fi->rep->representation);
2662             } else {
2663                 /* Just print out the protocol abbreviation */
2664                 return g_strdup(fi->hfinfo->abbrev);
2665             }
2666         case FT_NONE:
2667             /* Return "1" so that the presence of a field of type
2668              * FT_NONE can be checked when using -T fields */
2669             return g_strdup("1");
2670         case FT_UINT_BYTES:
2671         case FT_BYTES:
2672             {
2673                 gchar *ret;
2674                 guint8 *bytes = (guint8 *)fvalue_get(&fi->value);
2675                 if (bytes) {
2676                     dfilter_string = (gchar *)wmem_alloc(NULL, 3*fvalue_length(&fi->value));
2677                     switch (fi->hfinfo->display) {
2678                     case SEP_DOT:
2679                         ret = bytes_to_hexstr_punct(dfilter_string, bytes, fvalue_length(&fi->value), '.');
2680                         break;
2681                     case SEP_DASH:
2682                         ret = bytes_to_hexstr_punct(dfilter_string, bytes, fvalue_length(&fi->value), '-');
2683                         break;
2684                     case SEP_COLON:
2685                         ret = bytes_to_hexstr_punct(dfilter_string, bytes, fvalue_length(&fi->value), ':');
2686                         break;
2687                     case SEP_SPACE:
2688                         ret = bytes_to_hexstr_punct(dfilter_string, bytes, fvalue_length(&fi->value), ' ');
2689                         break;
2690                     case BASE_NONE:
2691                     default:
2692                         ret = bytes_to_hexstr(dfilter_string, bytes, fvalue_length(&fi->value));
2693                         break;
2694                     }
2695                     *ret = '\0';
2696                     ret = g_strdup(dfilter_string);
2697                     wmem_free(NULL, dfilter_string);
2698                 } else {
2699                     if (fi->hfinfo->display & BASE_ALLOW_ZERO) {
2700                         ret = g_strdup("<none>");
2701                     } else {
2702                         ret = g_strdup("<MISSING>");
2703                     }
2704                 }
2705                 return ret;
2706             }
2707             break;
2708         default:
2709             dfilter_string = fvalue_to_string_repr(NULL, &fi->value, FTREPR_DISPLAY, fi->hfinfo->display);
2710             if (dfilter_string != NULL) {
2711                 gchar* ret = g_strdup(dfilter_string);
2712                 wmem_free(NULL, dfilter_string);
2713                 return ret;
2714             } else {
2715                 return get_field_hex_value(edt->pi.data_src, fi);
2716             }
2717         }
2718     }
2719 }
2720 
2721 static gchar*
get_field_hex_value(GSList * src_list,field_info * fi)2722 get_field_hex_value(GSList *src_list, field_info *fi)
2723 {
2724     const guint8 *pd;
2725 
2726     if (!fi->ds_tvb)
2727         return NULL;
2728 
2729     if (fi->length > tvb_captured_length_remaining(fi->ds_tvb, fi->start)) {
2730         return g_strdup("field length invalid!");
2731     }
2732 
2733     /* Find the data for this field. */
2734     pd = get_field_data(src_list, fi);
2735 
2736     if (pd) {
2737         int        i;
2738         gchar     *buffer;
2739         gchar     *p;
2740         int        len;
2741         const int  chars_per_byte = 2;
2742 
2743         len    = chars_per_byte * fi->length;
2744         buffer = (gchar *)g_malloc(sizeof(gchar)*(len + 1));
2745         buffer[len] = '\0'; /* Ensure NULL termination in bad cases */
2746         p = buffer;
2747         /* Print a simple hex dump */
2748         for (i = 0 ; i < fi->length; i++) {
2749             g_snprintf(p, chars_per_byte+1, "%02x", pd[i]);
2750             p += chars_per_byte;
2751         }
2752         return buffer;
2753     } else {
2754         return NULL;
2755     }
2756 }
2757 
output_fields_new(void)2758 output_fields_t* output_fields_new(void)
2759 {
2760     output_fields_t* fields     = g_new(output_fields_t, 1);
2761     fields->print_bom           = FALSE;
2762     fields->print_header        = FALSE;
2763     fields->separator           = '\t';
2764     fields->occurrence          = 'a';
2765     fields->aggregator          = ',';
2766     fields->fields              = NULL; /*Do lazy initialisation */
2767     fields->field_indicies      = NULL;
2768     fields->field_values        = NULL;
2769     fields->quote               ='\0';
2770     fields->includes_col_fields = FALSE;
2771     return fields;
2772 }
2773 
2774 /*
2775  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
2776  *
2777  * Local variables:
2778  * c-basic-offset: 4
2779  * tab-width: 8
2780  * indent-tabs-mode: nil
2781  * End:
2782  *
2783  * vi: set shiftwidth=4 tabstop=8 expandtab:
2784  * :indentSize=4:tabSize=8:noTabs=true:
2785  */
2786