Coverage Report

Created: 2026-07-12 07:10

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