2 * Routines for printing packet analysis trees.
4 * Gilbert Ramirez <gram@alumni.rice.edu>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
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-int.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 <version_info.h>
33 #include <wsutil/utf8_entities.h>
34 #include <ftypes/ftypes-int.h>
36 #define PDML_VERSION "0"
37 #define PSML_VERSION "0"
41 print_stream_t
*stream
;
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 */
55 pf_flags filter_flags
;
61 pf_flags filter_flags
;
64 proto_node_children_grouper_func node_children_grouper
;
69 output_fields_t
*fields
;
73 struct _output_fields
{
75 gboolean print_header
;
80 GHashTable
*field_indicies
;
81 GPtrArray
**field_values
;
83 gboolean includes_col_fields
;
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
,
100 static void print_escaped_xml(FILE *fh
, const char *unescaped_string
);
101 static void print_escaped_csv(FILE *fh
, const char *unescaped_string
);
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
,
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_children(proto_node
*node
, write_json_data
*data
);
116 static void write_json_proto_node_value(proto_node
*node
, write_json_data
*data
);
117 static void write_json_proto_node_no_value(proto_node
*node
, write_json_data
*data
);
118 static const char *proto_node_to_json_key(proto_node
*node
);
120 static void print_pdml_geninfo(epan_dissect_t
*edt
, FILE *fh
);
121 static void write_ek_summary(column_info
*cinfo
, write_json_data
*pdata
);
123 static void proto_tree_get_node_field_values(proto_node
*node
, gpointer data
);
125 /* Cache the protocols and field handles that the print functionality needs
126 This helps break explicit dependency on the dissectors. */
127 static int proto_data
= -1;
128 static int proto_frame
= -1;
130 void print_cache_field_handles(void)
132 proto_data
= proto_get_id_by_short_name("Data");
133 proto_frame
= proto_get_id_by_short_name("Frame");
137 proto_tree_print(print_dissections_e print_dissections
, gboolean print_hex
,
138 epan_dissect_t
*edt
, GHashTable
*output_only_tables
,
139 print_stream_t
*stream
)
143 /* Create the output */
145 data
.stream
= stream
;
147 data
.src_list
= edt
->pi
.data_src
;
148 data
.encoding
= (packet_char_enc
)edt
->pi
.fd
->encoding
;
149 data
.print_dissections
= print_dissections
;
150 /* If we're printing the entire packet in hex, don't
151 print uninterpreted data fields in hex as well. */
152 data
.print_hex_for_data
= !print_hex
;
153 data
.output_only_tables
= output_only_tables
;
155 proto_tree_children_foreach(edt
->tree
, proto_tree_print_node
, &data
);
159 /* Print a tree's data, and any child nodes. */
161 proto_tree_print_node(proto_node
*node
, gpointer data
)
163 field_info
*fi
= PNODE_FINFO(node
);
164 print_data
*pdata
= (print_data
*) data
;
166 gchar label_str
[ITEM_LABEL_LENGTH
];
169 /* dissection with an invisible proto tree? */
172 /* Don't print invisible entries. */
173 if (proto_item_is_hidden(node
) && (prefs
.display_hidden_proto_items
== FALSE
))
176 /* Give up if we've already gotten an error. */
180 /* was a free format label produced? */
182 label_ptr
= fi
->rep
->representation
;
184 else { /* no, make a generic label */
185 label_ptr
= label_str
;
186 proto_item_fill_label(fi
, label_str
);
189 if (proto_item_is_generated(node
))
190 label_ptr
= g_strconcat("[", label_ptr
, "]", NULL
);
192 pdata
->success
= print_line(pdata
->stream
, pdata
->level
, label_ptr
);
194 if (proto_item_is_generated(node
))
201 * If -O is specified, only display the protocols which are in the
202 * lookup table. Only check on the first level: once we start printing
203 * a tree, print the rest of the subtree. Otherwise we won't print
204 * subitems whose abbreviation doesn't match the protocol--for example
205 * text items (whose abbreviation is simply "text").
207 if ((pdata
->output_only_tables
!= NULL
) && (pdata
->level
== 0)
208 && (g_hash_table_lookup(pdata
->output_only_tables
, fi
->hfinfo
->abbrev
) == NULL
)) {
212 /* If it's uninterpreted data, dump it (unless our caller will
213 be printing the entire packet in hex). */
214 if ((fi
->hfinfo
->id
== proto_data
) && (pdata
->print_hex_for_data
)) {
216 * Find the data for this field.
218 pd
= get_field_data(pdata
->src_list
, fi
);
220 if (!print_line(pdata
->stream
, 0, "")) {
221 pdata
->success
= FALSE
;
224 if (!print_hex_data_buffer(pdata
->stream
, pd
,
225 fi
->length
, pdata
->encoding
)) {
226 pdata
->success
= FALSE
;
232 /* If we're printing all levels, or if this node is one with a
233 subtree and its subtree is expanded, recurse into the subtree,
235 g_assert((fi
->tree_type
>= -1) && (fi
->tree_type
< num_tree_types
));
236 if ((pdata
->print_dissections
== print_dissections_expanded
) ||
237 ((pdata
->print_dissections
== print_dissections_as_displayed
) &&
238 (fi
->tree_type
>= 0) && tree_expanded(fi
->tree_type
))) {
239 if (node
->first_child
!= NULL
) {
241 proto_tree_children_foreach(node
,
242 proto_tree_print_node
, pdata
);
250 #define PDML2HTML_XSL "pdml2html.xsl"
252 write_pdml_preamble(FILE *fh
, const gchar
*filename
)
254 time_t t
= time(NULL
);
255 struct tm
* timeinfo
;
259 /* Create the output */
260 timeinfo
= localtime(&t
);
261 if (timeinfo
!= NULL
) {
262 fmt_ts
= asctime(timeinfo
);
263 fmt_ts
[strlen(fmt_ts
)-1] = 0; /* overwrite \n */
266 ts
= "Not representable";
268 fprintf(fh
, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
269 fprintf(fh
, "<?xml-stylesheet type=\"text/xsl\" href=\"" PDML2HTML_XSL
"\"?>\n");
270 fprintf(fh
, "<!-- You can find " PDML2HTML_XSL
" in %s or at https://gitlab.com/wireshark/wireshark/-/raw/master/" PDML2HTML_XSL
". -->\n", get_datafile_dir());
271 fprintf(fh
, "<pdml version=\"" PDML_VERSION
"\" creator=\"%s/%s\" time=\"%s\" capture_file=\"", PACKAGE
, VERSION
, ts
);
273 /* \todo filename should be converted to UTF-8. */
274 print_escaped_xml(fh
, filename
);
276 fprintf(fh
, "\">\n");
279 /* Check if the str match the protocolfilter. json_filter is space
280 delimited string and str need to exact-match to one of the value. */
281 static gboolean
check_protocolfilter(gchar
**protocolfilter
, const char *str
)
283 gboolean res
= FALSE
;
286 if (str
== NULL
|| protocolfilter
== NULL
) {
290 for (ptr
= protocolfilter
; *ptr
; ptr
++) {
291 if (strcmp(*ptr
, str
) == 0) {
301 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 write_pdml_data data
;
304 const color_filter_t
*cfp
;
309 cfp
= edt
->pi
.fd
->color_filter
;
311 /* Create the output */
312 if (use_color
&& (cfp
!= NULL
)) {
313 fprintf(fh
, "<packet foreground='#%06x' background='#%06x'>\n",
314 color_t_to_rgb(&cfp
->fg_color
),
315 color_t_to_rgb(&cfp
->bg_color
));
317 fprintf(fh
, "<packet>\n");
320 /* Print a "geninfo" protocol as required by PDML */
321 print_pdml_geninfo(edt
, fh
);
323 if (fields
== NULL
|| fields
->fields
== NULL
) {
324 /* Write out all fields */
327 data
.src_list
= edt
->pi
.data_src
;
328 data
.filter
= protocolfilter
;
329 data
.filter_flags
= protocolfilter_flags
;
331 proto_tree_children_foreach(edt
->tree
, proto_tree_write_node_pdml
,
334 /* Write out specified fields */
335 write_specified_fields(FORMAT_XML
, fields
, edt
, cinfo
, fh
, NULL
);
338 fprintf(fh
, "</packet>\n\n");
342 write_ek_proto_tree(output_fields_t
* fields
,
343 gboolean print_summary
, gboolean print_hex
,
344 gchar
**protocolfilter
,
345 pf_flags protocolfilter_flags
, epan_dissect_t
*edt
,
352 write_json_data data
;
354 json_dumper dumper
= {
356 .flags
= JSON_DUMPER_DOT_TO_UNDERSCORE
359 data
.dumper
= &dumper
;
361 json_dumper_begin_object(&dumper
);
362 json_dumper_set_member_name(&dumper
, "index");
363 json_dumper_begin_object(&dumper
);
364 write_json_index(&dumper
, edt
);
365 json_dumper_set_member_name(&dumper
, "_type");
366 json_dumper_value_string(&dumper
, "doc");
367 json_dumper_end_object(&dumper
);
368 json_dumper_end_object(&dumper
);
369 json_dumper_finish(&dumper
);
370 json_dumper_begin_object(&dumper
);
372 /* Timestamp added for time indexing in Elasticsearch */
373 json_dumper_set_member_name(&dumper
, "timestamp");
374 json_dumper_value_anyf(&dumper
, "\"%" G_GUINT64_FORMAT
"%03d\"", (guint64
)edt
->pi
.abs_ts
.secs
, edt
->pi
.abs_ts
.nsecs
/1000000);
377 write_ek_summary(edt
->pi
.cinfo
, &data
);
380 json_dumper_set_member_name(&dumper
, "layers");
381 json_dumper_begin_object(&dumper
);
383 if (fields
== NULL
|| fields
->fields
== NULL
) {
384 /* Write out all fields */
385 data
.src_list
= edt
->pi
.data_src
;
386 data
.filter
= protocolfilter
;
387 data
.filter_flags
= protocolfilter_flags
;
388 data
.print_hex
= print_hex
;
389 proto_tree_write_node_ek(edt
->tree
, &data
);
391 /* Write out specified fields */
392 write_specified_fields(FORMAT_EK
, fields
, edt
, cinfo
, NULL
, data
.dumper
);
395 json_dumper_end_object(&dumper
);
397 json_dumper_end_object(&dumper
);
398 json_dumper_finish(&dumper
);
402 write_fields_proto_tree(output_fields_t
* fields
, epan_dissect_t
*edt
, column_info
*cinfo
, FILE *fh
)
407 /* Create the output */
408 write_specified_fields(FORMAT_CSV
, fields
, edt
, cinfo
, fh
, NULL
);
411 /* Indent to the correct level */
412 static void print_indent(int level
, FILE *fh
)
414 /* Use a buffer pre-filed with spaces */
415 #define MAX_INDENT 2048
416 static char spaces
[MAX_INDENT
];
417 static gboolean inited
= FALSE
;
419 for (int n
=0; n
< MAX_INDENT
; n
++) {
429 /* Temp terminate at right length and write to fh. */
430 spaces
[MIN(level
*2, MAX_INDENT
-1)] ='\0';
432 spaces
[MIN(level
*2, MAX_INDENT
-1)] =' ';
435 /* Write out a tree's data, and any child nodes, as PDML */
437 proto_tree_write_node_pdml(proto_node
*node
, gpointer data
)
439 field_info
*fi
= PNODE_FINFO(node
);
440 write_pdml_data
*pdata
= (write_pdml_data
*) data
;
441 const gchar
*label_ptr
;
442 gchar label_str
[ITEM_LABEL_LENGTH
];
443 char *dfilter_string
;
444 gboolean wrap_in_fake_protocol
;
446 /* dissection with an invisible proto tree? */
449 /* Will wrap up top-level field items inside a fake protocol wrapper to
450 preserve the PDML schema */
451 wrap_in_fake_protocol
=
452 (((fi
->hfinfo
->type
!= FT_PROTOCOL
) ||
453 (fi
->hfinfo
->id
== proto_data
)) &&
454 (pdata
->level
== 0));
456 print_indent(pdata
->level
+ 1, pdata
->fh
);
458 if (wrap_in_fake_protocol
) {
459 /* Open fake protocol wrapper */
460 fputs("<proto name=\"fake-field-wrapper\">\n", pdata
->fh
);
463 print_indent(pdata
->level
+ 1, pdata
->fh
);
466 /* Text label. It's printed as a field with no name. */
467 if (fi
->hfinfo
->id
== hf_text_only
) {
470 label_ptr
= fi
->rep
->representation
;
475 /* Show empty name since it is a required field */
476 fputs("<field name=\"", pdata
->fh
);
477 fputs("\" show=\"", pdata
->fh
);
478 print_escaped_xml(pdata
->fh
, label_ptr
);
480 fprintf(pdata
->fh
, "\" size=\"%d", fi
->length
);
481 if (node
->parent
&& node
->parent
->finfo
&& (fi
->start
< node
->parent
->finfo
->start
)) {
482 fprintf(pdata
->fh
, "\" pos=\"%d", node
->parent
->finfo
->start
+ fi
->start
);
484 fprintf(pdata
->fh
, "\" pos=\"%d", fi
->start
);
487 if (fi
->length
> 0) {
488 fputs("\" value=\"", pdata
->fh
);
489 pdml_write_field_hex_value(pdata
, fi
);
492 if (node
->first_child
!= NULL
) {
493 fputs("\">\n", pdata
->fh
);
495 fputs("\"/>\n", pdata
->fh
);
499 /* Uninterpreted data, i.e., the "Data" protocol, is
500 * printed as a field instead of a protocol. */
501 else if (fi
->hfinfo
->id
== proto_data
) {
502 /* Write out field with data */
503 fputs("<field name=\"data\" value=\"", pdata
->fh
);
504 pdml_write_field_hex_value(pdata
, fi
);
505 fputs("\">\n", pdata
->fh
);
507 /* Normal protocols and fields */
508 if ((fi
->hfinfo
->type
== FT_PROTOCOL
) && (fi
->hfinfo
->id
!= proto_expert
)) {
509 fputs("<proto name=\"", pdata
->fh
);
511 fputs("<field name=\"", pdata
->fh
);
513 print_escaped_xml(pdata
->fh
, fi
->hfinfo
->abbrev
);
517 * https://wayback.archive.org/web/20150330045501/http://www.nbee.org/doku.php?id=netpdl:pdml_specification
519 * the show fields contains things in 'human readable' format
520 * showname: contains only the name of the field
521 * show: contains only the data of the field
522 * showdtl: contains additional details of the field data
523 * showmap: contains mappings of the field data (e.g. the hostname to an IP address)
525 * XXX - the showname shouldn't contain the field data itself
526 * (like it's contained in the fi->rep->representation).
527 * Unfortunately, we don't have the field data representation for
528 * all fields, so this isn't currently possible */
529 fputs("\" showname=\"", pdata
->fh
);
530 print_escaped_xml(pdata
->fh
, fi
->hfinfo
->name
);
534 fputs("\" showname=\"", pdata
->fh
);
535 print_escaped_xml(pdata
->fh
, fi
->rep
->representation
);
537 label_ptr
= label_str
;
538 proto_item_fill_label(fi
, label_str
);
539 fputs("\" showname=\"", pdata
->fh
);
540 print_escaped_xml(pdata
->fh
, label_ptr
);
543 if (proto_item_is_hidden(node
) && (prefs
.display_hidden_proto_items
== FALSE
))
544 fprintf(pdata
->fh
, "\" hide=\"yes");
546 fprintf(pdata
->fh
, "\" size=\"%d", fi
->length
);
547 if (node
->parent
&& node
->parent
->finfo
&& (fi
->start
< node
->parent
->finfo
->start
)) {
548 fprintf(pdata
->fh
, "\" pos=\"%d", node
->parent
->finfo
->start
+ fi
->start
);
550 fprintf(pdata
->fh
, "\" pos=\"%d", fi
->start
);
552 /* fprintf(pdata->fh, "\" id=\"%d", fi->hfinfo->id);*/
554 /* show, value, and unmaskedvalue attributes */
555 switch (fi
->hfinfo
->type
)
560 fputs("\" show=\"\" value=\"", pdata
->fh
);
563 dfilter_string
= fvalue_to_string_repr(NULL
, &fi
->value
, FTREPR_DISPLAY
, fi
->hfinfo
->display
);
564 if (dfilter_string
!= NULL
) {
566 fputs("\" show=\"", pdata
->fh
);
567 print_escaped_xml(pdata
->fh
, dfilter_string
);
569 wmem_free(NULL
, dfilter_string
);
572 * XXX - should we omit "value" for any fields?
573 * What should we do for fields whose length is 0?
574 * They might come from a pseudo-header or from
575 * the capture header (e.g., time stamps), or
576 * they might be generated fields.
578 if (fi
->length
> 0) {
579 fputs("\" value=\"", pdata
->fh
);
581 if (fi
->hfinfo
->bitmask
!=0) {
582 switch (fi
->value
.ftype
->ftype
) {
587 fprintf(pdata
->fh
, "%X", (guint
) fvalue_get_sinteger(&fi
->value
));
594 fprintf(pdata
->fh
, "%X", fvalue_get_uinteger(&fi
->value
));
600 fprintf(pdata
->fh
, "%" G_GINT64_MODIFIER
"X", fvalue_get_sinteger64(&fi
->value
));
607 fprintf(pdata
->fh
, "%" G_GINT64_MODIFIER
"X", fvalue_get_uinteger64(&fi
->value
));
610 g_assert_not_reached();
612 fputs("\" unmaskedvalue=\"", pdata
->fh
);
613 pdml_write_field_hex_value(pdata
, fi
);
615 pdml_write_field_hex_value(pdata
, fi
);
620 if (node
->first_child
!= NULL
) {
621 fputs("\">\n", pdata
->fh
);
622 } else if (fi
->hfinfo
->id
== proto_data
) {
623 fputs("\">\n", pdata
->fh
);
625 fputs("\"/>\n", pdata
->fh
);
629 /* We print some levels for PDML. Recurse here. */
630 if (node
->first_child
!= NULL
) {
631 if (pdata
->filter
== NULL
|| check_protocolfilter(pdata
->filter
, fi
->hfinfo
->abbrev
)) {
632 gchar
**_filter
= NULL
;
633 /* Remove protocol filter for children, if children should be included */
634 if ((pdata
->filter_flags
&PF_INCLUDE_CHILDREN
) == PF_INCLUDE_CHILDREN
) {
635 _filter
= pdata
->filter
;
636 pdata
->filter
= NULL
;
640 proto_tree_children_foreach(node
,
641 proto_tree_write_node_pdml
, pdata
);
644 /* Put protocol filter back */
645 if ((pdata
->filter_flags
&PF_INCLUDE_CHILDREN
) == PF_INCLUDE_CHILDREN
) {
646 pdata
->filter
= _filter
;
649 print_indent(pdata
->level
+ 2, pdata
->fh
);
651 /* print dummy field */
652 fputs("<field name=\"filtered\" value=\"", pdata
->fh
);
653 print_escaped_xml(pdata
->fh
, fi
->hfinfo
->abbrev
);
654 fputs("\" />\n", pdata
->fh
);
658 /* Take back the extra level we added for fake wrapper protocol */
659 if (wrap_in_fake_protocol
) {
663 if (node
->first_child
!= NULL
) {
664 print_indent(pdata
->level
+ 1, pdata
->fh
);
666 /* Close off current element */
667 /* Data and expert "protocols" use simple tags */
668 if ((fi
->hfinfo
->id
!= proto_data
) && (fi
->hfinfo
->id
!= proto_expert
)) {
669 if (fi
->hfinfo
->type
== FT_PROTOCOL
) {
670 fputs("</proto>\n", pdata
->fh
);
672 fputs("</field>\n", pdata
->fh
);
675 fputs("</field>\n", pdata
->fh
);
679 /* Close off fake wrapper protocol */
680 if (wrap_in_fake_protocol
) {
681 print_indent(pdata
->level
+ 1, pdata
->fh
);
682 fputs("</proto>\n", pdata
->fh
);
687 write_json_preamble(FILE *fh
)
689 json_dumper dumper
= {
691 .flags
= JSON_DUMPER_FLAGS_PRETTY_PRINT
693 json_dumper_begin_array(&dumper
);
698 write_json_finale(json_dumper
*dumper
)
700 json_dumper_end_array(dumper
);
701 json_dumper_finish(dumper
);
705 write_json_index(json_dumper
*dumper
, epan_dissect_t
*edt
)
708 struct tm
* timeinfo
;
711 timeinfo
= localtime(&edt
->pi
.abs_ts
.secs
);
712 if (timeinfo
!= NULL
) {
713 strftime(ts
, sizeof(ts
), "%Y-%m-%d", timeinfo
);
715 g_strlcpy(ts
, "XXXX-XX-XX", sizeof(ts
)); /* XXX - better way of saying "Not representable"? */
717 json_dumper_set_member_name(dumper
, "_index");
718 str
= g_strdup_printf("packets-%s", ts
);
719 json_dumper_value_string(dumper
, str
);
724 write_json_proto_tree(output_fields_t
* fields
,
725 print_dissections_e print_dissections
,
726 gboolean print_hex
, gchar
**protocolfilter
,
727 pf_flags protocolfilter_flags
, epan_dissect_t
*edt
,
729 proto_node_children_grouper_func node_children_grouper
,
732 write_json_data data
;
734 data
.dumper
= dumper
;
736 json_dumper_begin_object(dumper
);
737 write_json_index(dumper
, edt
);
738 json_dumper_set_member_name(dumper
, "_type");
739 json_dumper_value_string(dumper
, "doc");
740 json_dumper_set_member_name(dumper
, "_score");
741 json_dumper_value_string(dumper
, NULL
);
742 json_dumper_set_member_name(dumper
, "_source");
743 json_dumper_begin_object(dumper
);
744 json_dumper_set_member_name(dumper
, "layers");
746 if (fields
== NULL
|| fields
->fields
== NULL
) {
747 /* Write out all fields */
748 data
.src_list
= edt
->pi
.data_src
;
749 data
.filter
= protocolfilter
;
750 data
.filter_flags
= protocolfilter_flags
;
751 data
.print_hex
= print_hex
;
752 data
.print_text
= TRUE
;
753 if (print_dissections
== print_dissections_none
) {
754 data
.print_text
= FALSE
;
756 data
.node_children_grouper
= node_children_grouper
;
758 write_json_proto_node_children(edt
->tree
, &data
);
760 write_specified_fields(FORMAT_JSON
, fields
, edt
, cinfo
, NULL
, dumper
);
763 json_dumper_end_object(dumper
);
764 json_dumper_end_object(dumper
);
768 * Write a json object containing a list of key:value pairs where each key:value pair corresponds to a different json
769 * key and its associated nodes in the proto_tree.
770 * @param proto_node_list_head A 2-dimensional list containing a list of values for each different node json key. The
771 * elements themselves are a linked list of values associated with the same json key.
772 * @param pdata json writing metadata
775 write_json_proto_node_list(GSList
*proto_node_list_head
, write_json_data
*pdata
)
777 GSList
*current_node
= proto_node_list_head
;
779 json_dumper_begin_object(pdata
->dumper
);
781 // Loop over each list of nodes (differentiated by json key) and write the associated json key:value pair in the
783 while (current_node
!= NULL
) {
784 // Get the list of values for the current json key.
785 GSList
*node_values_list
= (GSList
*) current_node
->data
;
787 // Retrieve the json key from the first value.
788 proto_node
*first_value
= (proto_node
*) node_values_list
->data
;
789 const char *json_key
= proto_node_to_json_key(first_value
);
790 // Check if the current json key is filtered from the output with the "-j" cli option.
791 gboolean is_filtered
= pdata
->filter
!= NULL
&& !check_protocolfilter(pdata
->filter
, json_key
);
793 field_info
*fi
= first_value
->finfo
;
794 char *value_string_repr
= fvalue_to_string_repr(NULL
, &fi
->value
, FTREPR_DISPLAY
, fi
->hfinfo
->display
);
796 // We assume all values of a json key have roughly the same layout. Thus we can use the first value to derive
797 // attributes of all the values.
798 gboolean has_value
= value_string_repr
!= NULL
;
799 gboolean has_children
= first_value
->first_child
!= NULL
;
800 gboolean is_pseudo_text_field
= fi
->hfinfo
->id
== 0;
802 wmem_free(NULL
, value_string_repr
); // fvalue_to_string_repr returns allocated buffer
804 // "-x" command line option. A "_raw" suffix is added to the json key so the textual value can be printed
805 // with the original json key. If both hex and text writing are enabled the raw information of fields whose
806 // length is equal to 0 is not written to the output. If the field is a special text pseudo field no raw
807 // information is written either.
808 if (pdata
->print_hex
&& (!pdata
->print_text
|| fi
->length
> 0) && !is_pseudo_text_field
) {
809 write_json_proto_node(node_values_list
, "_raw", write_json_proto_node_hex_dump
, pdata
);
812 if (pdata
->print_text
&& has_value
) {
813 write_json_proto_node(node_values_list
, "", write_json_proto_node_value
, pdata
);
817 // If a node has both a value and a set of children we print the value and the children in separate
818 // key:value pairs. These can't have the same key so whenever a value is already printed with the node
819 // json key we print the children with the same key with a "_tree" suffix added.
820 char *suffix
= has_value
? "_tree": "";
823 write_json_proto_node(node_values_list
, suffix
, write_json_proto_node_filtered
, pdata
);
825 // Remove protocol filter for children, if children should be included. This functionality is enabled
826 // with the "-J" command line option. We save the filter so it can be reenabled when we are done with
827 // the current key:value pair.
828 gchar
**_filter
= NULL
;
829 if ((pdata
->filter_flags
&PF_INCLUDE_CHILDREN
) == PF_INCLUDE_CHILDREN
) {
830 _filter
= pdata
->filter
;
831 pdata
->filter
= NULL
;
834 write_json_proto_node(node_values_list
, suffix
, write_json_proto_node_children
, pdata
);
836 // Put protocol filter back
837 if ((pdata
->filter_flags
&PF_INCLUDE_CHILDREN
) == PF_INCLUDE_CHILDREN
) {
838 pdata
->filter
= _filter
;
843 if (!has_value
&& !has_children
&& (pdata
->print_text
|| (pdata
->print_hex
&& is_pseudo_text_field
))) {
844 write_json_proto_node(node_values_list
, "", write_json_proto_node_no_value
, pdata
);
847 current_node
= current_node
->next
;
849 json_dumper_end_object(pdata
->dumper
);
853 * Writes a single node as a key:value pair. The value_writer param can be used to specify how the node's value should
855 * @param node_values_head Linked list containing all nodes associated with the same json key in this object.
856 * @param suffix Suffix that should be added to the json key.
857 * @param value_writer A function which writes the actual values of the node json key.
858 * @param pdata json writing metadata
861 write_json_proto_node(GSList
*node_values_head
,
863 proto_node_value_writer value_writer
,
864 write_json_data
*pdata
)
866 // Retrieve json key from first value.
867 proto_node
*first_value
= (proto_node
*) node_values_head
->data
;
868 const char *json_key
= proto_node_to_json_key(first_value
);
869 gchar
* json_key_suffix
= g_strdup_printf("%s%s", json_key
, suffix
);
870 json_dumper_set_member_name(pdata
->dumper
, json_key_suffix
);
871 g_free(json_key_suffix
);
872 write_json_proto_node_value_list(node_values_head
, value_writer
, pdata
);
876 * Writes a list of values of a single json key. If multiple values are passed they are wrapped in a json array.
877 * @param node_values_head Linked list containing all values that should be written.
878 * @param value_writer Function which writes the separate values.
879 * @param pdata json writing metadata
882 write_json_proto_node_value_list(GSList
*node_values_head
, proto_node_value_writer value_writer
, write_json_data
*pdata
)
884 GSList
*current_value
= node_values_head
;
886 // Write directly if only a single value is passed. Wrap in json array otherwise.
887 if (current_value
->next
== NULL
) {
888 value_writer((proto_node
*) current_value
->data
, pdata
);
890 json_dumper_begin_array(pdata
->dumper
);
892 while (current_value
!= NULL
) {
893 value_writer((proto_node
*) current_value
->data
, pdata
);
894 current_value
= current_value
->next
;
896 json_dumper_end_array(pdata
->dumper
);
901 * Writes the value for a node that's filtered from the output.
904 write_json_proto_node_filtered(proto_node
*node
, write_json_data
*pdata
)
906 const char *json_key
= proto_node_to_json_key(node
);
908 json_dumper_begin_object(pdata
->dumper
);
909 json_dumper_set_member_name(pdata
->dumper
, "filtered");
910 json_dumper_value_string(pdata
->dumper
, json_key
);
911 json_dumper_end_object(pdata
->dumper
);
915 * Writes the hex dump of a node. A json array is written containing the hex dump, position, length, bitmask and type of
919 write_json_proto_node_hex_dump(proto_node
*node
, write_json_data
*pdata
)
921 field_info
*fi
= node
->finfo
;
923 json_dumper_begin_array(pdata
->dumper
);
925 if (fi
->hfinfo
->bitmask
!=0) {
926 switch (fi
->value
.ftype
->ftype
) {
931 json_dumper_value_anyf(pdata
->dumper
, "\"%X\"", (guint
) fvalue_get_sinteger(&fi
->value
));
938 json_dumper_value_anyf(pdata
->dumper
, "\"%X\"", fvalue_get_uinteger(&fi
->value
));
944 json_dumper_value_anyf(pdata
->dumper
, "\"%" G_GINT64_MODIFIER
"X\"", fvalue_get_sinteger64(&fi
->value
));
951 json_dumper_value_anyf(pdata
->dumper
, "\"%" G_GINT64_MODIFIER
"X\"", fvalue_get_uinteger64(&fi
->value
));
954 g_assert_not_reached();
957 json_write_field_hex_value(pdata
, fi
);
960 /* Dump raw hex-encoded dissected information including position, length, bitmask, type */
961 json_dumper_value_anyf(pdata
->dumper
, "%" G_GINT32_MODIFIER
"d", fi
->start
);
962 json_dumper_value_anyf(pdata
->dumper
, "%" G_GINT32_MODIFIER
"d", fi
->length
);
963 json_dumper_value_anyf(pdata
->dumper
, "%" G_GUINT64_FORMAT
, fi
->hfinfo
->bitmask
);
964 json_dumper_value_anyf(pdata
->dumper
, "%" G_GINT32_MODIFIER
"d", (gint32
)fi
->value
.ftype
->ftype
);
966 json_dumper_end_array(pdata
->dumper
);
970 * Writes the children of a node. Calls write_json_proto_node_list internally which recursively writes children of nodes
974 write_json_proto_node_children(proto_node
*node
, write_json_data
*data
)
976 GSList
*grouped_children_list
= data
->node_children_grouper(node
);
977 write_json_proto_node_list(grouped_children_list
, data
);
978 g_slist_free_full(grouped_children_list
, (GDestroyNotify
) g_slist_free
);
982 * Writes the value of a node to the output.
985 write_json_proto_node_value(proto_node
*node
, write_json_data
*pdata
)
987 field_info
*fi
= node
->finfo
;
988 // Get the actual value of the node as a string.
989 char *value_string_repr
= fvalue_to_string_repr(NULL
, &fi
->value
, FTREPR_DISPLAY
, fi
->hfinfo
->display
);
991 json_dumper_value_string(pdata
->dumper
, value_string_repr
);
993 wmem_free(NULL
, value_string_repr
);
997 * Write the value for a node that has no value and no children. This is the empty string for all nodes except those of
998 * type FT_PROTOCOL for which the full name is written instead.
1001 write_json_proto_node_no_value(proto_node
*node
, write_json_data
*pdata
)
1003 field_info
*fi
= node
->finfo
;
1005 if (fi
->hfinfo
->type
== FT_PROTOCOL
) {
1007 json_dumper_value_string(pdata
->dumper
, fi
->rep
->representation
);
1009 gchar label_str
[ITEM_LABEL_LENGTH
];
1010 proto_item_fill_label(fi
, label_str
);
1011 json_dumper_value_string(pdata
->dumper
, label_str
);
1014 json_dumper_value_string(pdata
->dumper
, "");
1019 * Groups each child of the node separately.
1020 * @return Linked list where each element is another linked list containing a single node.
1023 proto_node_group_children_by_unique(proto_node
*node
) {
1024 GSList
*unique_nodes_list
= NULL
;
1025 proto_node
*current_child
= node
->first_child
;
1027 while (current_child
!= NULL
) {
1028 GSList
*unique_node
= g_slist_prepend(NULL
, current_child
);
1029 unique_nodes_list
= g_slist_prepend(unique_nodes_list
, unique_node
);
1030 current_child
= current_child
->next
;
1033 return g_slist_reverse(unique_nodes_list
);
1037 * Groups the children of a node by their json key. Children are put in the same group if they have the same json key.
1038 * @return Linked list where each element is another linked list of nodes associated with the same json key.
1041 proto_node_group_children_by_json_key(proto_node
*node
)
1044 * For each different json key we store a linked list of values corresponding to that json key. These lists are kept
1045 * in both a linked list and a hashmap. The hashmap is used to quickly retrieve the values of a json key. The linked
1046 * list is used to preserve the ordering of keys as they are encountered which is not guaranteed when only using a
1049 GSList
*same_key_nodes_list
= NULL
;
1050 GHashTable
*lookup_by_json_key
= g_hash_table_new(g_str_hash
, g_str_equal
);
1051 proto_node
*current_child
= node
->first_child
;
1054 * For each child of the node get the key and get the list of values already associated with that key from the
1055 * 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
1056 * list already exists add the node to that list.
1058 while (current_child
!= NULL
) {
1059 char *json_key
= (char *) proto_node_to_json_key(current_child
);
1060 GSList
*json_key_nodes
= (GSList
*) g_hash_table_lookup(lookup_by_json_key
, json_key
);
1062 if (json_key_nodes
== NULL
) {
1063 json_key_nodes
= g_slist_append(json_key_nodes
, current_child
);
1064 // Prepending in single linked list is O(1), appending is O(n). Better to prepend here and reverse at the
1065 // end than potentially looping to the end of the linked list for each child.
1066 same_key_nodes_list
= g_slist_prepend(same_key_nodes_list
, json_key_nodes
);
1067 g_hash_table_insert(lookup_by_json_key
, json_key
, json_key_nodes
);
1069 // Store and insert value again to circumvent unused_variable warning.
1070 // Append in this case since most value lists will only have a single value.
1071 json_key_nodes
= g_slist_append(json_key_nodes
, current_child
);
1072 g_hash_table_insert(lookup_by_json_key
, json_key
, json_key_nodes
);
1075 current_child
= current_child
->next
;
1078 // Hash table is not needed anymore since the linked list with the correct ordering is returned.
1079 g_hash_table_destroy(lookup_by_json_key
);
1081 return g_slist_reverse(same_key_nodes_list
);
1085 * Returns the json key of a node. Tries to use the node's abbreviated name. If the abbreviated name is not available
1086 * the representation is used instead.
1089 proto_node_to_json_key(proto_node
*node
)
1091 const char *json_key
;
1092 // Check if node has abbreviated name.
1093 if (node
->finfo
->hfinfo
->id
!= hf_text_only
) {
1094 json_key
= node
->finfo
->hfinfo
->abbrev
;
1095 } else if (node
->finfo
->rep
!= NULL
) {
1096 json_key
= node
->finfo
->rep
->representation
;
1105 ek_check_protocolfilter(gchar
**protocolfilter
, const char *str
)
1107 gchar
*str_escaped
= NULL
;
1111 if (check_protocolfilter(protocolfilter
, str
))
1114 /* to to thread the '.' and '_' equally. The '.' is replace by print_escaped_ek for '_' */
1115 if (str
!= NULL
&& strlen(str
) > 0) {
1116 str_escaped
= g_strdup(str
);
1119 while (str_escaped
[i
] != '\0') {
1120 if (str_escaped
[i
] == '.') {
1121 str_escaped
[i
] = '_';
1127 check
= check_protocolfilter(protocolfilter
, str_escaped
);
1128 g_free(str_escaped
);
1133 * Finds a node's descendants to be printed as EK/JSON attributes.
1136 write_ek_summary(column_info
*cinfo
, write_json_data
* pdata
)
1140 for (i
= 0; i
< cinfo
->num_cols
; i
++) {
1141 if (!get_column_visible(i
))
1143 json_dumper_set_member_name(pdata
->dumper
, g_ascii_strdown(cinfo
->columns
[i
].col_title
, -1));
1144 json_dumper_value_string(pdata
->dumper
, cinfo
->columns
[i
].col_data
);
1148 /* Write out a tree's data, and any child nodes, as JSON for EK */
1150 ek_fill_attr(proto_node
*node
, GSList
**attr_list
, GHashTable
*attr_table
, write_json_data
*pdata
)
1152 field_info
*fi
= NULL
;
1153 field_info
*fi_parent
= NULL
;
1154 gchar
*node_name
= NULL
;
1155 GSList
*attr_instances
= NULL
;
1157 proto_node
*current_node
= node
->first_child
;
1158 while (current_node
!= NULL
) {
1159 fi
= PNODE_FINFO(current_node
);
1160 fi_parent
= PNODE_FINFO(current_node
->parent
);
1162 /* dissection with an invisible proto tree? */
1165 if (fi_parent
== NULL
) {
1166 node_name
= g_strdup(fi
->hfinfo
->abbrev
);
1168 node_name
= g_strconcat(fi_parent
->hfinfo
->abbrev
, "_", fi
->hfinfo
->abbrev
, NULL
);
1171 attr_instances
= (GSList
*) g_hash_table_lookup(attr_table
, node_name
);
1172 // First time we encounter this attr
1173 if (attr_instances
== NULL
) {
1174 attr_instances
= g_slist_append(attr_instances
, current_node
);
1175 *attr_list
= g_slist_prepend(*attr_list
, attr_instances
);
1177 attr_instances
= g_slist_append(attr_instances
, current_node
);
1180 // Update instance list for this attr in hash table
1181 g_hash_table_insert(attr_table
, node_name
, attr_instances
);
1183 /* Field, recurse through children*/
1184 if (fi
->hfinfo
->type
!= FT_PROTOCOL
&& current_node
->first_child
!= NULL
) {
1185 if (pdata
->filter
!= NULL
) {
1186 if (ek_check_protocolfilter(pdata
->filter
, fi
->hfinfo
->abbrev
)) {
1187 gchar
**_filter
= NULL
;
1188 /* Remove protocol filter for children, if children should be included */
1189 if ((pdata
->filter_flags
&PF_INCLUDE_CHILDREN
) == PF_INCLUDE_CHILDREN
) {
1190 _filter
= pdata
->filter
;
1191 pdata
->filter
= NULL
;
1194 ek_fill_attr(current_node
, attr_list
, attr_table
, pdata
);
1196 /* Put protocol filter back */
1197 if ((pdata
->filter_flags
&PF_INCLUDE_CHILDREN
) == PF_INCLUDE_CHILDREN
) {
1198 pdata
->filter
= _filter
;
1201 // Don't traverse children if filtered out
1204 ek_fill_attr(current_node
, attr_list
, attr_table
, pdata
);
1207 // Will descend into object at another point
1210 current_node
= current_node
->next
;
1215 ek_write_name(proto_node
*pnode
, gchar
* suffix
, write_json_data
* pdata
)
1217 field_info
*fi
= PNODE_FINFO(pnode
);
1220 if (fi
->hfinfo
->parent
!= -1) {
1221 header_field_info
* parent
= proto_registrar_get_nth(fi
->hfinfo
->parent
);
1222 str
= g_strdup_printf("%s_%s%s", parent
->abbrev
, fi
->hfinfo
->abbrev
, suffix
? suffix
: "");
1223 json_dumper_set_member_name(pdata
->dumper
, str
);
1225 str
= g_strdup_printf("%s%s", fi
->hfinfo
->abbrev
, suffix
? suffix
: "");
1226 json_dumper_set_member_name(pdata
->dumper
, str
);
1232 ek_write_hex(field_info
*fi
, write_json_data
*pdata
)
1234 if (fi
->hfinfo
->bitmask
!= 0) {
1235 switch (fi
->value
.ftype
->ftype
) {
1240 json_dumper_value_anyf(pdata
->dumper
, "\"%X\"", (guint
) fvalue_get_sinteger(&fi
->value
));
1247 json_dumper_value_anyf(pdata
->dumper
, "\"%X\"", fvalue_get_uinteger(&fi
->value
));
1253 json_dumper_value_anyf(pdata
->dumper
, "\"%" G_GINT64_MODIFIER
"X\"", fvalue_get_sinteger64(&fi
->value
));
1260 json_dumper_value_anyf(pdata
->dumper
, "\"%" G_GINT64_MODIFIER
"X\"", fvalue_get_uinteger64(&fi
->value
));
1263 g_assert_not_reached();
1266 json_write_field_hex_value(pdata
, fi
);
1271 ek_write_field_value(field_info
*fi
, write_json_data
* pdata
)
1273 gchar label_str
[ITEM_LABEL_LENGTH
];
1274 char *dfilter_string
;
1280 char time_string
[sizeof("YYYY-MM-DDTHH:MM:SS")];
1283 if (fi
->hfinfo
->id
== hf_text_only
&& fi
->rep
) {
1284 json_dumper_value_string(pdata
->dumper
, fi
->rep
->representation
);
1286 /* show, value, and unmaskedvalue attributes */
1287 switch(fi
->hfinfo
->type
) {
1290 json_dumper_value_string(pdata
->dumper
, fi
->rep
->representation
);
1293 proto_item_fill_label(fi
, label_str
);
1294 json_dumper_value_string(pdata
->dumper
, label_str
);
1298 json_dumper_value_string(pdata
->dumper
, NULL
);
1301 if (fi
->value
.value
.uinteger64
)
1302 json_dumper_value_anyf(pdata
->dumper
, "true");
1304 json_dumper_value_anyf(pdata
->dumper
, "false");
1306 case FT_ABSOLUTE_TIME
:
1307 t
= (const nstime_t
*)fvalue_get(&fi
->value
);
1310 * Do not use gmtime_s(), as it will call and
1311 * exception handler if the time we're providing
1312 * is < 0, and that will, by default, exit.
1313 * ("Programmers not bothering to check return
1314 * values? Try new Microsoft Visual Studio,
1315 * with Parameter Validation(R)! Kill insufficiently
1316 * careful programs - *and* the processes running them -
1319 * We just want to report this as an unrepresentable
1320 * time. It fills in a per-thread structure, which
1321 * is sufficiently thread-safe for our purposes.
1323 tm
= gmtime(&t
->secs
);
1326 * Use gmtime_r(), because the Single UNIX Specification
1327 * does *not* guarantee that gmtime() is thread-safe.
1328 * Perhaps it is on all platforms on which we run, but
1329 * this way we don't have to check.
1331 tm
= gmtime_r(&t
->secs
, &tm_time
);
1334 strftime(time_string
, sizeof(time_string
), "%FT%T", tm
);
1335 json_dumper_value_anyf(pdata
->dumper
, "\"%s.%09uZ\"", time_string
, t
->nsecs
);
1337 json_dumper_value_anyf(pdata
->dumper
, "\"Not representable\"");
1341 dfilter_string
= fvalue_to_string_repr(NULL
, &fi
->value
, FTREPR_DISPLAY
, fi
->hfinfo
->display
);
1342 if (dfilter_string
!= NULL
) {
1343 json_dumper_value_string(pdata
->dumper
, dfilter_string
);
1345 wmem_free(NULL
, dfilter_string
);
1352 ek_write_attr_hex(GSList
*attr_instances
, write_json_data
*pdata
)
1354 GSList
*current_node
= attr_instances
;
1355 proto_node
*pnode
= (proto_node
*) current_node
->data
;
1356 field_info
*fi
= NULL
;
1359 ek_write_name(pnode
, "_raw", pdata
);
1361 if (g_slist_length(attr_instances
) > 1) {
1362 json_dumper_begin_array(pdata
->dumper
);
1366 while (current_node
!= NULL
) {
1367 pnode
= (proto_node
*) current_node
->data
;
1368 fi
= PNODE_FINFO(pnode
);
1370 ek_write_hex(fi
, pdata
);
1372 current_node
= current_node
->next
;
1375 if (g_slist_length(attr_instances
) > 1) {
1376 json_dumper_end_array(pdata
->dumper
);
1381 ek_write_attr(GSList
*attr_instances
, write_json_data
*pdata
)
1383 GSList
*current_node
= attr_instances
;
1384 proto_node
*pnode
= (proto_node
*) current_node
->data
;
1385 field_info
*fi
= PNODE_FINFO(pnode
);
1388 if (pdata
->print_hex
&& fi
&& fi
->length
> 0 && fi
->hfinfo
->id
!= hf_text_only
) {
1389 ek_write_attr_hex(attr_instances
, pdata
);
1393 ek_write_name(pnode
, NULL
, pdata
);
1395 if (g_slist_length(attr_instances
) > 1) {
1396 json_dumper_begin_array(pdata
->dumper
);
1399 while (current_node
!= NULL
) {
1400 pnode
= (proto_node
*) current_node
->data
;
1401 fi
= PNODE_FINFO(pnode
);
1404 if (fi
->hfinfo
->type
!= FT_PROTOCOL
) {
1405 if (pdata
->filter
!= NULL
1406 && !ek_check_protocolfilter(pdata
->filter
, fi
->hfinfo
->abbrev
)) {
1408 /* print dummy field */
1409 json_dumper_begin_object(pdata
->dumper
);
1410 json_dumper_set_member_name(pdata
->dumper
, "filtered");
1411 json_dumper_value_string(pdata
->dumper
, fi
->hfinfo
->abbrev
);
1412 json_dumper_end_object(pdata
->dumper
);
1414 ek_write_field_value(fi
, pdata
);
1418 json_dumper_begin_object(pdata
->dumper
);
1420 if (pdata
->filter
!= NULL
) {
1421 if (ek_check_protocolfilter(pdata
->filter
, fi
->hfinfo
->abbrev
)) {
1422 gchar
**_filter
= NULL
;
1423 /* Remove protocol filter for children, if children should be included */
1424 if ((pdata
->filter_flags
&PF_INCLUDE_CHILDREN
) == PF_INCLUDE_CHILDREN
) {
1425 _filter
= pdata
->filter
;
1426 pdata
->filter
= NULL
;
1429 proto_tree_write_node_ek(pnode
, pdata
);
1431 /* Put protocol filter back */
1432 if ((pdata
->filter_flags
&PF_INCLUDE_CHILDREN
) == PF_INCLUDE_CHILDREN
) {
1433 pdata
->filter
= _filter
;
1436 /* print dummy field */
1437 json_dumper_set_member_name(pdata
->dumper
, "filtered");
1438 json_dumper_value_string(pdata
->dumper
, fi
->hfinfo
->abbrev
);
1441 proto_tree_write_node_ek(pnode
, pdata
);
1444 json_dumper_end_object(pdata
->dumper
);
1447 current_node
= current_node
->next
;
1450 if (g_slist_length(attr_instances
) > 1) {
1451 json_dumper_end_array(pdata
->dumper
);
1455 /* Write out a tree's data, and any child nodes, as JSON for EK */
1457 proto_tree_write_node_ek(proto_node
*node
, write_json_data
*pdata
)
1459 GSList
*attr_list
= NULL
;
1460 GHashTable
*attr_table
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, NULL
);
1462 ek_fill_attr(node
, &attr_list
, attr_table
, pdata
);
1464 g_hash_table_destroy(attr_table
);
1467 attr_list
= g_slist_reverse(attr_list
);
1468 GSList
*current_attr
= attr_list
;
1469 while (current_attr
!= NULL
) {
1470 GSList
*attr_instances
= (GSList
*) current_attr
->data
;
1472 ek_write_attr(attr_instances
, pdata
);
1474 current_attr
= current_attr
->next
;
1477 g_slist_free_full(attr_list
, (GDestroyNotify
) g_slist_free
);
1480 /* Print info for a 'geninfo' pseudo-protocol. This is required by
1481 * the PDML spec. The information is contained in Wireshark's 'frame' protocol,
1482 * but we produce a 'geninfo' protocol in the PDML to conform to spec.
1483 * The 'frame' protocol follows the 'geninfo' protocol in the PDML. */
1485 print_pdml_geninfo(epan_dissect_t
*edt
, FILE *fh
)
1487 guint32 num
, len
, caplen
;
1488 GPtrArray
*finfo_array
;
1489 field_info
*frame_finfo
;
1492 /* Get frame protocol's finfo. */
1493 finfo_array
= proto_find_first_finfo(edt
->tree
, proto_frame
);
1494 if (g_ptr_array_len(finfo_array
) < 1) {
1497 frame_finfo
= (field_info
*)finfo_array
->pdata
[0];
1498 g_ptr_array_free(finfo_array
, TRUE
);
1500 /* frame.number, packet_info.num */
1503 /* frame.frame_len, packet_info.frame_data->pkt_len */
1504 len
= edt
->pi
.fd
->pkt_len
;
1506 /* frame.cap_len --> packet_info.frame_data->cap_len */
1507 caplen
= edt
->pi
.fd
->cap_len
;
1509 /* Print geninfo start */
1511 " <proto name=\"geninfo\" pos=\"0\" showname=\"General information\" size=\"%d\">\n",
1512 frame_finfo
->length
);
1514 /* Print geninfo.num */
1516 " <field name=\"num\" pos=\"0\" show=\"%u\" showname=\"Number\" value=\"%x\" size=\"%d\"/>\n",
1517 num
, num
, frame_finfo
->length
);
1519 /* Print geninfo.len */
1521 " <field name=\"len\" pos=\"0\" show=\"%u\" showname=\"Frame Length\" value=\"%x\" size=\"%d\"/>\n",
1522 len
, len
, frame_finfo
->length
);
1524 /* Print geninfo.caplen */
1526 " <field name=\"caplen\" pos=\"0\" show=\"%u\" showname=\"Captured Length\" value=\"%x\" size=\"%d\"/>\n",
1527 caplen
, caplen
, frame_finfo
->length
);
1529 tmp
= abs_time_to_str(NULL
, &edt
->pi
.abs_ts
, ABSOLUTE_TIME_LOCAL
, TRUE
);
1531 /* Print geninfo.timestamp */
1533 " <field name=\"timestamp\" pos=\"0\" show=\"%s\" showname=\"Captured Time\" value=\"%d.%09d\" size=\"%d\"/>\n",
1534 tmp
, (int)edt
->pi
.abs_ts
.secs
, edt
->pi
.abs_ts
.nsecs
, frame_finfo
->length
);
1536 wmem_free(NULL
, tmp
);
1538 /* Print geninfo end */
1544 write_pdml_finale(FILE *fh
)
1546 fputs("</pdml>\n", fh
);
1550 write_psml_preamble(column_info
*cinfo
, FILE *fh
)
1554 fprintf(fh
, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
1555 fprintf(fh
, "<psml version=\"" PSML_VERSION
"\" creator=\"%s/%s\">\n", PACKAGE
, VERSION
);
1556 fprintf(fh
, "<structure>\n");
1558 for (i
= 0; i
< cinfo
->num_cols
; i
++) {
1559 if (!get_column_visible(i
))
1561 fprintf(fh
, "<section>");
1562 print_escaped_xml(fh
, cinfo
->columns
[i
].col_title
);
1563 fprintf(fh
, "</section>\n");
1566 fprintf(fh
, "</structure>\n\n");
1570 write_psml_columns(epan_dissect_t
*edt
, FILE *fh
, gboolean use_color
)
1573 const color_filter_t
*cfp
= edt
->pi
.fd
->color_filter
;
1575 if (use_color
&& (cfp
!= NULL
)) {
1576 fprintf(fh
, "<packet foreground='#%06x' background='#%06x'>\n",
1577 color_t_to_rgb(&cfp
->fg_color
),
1578 color_t_to_rgb(&cfp
->bg_color
));
1580 fprintf(fh
, "<packet>\n");
1583 for (i
= 0; i
< edt
->pi
.cinfo
->num_cols
; i
++) {
1584 if (!get_column_visible(i
))
1586 fprintf(fh
, "<section>");
1587 print_escaped_xml(fh
, edt
->pi
.cinfo
->columns
[i
].col_data
);
1588 fprintf(fh
, "</section>\n");
1591 fprintf(fh
, "</packet>\n\n");
1595 write_psml_finale(FILE *fh
)
1597 fputs("</psml>\n", fh
);
1600 static gchar
*csv_massage_str(const gchar
*source
, const gchar
*exceptions
)
1605 /* In general, our output for any field can contain Unicode characters,
1606 so g_strescape (which escapes any non-ASCII) is the wrong thing to do.
1607 Unfortunately glib doesn't appear to provide g_unicode_strescape()... */
1608 csv_str
= g_strescape(source
, exceptions
);
1610 /* Locate the UTF-8 right arrow character and replace it by an ASCII equivalent */
1611 while ( (tmp_str
= strstr(tmp_str
, UTF8_RIGHTWARDS_ARROW
)) != NULL
) {
1617 while ( (tmp_str
= strstr(tmp_str
, "\\\"")) != NULL
)
1622 static void csv_write_str(const char *str
, char sep
, FILE *fh
)
1626 /* Do not escape the UTF-8 right arrow character */
1627 csv_str
= csv_massage_str(str
, UTF8_RIGHTWARDS_ARROW
);
1628 fprintf(fh
, "\"%s\"%c", csv_str
, sep
);
1633 write_csv_column_titles(column_info
*cinfo
, FILE *fh
)
1637 for (i
= 0; i
< cinfo
->num_cols
- 1; i
++) {
1638 if (!get_column_visible(i
))
1640 csv_write_str(cinfo
->columns
[i
].col_title
, ',', fh
);
1642 csv_write_str(cinfo
->columns
[i
].col_title
, '\n', fh
);
1646 write_csv_columns(epan_dissect_t
*edt
, FILE *fh
)
1650 for (i
= 0; i
< edt
->pi
.cinfo
->num_cols
- 1; i
++) {
1651 if (!get_column_visible(i
))
1653 csv_write_str(edt
->pi
.cinfo
->columns
[i
].col_data
, ',', fh
);
1655 csv_write_str(edt
->pi
.cinfo
->columns
[i
].col_data
, '\n', fh
);
1659 write_carrays_hex_data(guint32 num
, FILE *fh
, epan_dissect_t
*edt
)
1661 guint32 i
= 0, src_num
= 0;
1668 struct data_source
*src
;
1670 for (src_le
= edt
->pi
.data_src
; src_le
!= NULL
; src_le
= src_le
->next
) {
1671 memset(ascii
, 0, sizeof(ascii
));
1672 src
= (struct data_source
*)src_le
->data
;
1673 tvb
= get_data_source_tvb(src
);
1674 length
= tvb_captured_length(tvb
);
1678 cp
= tvb_get_ptr(tvb
, 0, length
);
1680 name
= get_data_source_name(src
);
1682 fprintf(fh
, "/* %s */\n", name
);
1683 wmem_free(NULL
, name
);
1686 fprintf(fh
, "static const unsigned char pkt%u_%u[%u] = {\n",
1687 num
, src_num
, length
);
1689 fprintf(fh
, "static const unsigned char pkt%u[%u] = {\n",
1694 for (i
= 0; i
< length
; i
++) {
1695 fprintf(fh
, "0x%02x", *(cp
+ i
));
1696 ascii
[i
% 8] = g_ascii_isprint(*(cp
+ i
)) ? *(cp
+ i
) : '.';
1698 if (i
== (length
- 1)) {
1703 for ( j
= 0; j
< 8 - rem
; j
++ )
1706 fprintf(fh
, " /* %s */\n};\n\n", ascii
);
1710 if (!((i
+ 1) % 8)) {
1711 fprintf(fh
, ", /* %s */\n", ascii
);
1712 memset(ascii
, 0, sizeof(ascii
));
1721 * Find the data source for a specified field, and return a pointer
1722 * to the data in it. Returns NULL if the data is out of bounds.
1724 /* XXX: What am I missing ?
1725 * Why bother searching for fi->ds_tvb for the matching tvb
1726 * in the data_source list ?
1727 * IOW: Why not just use fi->ds_tvb for the arg to tvb_get_ptr() ?
1730 static const guint8
*
1731 get_field_data(GSList
*src_list
, field_info
*fi
)
1735 gint length
, tvbuff_length
;
1736 struct data_source
*src
;
1738 for (src_le
= src_list
; src_le
!= NULL
; src_le
= src_le
->next
) {
1739 src
= (struct data_source
*)src_le
->data
;
1740 src_tvb
= get_data_source_tvb(src
);
1741 if (fi
->ds_tvb
== src_tvb
) {
1745 * XXX - a field can have a length that runs past
1746 * the end of the tvbuff. Ideally, that should
1747 * be fixed when adding an item to the protocol
1748 * tree, but checking the length when doing
1749 * that could be expensive. Until we fix that,
1750 * we'll do the check here.
1752 tvbuff_length
= tvb_captured_length_remaining(src_tvb
,
1754 if (tvbuff_length
< 0) {
1757 length
= fi
->length
;
1758 if (length
> tvbuff_length
)
1759 length
= tvbuff_length
;
1760 return tvb_get_ptr(src_tvb
, fi
->start
, length
);
1763 return NULL
; /* not found */
1766 /* Print a string, escaping out certain characters that need to
1767 * escaped out for XML. */
1769 print_escaped_xml(FILE *fh
, const char *unescaped_string
)
1773 #define ESCAPED_BUFFER_MAX 256
1774 static char temp_buffer
[ESCAPED_BUFFER_MAX
];
1777 if (fh
== NULL
|| unescaped_string
== NULL
) {
1781 for (p
= unescaped_string
; *p
!= '\0'; p
++) {
1784 g_strlcpy(&temp_buffer
[offset
], "&", ESCAPED_BUFFER_MAX
-offset
);
1788 g_strlcpy(&temp_buffer
[offset
], "<", ESCAPED_BUFFER_MAX
-offset
);
1792 g_strlcpy(&temp_buffer
[offset
], ">", ESCAPED_BUFFER_MAX
-offset
);
1796 g_strlcpy(&temp_buffer
[offset
], """, ESCAPED_BUFFER_MAX
-offset
);
1800 g_strlcpy(&temp_buffer
[offset
], "'", ESCAPED_BUFFER_MAX
-offset
);
1804 temp_buffer
[offset
++] = *p
;
1806 if (offset
> ESCAPED_BUFFER_MAX
-8) {
1807 /* Getting close to end of buffer so flush to fh */
1808 temp_buffer
[offset
] = '\0';
1809 fputs(temp_buffer
, fh
);
1814 /* Flush any outstanding data */
1815 temp_buffer
[offset
] = '\0';
1816 fputs(temp_buffer
, fh
);
1821 print_escaped_csv(FILE *fh
, const char *unescaped_string
)
1825 if (fh
== NULL
|| unescaped_string
== NULL
) {
1829 for (p
= unescaped_string
; *p
!= '\0'; p
++) {
1853 pdml_write_field_hex_value(write_pdml_data
*pdata
, field_info
*fi
)
1861 if (fi
->length
> tvb_captured_length_remaining(fi
->ds_tvb
, fi
->start
)) {
1862 fprintf(pdata
->fh
, "field length invalid!");
1866 /* Find the data for this field. */
1867 pd
= get_field_data(pdata
->src_list
, fi
);
1870 /* Used fixed buffer where can, otherwise temp malloc */
1871 static gchar str_static
[129];
1872 gchar
*str
= str_static
;
1873 gchar
* str_heap
= NULL
;
1874 if (fi
->length
> 64) {
1875 str_heap
= (gchar
*)g_malloc0(fi
->length
*2+1);
1879 static const char hex
[] = "0123456789abcdef";
1881 /* Print a simple hex dump */
1882 for (i
= 0 ; i
< fi
->length
; i
++) {
1883 str
[2*i
] = hex
[pd
[i
] >> 4];
1884 str
[2*i
+1] = hex
[pd
[i
] & 0xf];
1886 str
[2 * fi
->length
] = '\0';
1887 fputs(str
, pdata
->fh
);
1894 json_write_field_hex_value(write_json_data
*pdata
, field_info
*fi
)
1901 if (fi
->length
> tvb_captured_length_remaining(fi
->ds_tvb
, fi
->start
)) {
1902 json_dumper_value_string(pdata
->dumper
, "field length invalid!");
1906 /* Find the data for this field. */
1907 pd
= get_field_data(pdata
->src_list
, fi
);
1911 guint len
= fi
->length
* 2 + 1;
1912 gchar
* str
= (gchar
*)g_malloc0(len
);
1913 static const char hex
[] = "0123456789abcdef";
1914 /* Print a simple hex dump */
1915 for (i
= 0; i
< fi
->length
; i
++) {
1917 str
[2 * i
] = hex
[c
>> 4];
1918 str
[2 * i
+ 1] = hex
[c
& 0xf];
1920 str
[2 * fi
->length
] = '\0';
1921 json_dumper_value_string(pdata
->dumper
, str
);
1924 json_dumper_value_string(pdata
->dumper
, "");
1929 print_hex_data(print_stream_t
*stream
, epan_dissect_t
*edt
)
1931 gboolean multiple_sources
;
1937 struct data_source
*src
;
1940 * Set "multiple_sources" iff this frame has more than one
1941 * data source; if it does, we need to print the name of
1942 * the data source before printing the data from the
1945 multiple_sources
= (edt
->pi
.data_src
->next
!= NULL
);
1947 for (src_le
= edt
->pi
.data_src
; src_le
!= NULL
;
1948 src_le
= src_le
->next
) {
1949 src
= (struct data_source
*)src_le
->data
;
1950 tvb
= get_data_source_tvb(src
);
1951 if (multiple_sources
) {
1952 name
= get_data_source_name(src
);
1953 line
= g_strdup_printf("%s:", name
);
1954 wmem_free(NULL
, name
);
1955 print_line(stream
, 0, line
);
1958 length
= tvb_captured_length(tvb
);
1961 cp
= tvb_get_ptr(tvb
, 0, length
);
1962 if (!print_hex_data_buffer(stream
, cp
, length
,
1963 (packet_char_enc
)edt
->pi
.fd
->encoding
))
1970 * This routine is based on a routine created by Dan Lasley
1971 * <DLASLEY@PROMUS.com>.
1973 * It was modified for Wireshark by Gilbert Ramirez and others.
1976 #define MAX_OFFSET_LEN 8 /* max length of hex offset of bytes */
1977 #define BYTES_PER_LINE 16 /* max byte values printed on a line */
1978 #define HEX_DUMP_LEN (BYTES_PER_LINE*3)
1979 /* max number of characters hex dump takes -
1980 2 digits plus trailing blank */
1981 #define DATA_DUMP_LEN (HEX_DUMP_LEN + 2 + BYTES_PER_LINE)
1982 /* number of characters those bytes take;
1983 3 characters per byte of hex dump,
1984 2 blanks separating hex from ASCII,
1985 1 character per byte of ASCII dump */
1986 #define MAX_LINE_LEN (MAX_OFFSET_LEN + 2 + DATA_DUMP_LEN)
1987 /* number of characters per line;
1988 offset, 2 blanks separating offset
1989 from data dump, data dump */
1992 print_hex_data_buffer(print_stream_t
*stream
, const guchar
*cp
,
1993 guint length
, packet_char_enc encoding
)
1995 register unsigned int ad
, i
, j
, k
, l
;
1997 gchar line
[MAX_LINE_LEN
+ 1];
1998 unsigned int use_digits
;
2000 static gchar binhex
[16] = {
2001 '0', '1', '2', '3', '4', '5', '6', '7',
2002 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
2005 * How many of the leading digits of the offset will we supply?
2006 * We always supply at least 4 digits, but if the maximum offset
2007 * won't fit in 4 digits, we use as many digits as will be needed.
2009 if (((length
- 1) & 0xF0000000) != 0)
2010 use_digits
= 8; /* need all 8 digits */
2011 else if (((length
- 1) & 0x0F000000) != 0)
2012 use_digits
= 7; /* need 7 digits */
2013 else if (((length
- 1) & 0x00F00000) != 0)
2014 use_digits
= 6; /* need 6 digits */
2015 else if (((length
- 1) & 0x000F0000) != 0)
2016 use_digits
= 5; /* need 5 digits */
2018 use_digits
= 4; /* we'll supply 4 digits */
2024 while (i
< length
) {
2025 if ((i
& 15) == 0) {
2027 * Start of a new line.
2033 c
= (ad
>> (l
*4)) & 0xF;
2034 line
[j
++] = binhex
[c
];
2038 memset(line
+j
, ' ', DATA_DUMP_LEN
);
2041 * Offset in line of ASCII dump.
2043 k
= j
+ HEX_DUMP_LEN
+ 2;
2046 line
[j
++] = binhex
[c
>>4];
2047 line
[j
++] = binhex
[c
&0xf];
2049 if (encoding
== PACKET_CHAR_ENC_CHAR_EBCDIC
) {
2050 c
= EBCDIC_to_ASCII1(c
);
2052 line
[k
++] = ((c
>= ' ') && (c
< 0x7f)) ? c
: '.';
2054 if (((i
& 15) == 0) || (i
== length
)) {
2056 * We'll be starting a new line, or
2057 * we're finished printing this buffer;
2058 * dump out the line we've constructed,
2059 * and advance the offset.
2062 if (!print_line(stream
, 0, line
))
2070 gsize
output_fields_num_fields(output_fields_t
* fields
)
2074 if (NULL
== fields
->fields
) {
2077 return fields
->fields
->len
;
2081 void output_fields_free(output_fields_t
* fields
)
2085 if (NULL
!= fields
->fields
) {
2088 if (NULL
!= fields
->field_indicies
) {
2089 /* Keys are stored in fields->fields, values are
2092 g_hash_table_destroy(fields
->field_indicies
);
2095 if (NULL
!= fields
->field_values
) {
2096 g_free(fields
->field_values
);
2099 for (i
= 0; i
< fields
->fields
->len
; ++i
) {
2100 gchar
* field
= (gchar
*)g_ptr_array_index(fields
->fields
,i
);
2103 g_ptr_array_free(fields
->fields
, TRUE
);
2109 #define COLUMN_FIELD_FILTER "_ws.col."
2111 void output_fields_add(output_fields_t
*fields
, const gchar
*field
)
2119 if (NULL
== fields
->fields
) {
2120 fields
->fields
= g_ptr_array_new();
2123 field_copy
= g_strdup(field
);
2125 g_ptr_array_add(fields
->fields
, field_copy
);
2127 /* See if we have a column as a field entry */
2128 if (!strncmp(field
, COLUMN_FIELD_FILTER
, strlen(COLUMN_FIELD_FILTER
)))
2129 fields
->includes_col_fields
= TRUE
;
2134 output_field_check(void *data
, void *user_data
)
2136 gchar
*field
= (gchar
*)data
;
2137 GSList
**invalid_fields
= (GSList
**)user_data
;
2139 if (!strncmp(field
, COLUMN_FIELD_FILTER
, strlen(COLUMN_FIELD_FILTER
)))
2142 if (!proto_registrar_get_byname(field
)) {
2143 *invalid_fields
= g_slist_prepend(*invalid_fields
, field
);
2149 output_fields_valid(output_fields_t
*fields
)
2151 GSList
*invalid_fields
= NULL
;
2152 if (fields
->fields
== NULL
) {
2156 g_ptr_array_foreach(fields
->fields
, output_field_check
, &invalid_fields
);
2158 return invalid_fields
;
2161 gboolean
output_fields_set_option(output_fields_t
*info
, gchar
*option
)
2163 const gchar
*option_name
;
2164 const gchar
*option_value
;
2169 if ('\0' == *option
) {
2170 return FALSE
; /* this happens if we're called from tshark -E '' */
2172 option_name
= strtok(option
, "=");
2176 option_value
= option
+ strlen(option_name
) + 1;
2177 if (*option_value
== '\0') {
2181 if (0 == strcmp(option_name
, "header")) {
2182 switch (*option_value
) {
2184 info
->print_header
= FALSE
;
2187 info
->print_header
= TRUE
;
2194 else if (0 == strcmp(option_name
, "separator")) {
2195 switch (*option_value
) {
2197 switch (*++option_value
) {
2199 info
->separator
= '\t';
2202 info
->separator
= ' ';
2205 info
->separator
= '\\';
2209 info
->separator
= *option_value
;
2214 else if (0 == strcmp(option_name
, "occurrence")) {
2215 switch (*option_value
) {
2219 info
->occurrence
= *option_value
;
2226 else if (0 == strcmp(option_name
, "aggregator")) {
2227 switch (*option_value
) {
2229 switch (*++option_value
) {
2231 info
->aggregator
= ' ';
2234 info
->aggregator
= '\\';
2238 info
->aggregator
= *option_value
;
2243 else if (0 == strcmp(option_name
, "quote")) {
2244 switch (*option_value
) {
2260 else if (0 == strcmp(option_name
, "bom")) {
2261 switch (*option_value
) {
2263 info
->print_bom
= FALSE
;
2266 info
->print_bom
= TRUE
;
2277 void output_fields_list_options(FILE *fh
)
2279 fprintf(fh
, "TShark: The available options for field output \"E\" are:\n");
2280 fputs("bom=y|n Prepend output with the UTF-8 BOM (def: N: no)\n", fh
);
2281 fputs("header=y|n Print field abbreviations as first line of output (def: N: no)\n", fh
);
2282 fputs("separator=/t|/s|<character> Set the separator to use;\n \"/t\" = tab, \"/s\" = space (def: /t: tab)\n", fh
);
2283 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
);
2284 fputs("aggregator=,|/s|<character> Set the aggregator to use;\n \",\" = comma, \"/s\" = space (def: ,: comma)\n", fh
);
2285 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
);
2288 gboolean
output_fields_has_cols(output_fields_t
* fields
)
2291 return fields
->includes_col_fields
;
2294 void write_fields_preamble(output_fields_t
* fields
, FILE *fh
)
2300 g_assert(fields
->fields
);
2302 if (fields
->print_bom
) {
2303 fputs(UTF8_BOM
, fh
);
2307 if (!fields
->print_header
) {
2311 for(i
= 0; i
< fields
->fields
->len
; ++i
) {
2312 const gchar
* field
= (const gchar
*)g_ptr_array_index(fields
->fields
,i
);
2314 fputc(fields
->separator
, fh
);
2321 static void format_field_values(output_fields_t
* fields
, gpointer field_index
, gchar
* value
)
2329 /* Unwrap change made to disambiguiate zero / null */
2330 indx
= GPOINTER_TO_UINT(field_index
) - 1;
2332 if (fields
->field_values
[indx
] == NULL
) {
2333 fields
->field_values
[indx
] = g_ptr_array_new();
2336 /* Essentially: fieldvalues[indx] is a 'GPtrArray *' with each array entry */
2337 /* pointing to a string which is (part of) the final output string. */
2339 fv_p
= fields
->field_values
[indx
];
2341 switch (fields
->occurrence
) {
2343 /* print the value of only the first occurrence of the field */
2344 if (g_ptr_array_len(fv_p
) != 0) {
2346 * This isn't the first occurrence, so the value won't be used;
2354 /* print the value of only the last occurrence of the field */
2355 if (g_ptr_array_len(fv_p
) != 0) {
2357 * This isn't the first occurrence, so there's already a
2358 * value in the array, which won't be used; free the
2359 * first (only) element in the array, and then remove
2360 * it - this value will replace it.
2362 g_free(g_ptr_array_index(fv_p
, 0));
2363 g_ptr_array_set_size(fv_p
, 0);
2367 /* print the value of all accurrences of the field */
2368 if (g_ptr_array_len(fv_p
) != 0) {
2370 * This isn't the first occurrence. so add the "aggregator"
2371 * character as a separator between the previous element
2374 g_ptr_array_add(fv_p
, (gpointer
)g_strdup_printf("%c", fields
->aggregator
));
2378 g_assert_not_reached();
2382 g_ptr_array_add(fv_p
, (gpointer
)value
);
2385 static void proto_tree_get_node_field_values(proto_node
*node
, gpointer data
)
2387 write_field_data_t
*call_data
;
2389 gpointer field_index
;
2391 call_data
= (write_field_data_t
*)data
;
2392 fi
= PNODE_FINFO(node
);
2394 /* dissection with an invisible proto tree? */
2397 field_index
= g_hash_table_lookup(call_data
->fields
->field_indicies
, fi
->hfinfo
->abbrev
);
2398 if (NULL
!= field_index
) {
2399 format_field_values(call_data
->fields
, field_index
,
2400 get_node_field_value(fi
, call_data
->edt
) /* g_ alloc'd string */
2405 if (node
->first_child
!= NULL
) {
2406 proto_tree_children_foreach(node
, proto_tree_get_node_field_values
,
2411 static void write_specified_fields(fields_format format
, output_fields_t
*fields
, epan_dissect_t
*edt
, column_info
*cinfo
, FILE *fh
, json_dumper
*dumper
)
2416 gpointer field_index
;
2418 write_field_data_t data
;
2421 g_assert(fields
->fields
);
2423 /* JSON formats must go through json_dumper */
2424 if (format
== FORMAT_JSON
|| format
== FORMAT_EK
) {
2425 g_assert(!fh
&& dumper
);
2427 g_assert(fh
&& !dumper
);
2430 data
.fields
= fields
;
2433 if (NULL
== fields
->field_indicies
) {
2434 /* Prepare a lookup table from string abbreviation for field to its index. */
2435 fields
->field_indicies
= g_hash_table_new(g_str_hash
, g_str_equal
);
2438 while (i
< fields
->fields
->len
) {
2439 gchar
*field
= (gchar
*)g_ptr_array_index(fields
->fields
, i
);
2440 /* Store field indicies +1 so that zero is not a valid value,
2441 * and can be distinguished from NULL as a pointer.
2444 g_hash_table_insert(fields
->field_indicies
, field
, GUINT_TO_POINTER(i
));
2448 /* Array buffer to store values for this packet */
2449 /* Allocate an array for the 'GPtrarray *' the first time */
2450 /* ths function is invoked for a file; */
2451 /* Any and all 'GPtrArray *' are freed (after use) each */
2452 /* time (each packet) this function is invoked for a flle. */
2453 /* XXX: ToDo: use packet-scope'd memory & (if/when implemented) wmem ptr_array */
2454 if (NULL
== fields
->field_values
)
2455 fields
->field_values
= g_new0(GPtrArray
*, fields
->fields
->len
); /* free'd in output_fields_free() */
2457 proto_tree_children_foreach(edt
->tree
, proto_tree_get_node_field_values
,
2460 /* Add columns to fields */
2461 if (fields
->includes_col_fields
) {
2462 for (col
= 0; col
< cinfo
->num_cols
; col
++) {
2463 if (!get_column_visible(col
))
2465 /* Prepend COLUMN_FIELD_FILTER as the field name */
2466 col_name
= g_strdup_printf("%s%s", COLUMN_FIELD_FILTER
, cinfo
->columns
[col
].col_title
);
2467 field_index
= g_hash_table_lookup(fields
->field_indicies
, col_name
);
2470 if (NULL
!= field_index
) {
2471 format_field_values(fields
, field_index
, g_strdup(cinfo
->columns
[col
].col_data
));
2478 for(i
= 0; i
< fields
->fields
->len
; ++i
) {
2480 fputc(fields
->separator
, fh
);
2482 if (NULL
!= fields
->field_values
[i
]) {
2486 fv_p
= fields
->field_values
[i
];
2487 if (fields
->quote
!= '\0') {
2488 fputc(fields
->quote
, fh
);
2491 /* Output the array of (partial) field values */
2492 for (j
= 0; j
< g_ptr_array_len(fv_p
); j
++ ) {
2493 str
= (gchar
*)g_ptr_array_index(fv_p
, j
);
2494 print_escaped_csv(fh
, str
);
2497 if (fields
->quote
!= '\0') {
2498 fputc(fields
->quote
, fh
);
2500 g_ptr_array_free(fv_p
, TRUE
); /* get ready for the next packet */
2501 fields
->field_values
[i
] = NULL
;
2506 for(i
= 0; i
< fields
->fields
->len
; ++i
) {
2507 gchar
*field
= (gchar
*)g_ptr_array_index(fields
->fields
, i
);
2509 if (NULL
!= fields
->field_values
[i
]) {
2513 fv_p
= fields
->field_values
[i
];
2515 /* Output the array of (partial) field values */
2516 for (j
= 0; j
< (g_ptr_array_len(fv_p
)); j
+=2 ) {
2517 str
= (gchar
*)g_ptr_array_index(fv_p
, j
);
2519 fprintf(fh
, " <field name=\"%s\" value=", field
);
2521 print_escaped_xml(fh
, str
);
2522 fputs("\"/>\n", fh
);
2525 g_ptr_array_free(fv_p
, TRUE
); /* get ready for the next packet */
2526 fields
->field_values
[i
] = NULL
;
2531 json_dumper_begin_object(dumper
);
2532 for(i
= 0; i
< fields
->fields
->len
; ++i
) {
2533 gchar
*field
= (gchar
*)g_ptr_array_index(fields
->fields
, i
);
2535 if (NULL
!= fields
->field_values
[i
]) {
2539 fv_p
= fields
->field_values
[i
];
2541 json_dumper_set_member_name(dumper
, field
);
2542 json_dumper_begin_array(dumper
);
2544 /* Output the array of (partial) field values */
2545 for (j
= 0; j
< (g_ptr_array_len(fv_p
)); j
+= 2) {
2546 str
= (gchar
*) g_ptr_array_index(fv_p
, j
);
2547 json_dumper_value_string(dumper
, str
);
2551 json_dumper_end_array(dumper
);
2553 g_ptr_array_free(fv_p
, TRUE
); /* get ready for the next packet */
2554 fields
->field_values
[i
] = NULL
;
2557 json_dumper_end_object(dumper
);
2560 for(i
= 0; i
< fields
->fields
->len
; ++i
) {
2561 gchar
*field
= (gchar
*)g_ptr_array_index(fields
->fields
, i
);
2563 if (NULL
!= fields
->field_values
[i
]) {
2567 fv_p
= fields
->field_values
[i
];
2569 json_dumper_set_member_name(dumper
, field
);
2570 json_dumper_begin_array(dumper
);
2572 /* Output the array of (partial) field values */
2573 for (j
= 0; j
< (g_ptr_array_len(fv_p
)); j
+= 2) {
2574 str
= (gchar
*)g_ptr_array_index(fv_p
, j
);
2575 json_dumper_value_string(dumper
, str
);
2579 json_dumper_end_array(dumper
);
2581 g_ptr_array_free(fv_p
, TRUE
); /* get ready for the next packet */
2582 fields
->field_values
[i
] = NULL
;
2588 fprintf(stderr
, "Unknown fields format %d\n", format
);
2589 g_assert_not_reached();
2594 void write_fields_finale(output_fields_t
* fields _U_
, FILE *fh _U_
)
2599 /* Returns an g_malloced string */
2600 gchar
* get_node_field_value(field_info
* fi
, epan_dissect_t
* edt
)
2602 if (fi
->hfinfo
->id
== hf_text_only
) {
2606 return g_strdup(fi
->rep
->representation
);
2609 return get_field_hex_value(edt
->pi
.data_src
, fi
);
2612 else if (fi
->hfinfo
->id
== proto_data
) {
2613 /* Uninterpreted data, i.e., the "Data" protocol, is
2614 * printed as a field instead of a protocol. */
2615 return get_field_hex_value(edt
->pi
.data_src
, fi
);
2618 /* Normal protocols and fields */
2619 gchar
*dfilter_string
;
2621 switch (fi
->hfinfo
->type
)
2624 /* Print out the full details for the protocol. */
2626 return g_strdup(fi
->rep
->representation
);
2628 /* Just print out the protocol abbreviation */
2629 return g_strdup(fi
->hfinfo
->abbrev
);
2632 /* Return "1" so that the presence of a field of type
2633 * FT_NONE can be checked when using -T fields */
2634 return g_strdup("1");
2639 guint8
*bytes
= (guint8
*)fvalue_get(&fi
->value
);
2641 dfilter_string
= (gchar
*)wmem_alloc(NULL
, 3*fvalue_length(&fi
->value
));
2642 switch (fi
->hfinfo
->display
) {
2644 ret
= bytes_to_hexstr_punct(dfilter_string
, bytes
, fvalue_length(&fi
->value
), '.');
2647 ret
= bytes_to_hexstr_punct(dfilter_string
, bytes
, fvalue_length(&fi
->value
), '-');
2650 ret
= bytes_to_hexstr_punct(dfilter_string
, bytes
, fvalue_length(&fi
->value
), ':');
2653 ret
= bytes_to_hexstr_punct(dfilter_string
, bytes
, fvalue_length(&fi
->value
), ' ');
2657 ret
= bytes_to_hexstr(dfilter_string
, bytes
, fvalue_length(&fi
->value
));
2661 ret
= g_strdup(dfilter_string
);
2662 wmem_free(NULL
, dfilter_string
);
2664 if (fi
->hfinfo
->display
& BASE_ALLOW_ZERO
) {
2665 ret
= g_strdup("<none>");
2667 ret
= g_strdup("<MISSING>");
2674 dfilter_string
= fvalue_to_string_repr(NULL
, &fi
->value
, FTREPR_DISPLAY
, fi
->hfinfo
->display
);
2675 if (dfilter_string
!= NULL
) {
2676 gchar
* ret
= g_strdup(dfilter_string
);
2677 wmem_free(NULL
, dfilter_string
);
2680 return get_field_hex_value(edt
->pi
.data_src
, fi
);
2687 get_field_hex_value(GSList
*src_list
, field_info
*fi
)
2694 if (fi
->length
> tvb_captured_length_remaining(fi
->ds_tvb
, fi
->start
)) {
2695 return g_strdup("field length invalid!");
2698 /* Find the data for this field. */
2699 pd
= get_field_data(src_list
, fi
);
2706 const int chars_per_byte
= 2;
2708 len
= chars_per_byte
* fi
->length
;
2709 buffer
= (gchar
*)g_malloc(sizeof(gchar
)*(len
+ 1));
2710 buffer
[len
] = '\0'; /* Ensure NULL termination in bad cases */
2712 /* Print a simple hex dump */
2713 for (i
= 0 ; i
< fi
->length
; i
++) {
2714 g_snprintf(p
, chars_per_byte
+1, "%02x", pd
[i
]);
2715 p
+= chars_per_byte
;
2723 output_fields_t
* output_fields_new(void)
2725 output_fields_t
* fields
= g_new(output_fields_t
, 1);
2726 fields
->print_bom
= FALSE
;
2727 fields
->print_header
= FALSE
;
2728 fields
->separator
= '\t';
2729 fields
->occurrence
= 'a';
2730 fields
->aggregator
= ',';
2731 fields
->fields
= NULL
; /*Do lazy initialisation */
2732 fields
->field_indicies
= NULL
;
2733 fields
->field_values
= NULL
;
2734 fields
->quote
='\0';
2735 fields
->includes_col_fields
= FALSE
;
2740 * Editor modelines - https://www.wireshark.org/tools/modelines.html
2745 * indent-tabs-mode: nil
2748 * vi: set shiftwidth=4 tabstop=8 expandtab:
2749 * :indentSize=4:tabSize=8:noTabs=true: