X-Git-Url: http://git.samba.org/samba.git/?a=blobdiff_plain;f=print.c;h=7243b8c0bf783c2f3d5c8643d8c3e9f70e57f7bf;hb=8bec5ac62c09185a8e728e27cdbff3f533d776ad;hp=5d26810405b605e425aeadb488db76c4e75ff074;hpb=f8921bc87aac76fbaf69ee20fda3ba1047202eb9;p=obnox%2Fwireshark%2Fwip.git diff --git a/print.c b/print.c index 5d26810405..7243b8c0bf 100644 --- a/print.c +++ b/print.c @@ -1,12 +1,12 @@ /* print.c * Routines for printing packet analysis trees. * - * $Id: print.c,v 1.75 2004/04/17 09:02:32 ulfl Exp $ + * $Id$ * * Gilbert Ramirez * - * Ethereal - Network traffic analyzer - * By Gerald Combs + * Wireshark - Network traffic analyzer + * By Gerald Combs * Copyright 1998 Gerald Combs * * This program is free software; you can redistribute it and/or @@ -31,54 +31,96 @@ #include #include +#include + #include #include #include #include +#include -#include "range.h" +#include "packet-range.h" #include "print.h" #include "ps.h" -#include "util.h" -#include "packet-data.h" -#include "packet-frame.h" +#include "version_info.h" +#include +#include +#include +#include +#include #define PDML_VERSION "0" +#define PSML_VERSION "0" + +typedef struct { + int level; + print_stream_t *stream; + gboolean success; + GSList *src_list; + print_dissections_e print_dissections; + gboolean print_hex_for_data; + packet_char_enc encoding; + epan_dissect_t *edt; +} print_data; +typedef struct { + int level; + FILE *fh; + GSList *src_list; + epan_dissect_t *edt; +} write_pdml_data; + +typedef struct { + output_fields_t* fields; + epan_dissect_t *edt; +} write_field_data_t; + +struct _output_fields { + gboolean print_header; + gchar separator; + gchar occurrence; + gchar aggregator; + GPtrArray* fields; + GHashTable* field_indicies; + emem_strbuf_t** field_values; + gchar quote; +}; + +GHashTable *output_only_tables = NULL; + +static gboolean write_headers = FALSE; + +static const gchar* get_field_hex_value(GSList* src_list, field_info *fi); static void proto_tree_print_node(proto_node *node, gpointer data); -static void proto_tree_print_node_pdml(proto_node *node, gpointer data); -static void print_hex_data_buffer(FILE *fh, register const guchar *cp, - register guint length, char_enc encoding, gint format); +static void proto_tree_write_node_pdml(proto_node *node, gpointer data); +static const guint8 *get_field_data(GSList *src_list, field_info *fi); +static void write_pdml_field_hex_value(write_pdml_data *pdata, field_info *fi); +static gboolean print_hex_data_buffer(print_stream_t *stream, const guchar *cp, + guint length, packet_char_enc encoding); static void ps_clean_string(unsigned char *out, const unsigned char *in, int outbuf_size); +static void print_escaped_xml(FILE *fh, const char *unescaped_string); -typedef struct { - int level; - FILE *fh; - GSList *src_list; - print_dissections_e print_dissections; - gboolean print_hex_for_data; - char_enc encoding; - gint format; - epan_dissect_t *edt; -} print_data; +static void print_pdml_geninfo(proto_tree *tree, FILE *fh); -static void print_pdml_geninfo(proto_tree *tree, print_data *pdata); +static void proto_tree_get_node_field_values(proto_node *node, gpointer data); -FILE *open_print_dest(int to_file, const char *dest) +static FILE * +open_print_dest(int to_file, const char *dest) { FILE *fh; /* Open the file or command for output */ if (to_file) - fh = fopen(dest, "w"); + fh = ws_fopen(dest, "w"); else fh = popen(dest, "w"); return fh; } -gboolean close_print_dest(int to_file, FILE *fh) +static gboolean +close_print_dest(int to_file, FILE *fh) { /* Close the file or command */ if (to_file) @@ -87,98 +129,53 @@ gboolean close_print_dest(int to_file, FILE *fh) return (pclose(fh) == 0); } +#define MAX_PS_LINE_LENGTH 256 -void +gboolean proto_tree_print(print_args_t *print_args, epan_dissect_t *edt, - FILE *fh) + print_stream_t *stream) { print_data data; /* Create the output */ data.level = 0; - data.fh = fh; + data.stream = stream; + data.success = TRUE; data.src_list = edt->pi.data_src; data.encoding = edt->pi.fd->flags.encoding; data.print_dissections = print_args->print_dissections; + /* If we're printing the entire packet in hex, don't + print uninterpreted data fields in hex as well. */ data.print_hex_for_data = !print_args->print_hex; - /* If we're printing the entire packet in hex, don't - print uninterpreted data fields in hex as well. */ - data.format = print_args->format; data.edt = edt; - if (data.format == PR_FMT_PDML) { - - fprintf(fh, "\n"); - - /* Print a "geninfo" protocol as required by PDML */ - print_pdml_geninfo(edt->tree, &data); - - proto_tree_children_foreach(edt->tree, proto_tree_print_node_pdml, &data); - - fprintf(fh, "\n\n"); - } - else { - proto_tree_children_foreach(edt->tree, proto_tree_print_node, &data); - } -} - -/* - * Find the data source for a specified field, and return a pointer - * to the data in it. - */ -static const guint8 * -get_field_data(GSList *src_list, field_info *fi) -{ - GSList *src_le; - data_source *src; - tvbuff_t *src_tvb; - gint length, tvbuff_length; - - for (src_le = src_list; src_le != NULL; src_le = src_le->next) { - src = src_le->data; - src_tvb = src->tvb; - if (fi->ds_tvb == src_tvb) { - /* - * Found it. - * - * XXX - a field can have a length that runs past - * the end of the tvbuff. Ideally, that should - * be fixed when adding an item to the protocol - * tree, but checking the length when doing - * that could be expensive. Until we fix that, - * we'll do the check here. - */ - length = fi->length; - tvbuff_length = tvb_length_remaining(src_tvb, - fi->start); - if (length > tvbuff_length) - length = tvbuff_length; - return tvb_get_ptr(src_tvb, fi->start, length); - } - } - g_assert_not_reached(); - return NULL; /* not found */ + proto_tree_children_foreach(edt->tree, proto_tree_print_node, &data); + return data.success; } #define MAX_INDENT 160 -#define MAX_PS_LINE_LENGTH 256 - /* Print a tree's data, and any child nodes. */ static void proto_tree_print_node(proto_node *node, gpointer data) { - field_info *fi = PITEM_FINFO(node); + field_info *fi = PNODE_FINFO(node); print_data *pdata = (print_data*) data; const guint8 *pd; gchar label_str[ITEM_LABEL_LENGTH]; gchar *label_ptr; + g_assert(fi && "dissection with an invisible proto tree?"); + /* Don't print invisible entries. */ - if (!fi->visible) + if (PROTO_ITEM_IS_HIDDEN(node)) + return; + + /* Give up if we've already gotten an error. */ + if (!pdata->success) return; - /* was a free format label produced? */ + /* was a free format label produced? */ if (fi->rep) { label_ptr = fi->rep->representation; } @@ -187,7 +184,31 @@ void proto_tree_print_node(proto_node *node, gpointer data) proto_item_fill_label(fi, label_str); } - print_line(pdata->fh, pdata->level, pdata->format, label_ptr); + if (PROTO_ITEM_IS_GENERATED(node)) { + label_ptr = g_strdup_printf("[%s]", label_ptr); + } + + if (!print_line(pdata->stream, pdata->level, label_ptr)) { + pdata->success = FALSE; + return; + } + + /* + * If -O is specified, only display the protocols which are in the + * lookup table. Only check on the first level: once we start printing + * a tree, print the rest of the subtree. Otherwise we won't print + * subitems whose abbreviation doesn't match the protocol--for example + * text items (whose abbreviation is simply "text"). + */ + if (output_only_tables != NULL && pdata->level == 0 + && g_hash_table_lookup(output_only_tables, fi->hfinfo->abbrev) == NULL) { + pdata->success = TRUE; + return; + } + + if (PROTO_ITEM_IS_GENERATED(node)) { + g_free(label_ptr); + } /* If it's uninterpreted data, dump it (unless our caller will be printing the entire packet in hex). */ @@ -196,8 +217,13 @@ void proto_tree_print_node(proto_node *node, gpointer data) * Find the data for this field. */ pd = get_field_data(pdata->src_list, fi); - print_hex_data_buffer(pdata->fh, pd, fi->length, - pdata->encoding, pdata->format); + if (pd) { + if (!print_hex_data_buffer(pdata->stream, pd, + fi->length, pdata->encoding)) { + pdata->success = FALSE; + return; + } + } } /* If we're printing all levels, or if this node is one with a @@ -206,75 +232,93 @@ void proto_tree_print_node(proto_node *node, gpointer data) g_assert(fi->tree_type >= -1 && fi->tree_type < num_tree_types); if (pdata->print_dissections == print_dissections_expanded || (pdata->print_dissections == print_dissections_as_displayed && - fi->tree_type >= 0 && tree_is_expanded[fi->tree_type])) { + fi->tree_type >= 0 && tree_is_expanded[fi->tree_type])) { if (node->first_child != NULL) { pdata->level++; proto_tree_children_foreach(node, proto_tree_print_node, pdata); pdata->level--; + if (!pdata->success) + return; } } } -/* Print a string, escaping out certain characters that need to - * escaped out for XML. */ -static void -print_escaped_xml(FILE *fh, char *unescaped_string) +#define PDML2HTML_XSL "pdml2html.xsl" +void +write_pdml_preamble(FILE *fh, const gchar* filename) { - unsigned char *p; - - for (p = unescaped_string; *p != '\0'; p++) { - switch (*p) { - case '&': - fputs("&", fh); - break; - case '<': - fputs("<", fh); - break; - case '>': - fputs(">", fh); - break; - case '"': - fputs(""", fh); - break; - default: - fputc(*p, fh); - } - } + time_t t=time(NULL); + char *ts=asctime(localtime(&t)); + ts[strlen(ts)-1]=0; /* overwrite \n */ + + fputs("\n", fh); + fputs("\n", fh); + fprintf(fh, "\n", get_datafile_dir()); + fputs("\n", PACKAGE, VERSION, ts, filename ? filename : ""); } -static void -print_field_hex_value(print_data *pdata, field_info *fi) +void +proto_tree_write_pdml(epan_dissect_t *edt, FILE *fh) { - int i; - const guint8 *pd; + write_pdml_data data; - /* Find the data for this field. */ - pd = get_field_data(pdata->src_list, fi); + /* Create the output */ + data.level = 0; + data.fh = fh; + data.src_list = edt->pi.data_src; + data.edt = edt; - /* Print a simple hex dump */ - for (i = 0 ; i < fi->length; i++) { - fprintf(pdata->fh, "%02x", pd[i]); - } -} + fprintf(fh, "\n"); + + /* Print a "geninfo" protocol as required by PDML */ + print_pdml_geninfo(edt->tree, fh); + proto_tree_children_foreach(edt->tree, proto_tree_write_node_pdml, + &data); + + fprintf(fh, "\n\n"); +} -/* Print a tree's data, and any child nodes, as PDML */ +/* Write out a tree's data, and any child nodes, as PDML */ static void -proto_tree_print_node_pdml(proto_node *node, gpointer data) +proto_tree_write_node_pdml(proto_node *node, gpointer data) { - field_info *fi = PITEM_FINFO(node); - print_data *pdata = (print_data*) data; - gchar *label_ptr; + field_info *fi = PNODE_FINFO(node); + write_pdml_data *pdata = (write_pdml_data*) data; + const gchar *label_ptr; gchar label_str[ITEM_LABEL_LENGTH]; char *dfilter_string; - int chop_len; + size_t chop_len; int i; + gboolean wrap_in_fake_protocol; + + g_assert(fi && "dissection with an invisible proto tree?"); + + /* Will wrap up top-level field items inside a fake protocol wrapper to + preserve the PDML schema */ + wrap_in_fake_protocol = + (((fi->hfinfo->type != FT_PROTOCOL) || + (fi->hfinfo->id == proto_data)) && + (pdata->level == 0)); + /* Indent to the correct level */ for (i = -1; i < pdata->level; i++) { fputs(" ", pdata->fh); } + if (wrap_in_fake_protocol) { + /* Open fake protocol wrapper */ + fputs("\n", pdata->fh); + + /* Indent to increased level before writint out field */ + pdata->level++; + for (i = -1; i < pdata->level; i++) { + fputs(" ", pdata->fh); + } + } + /* Text label. It's printed as a field with no name. */ if (fi->hfinfo->id == hf_text_only) { /* Get the text */ @@ -285,14 +329,16 @@ proto_tree_print_node_pdml(proto_node *node, gpointer data) label_ptr = ""; } - fputs("fh); + /* Show empty name since it is a required field */ + fputs("fh); + fputs("\" show=\"", pdata->fh); print_escaped_xml(pdata->fh, label_ptr); fprintf(pdata->fh, "\" size=\"%d", fi->length); fprintf(pdata->fh, "\" pos=\"%d", fi->start); fputs("\" value=\"", pdata->fh); - print_field_hex_value(pdata, fi); + write_pdml_field_hex_value(pdata, fi); if (node->first_child != NULL) { fputs("\">\n", pdata->fh); @@ -301,16 +347,15 @@ proto_tree_print_node_pdml(proto_node *node, gpointer data) fputs("\"/>\n", pdata->fh); } } + /* Uninterpreted data, i.e., the "Data" protocol, is * printed as a field instead of a protocol. */ else if (fi->hfinfo->id == proto_data) { + /* Write out field with data */ fputs("fh); - - print_field_hex_value(pdata, fi); - + write_pdml_field_hex_value(pdata, fi); fputs("\"/>\n", pdata->fh); - } /* Normal protocols and fields */ else { @@ -323,19 +368,19 @@ proto_tree_print_node_pdml(proto_node *node, gpointer data) print_escaped_xml(pdata->fh, fi->hfinfo->abbrev); #if 0 - /* PDML spec, see: - * http://analyzer.polito.it/30alpha/docs/dissectors/PDMLSpec.htm - * - * the show fields contains things in 'human readable' format - * showname: contains only the name of the field - * show: contains only the data of the field - * showdtl: contains additional details of the field data - * showmap: contains mappings of the field data (e.g. the hostname to an IP address) - * - * XXX - the showname shouldn't contain the field data itself - * (like it's contained in the fi->rep->representation). - * Unfortunately, we don't have the field data representation for - * all fields, so this isn't currently possible */ + /* PDML spec, see: + * http://www.nbee.org/doku.php?id=netpdl:pdml_specification + * + * the show fields contains things in 'human readable' format + * showname: contains only the name of the field + * show: contains only the data of the field + * showdtl: contains additional details of the field data + * showmap: contains mappings of the field data (e.g. the hostname to an IP address) + * + * XXX - the showname shouldn't contain the field data itself + * (like it's contained in the fi->rep->representation). + * Unfortunately, we don't have the field data representation for + * all fields, so this isn't currently possible */ fputs("\" showname=\"", pdata->fh); print_escaped_xml(pdata->fh, fi->hfinfo->name); #endif @@ -351,21 +396,26 @@ proto_tree_print_node_pdml(proto_node *node, gpointer data) print_escaped_xml(pdata->fh, label_ptr); } - if(!fi->visible) { - fprintf(pdata->fh, "\" hide=\"yes"); - } + if (PROTO_ITEM_IS_HIDDEN(node)) + fprintf(pdata->fh, "\" hide=\"yes"); fprintf(pdata->fh, "\" size=\"%d", fi->length); fprintf(pdata->fh, "\" pos=\"%d", fi->start); /* fprintf(pdata->fh, "\" id=\"%d", fi->hfinfo->id);*/ - if (fi->hfinfo->type != FT_PROTOCOL) { - /* Field */ - + /* show, value, and unmaskedvalue attributes */ + switch (fi->hfinfo->type) + { + case FT_PROTOCOL: + break; + case FT_NONE: + fputs("\" show=\"\" value=\"", pdata->fh); + break; + default: /* XXX - this is a hack until we can just call * fvalue_to_string_repr() for *all* FT_* types. */ - dfilter_string = proto_construct_dfilter_string(fi, - pdata->edt); + dfilter_string = proto_construct_match_selected_string(fi, + pdata->edt); if (dfilter_string != NULL) { chop_len = strlen(fi->hfinfo->abbrev) + 4; /* for " == " */ @@ -382,9 +432,25 @@ proto_tree_print_node_pdml(proto_node *node, gpointer data) fputs("\" show=\"", pdata->fh); print_escaped_xml(pdata->fh, &dfilter_string[chop_len]); } + + /* + * XXX - should we omit "value" for any fields? + * What should we do for fields whose length is 0? + * They might come from a pseudo-header or from + * the capture header (e.g., time stamps), or + * they might be generated fields. + */ if (fi->length > 0) { fputs("\" value=\"", pdata->fh); - print_field_hex_value(pdata, fi); + + if (fi->hfinfo->bitmask!=0) { + fprintf(pdata->fh, "%X", fvalue_get_uinteger(&fi->value)); + fputs("\" unmaskedvalue=\"", pdata->fh); + write_pdml_field_hex_value(pdata, fi); + } + else { + write_pdml_field_hex_value(pdata, fi); + } } } @@ -403,29 +469,43 @@ proto_tree_print_node_pdml(proto_node *node, gpointer data) if (node->first_child != NULL) { pdata->level++; proto_tree_children_foreach(node, - proto_tree_print_node_pdml, pdata); + proto_tree_write_node_pdml, pdata); + pdata->level--; + } + + /* Take back the extra level we added for fake wrapper protocol */ + if (wrap_in_fake_protocol) { pdata->level--; } if (node->first_child != NULL) { + /* Indent to correct level */ for (i = -1; i < pdata->level; i++) { fputs(" ", pdata->fh); } - if (fi->hfinfo->type == FT_PROTOCOL) { - fputs("\n", pdata->fh); - } - else { - fputs("\n", pdata->fh); + /* Close off current element */ + if (fi->hfinfo->id != proto_data) { /* Data protocol uses simple tags */ + if (fi->hfinfo->type == FT_PROTOCOL) { + fputs("\n", pdata->fh); + } + else { + fputs("\n", pdata->fh); + } } } + + /* Close off fake wrapper protocol */ + if (wrap_in_fake_protocol) { + fputs("\n", pdata->fh); + } } /* Print info for a 'geninfo' pseudo-protocol. This is required by - * the PDML spec. The information is contained in Ethereal's 'frame' protocol, + * the PDML spec. The information is contained in Wireshark's 'frame' protocol, * but we produce a 'geninfo' protocol in the PDML to conform to spec. * The 'frame' protocol follows the 'geninfo' protocol in the PDML. */ static void -print_pdml_geninfo(proto_tree *tree, print_data *pdata) +print_pdml_geninfo(proto_tree *tree, FILE *fh) { guint32 num, len, caplen; nstime_t *timestamp; @@ -437,79 +517,323 @@ print_pdml_geninfo(proto_tree *tree, print_data *pdata) if (g_ptr_array_len(finfo_array) < 1) { return; } - frame_finfo = finfo_array->pdata[0]; - g_ptr_array_free(finfo_array, FALSE); + frame_finfo = (field_info *)finfo_array->pdata[0]; + g_ptr_array_free(finfo_array, TRUE); /* frame.number --> geninfo.num */ finfo_array = proto_find_finfo(tree, hf_frame_number); if (g_ptr_array_len(finfo_array) < 1) { return; } - num = fvalue_get_integer(&((field_info*)finfo_array->pdata[0])->value); - g_ptr_array_free(finfo_array, FALSE); + num = fvalue_get_uinteger(&((field_info*)finfo_array->pdata[0])->value); + g_ptr_array_free(finfo_array, TRUE); - /* frame.pkt_len --> geninfo.len */ - finfo_array = proto_find_finfo(tree, hf_frame_packet_len); + /* frame.frame_len --> geninfo.len */ + finfo_array = proto_find_finfo(tree, hf_frame_len); if (g_ptr_array_len(finfo_array) < 1) { return; } - len = fvalue_get_integer(&((field_info*)finfo_array->pdata[0])->value); - g_ptr_array_free(finfo_array, FALSE); + len = fvalue_get_uinteger(&((field_info*)finfo_array->pdata[0])->value); + g_ptr_array_free(finfo_array, TRUE); /* frame.cap_len --> geninfo.caplen */ finfo_array = proto_find_finfo(tree, hf_frame_capture_len); if (g_ptr_array_len(finfo_array) < 1) { return; } - caplen = fvalue_get_integer(&((field_info*)finfo_array->pdata[0])->value); - g_ptr_array_free(finfo_array, FALSE); + caplen = fvalue_get_uinteger(&((field_info*)finfo_array->pdata[0])->value); + g_ptr_array_free(finfo_array, TRUE); /* frame.time --> geninfo.timestamp */ finfo_array = proto_find_finfo(tree, hf_frame_arrival_time); if (g_ptr_array_len(finfo_array) < 1) { return; } - timestamp = fvalue_get(&((field_info*)finfo_array->pdata[0])->value); - g_ptr_array_free(finfo_array, FALSE); + timestamp = (nstime_t *)fvalue_get(&((field_info*)finfo_array->pdata[0])->value); + g_ptr_array_free(finfo_array, TRUE); /* Print geninfo start */ - fprintf(pdata->fh, + fprintf(fh, " \n", frame_finfo->length); /* Print geninfo.num */ - fprintf(pdata->fh, + fprintf(fh, " \n", num, num, frame_finfo->length); /* Print geninfo.len */ - fprintf(pdata->fh, -" \n", + fprintf(fh, +" \n", len, len, frame_finfo->length); /* Print geninfo.caplen */ - fprintf(pdata->fh, + fprintf(fh, " \n", caplen, caplen, frame_finfo->length); /* Print geninfo.timestamp */ - fprintf(pdata->fh, + fprintf(fh, " \n", - abs_time_to_str(timestamp), (int) timestamp->secs, timestamp->nsecs, frame_finfo->length); + abs_time_to_str(timestamp, ABSOLUTE_TIME_LOCAL, TRUE), (int) timestamp->secs, timestamp->nsecs, frame_finfo->length); /* Print geninfo end */ - fprintf(pdata->fh, + fprintf(fh, " \n"); } +void +write_pdml_finale(FILE *fh) +{ + fputs("\n", fh); +} + +void +write_psml_preamble(FILE *fh) +{ + fputs("\n", fh); + fputs("\n", PACKAGE, VERSION); + write_headers = TRUE; +} + +void +proto_tree_write_psml(epan_dissect_t *edt, FILE *fh) +{ + gint i; + + /* if this is the first packet, we have to create the PSML structure output */ + if(write_headers) { + fprintf(fh, "\n"); + + for(i=0; i < edt->pi.cinfo->num_cols; i++) { + fprintf(fh, "
"); + print_escaped_xml(fh, edt->pi.cinfo->col_title[i]); + fprintf(fh, "
\n"); + } + + fprintf(fh, "
\n\n"); + + write_headers = FALSE; + } + + fprintf(fh, "\n"); + + for(i=0; i < edt->pi.cinfo->num_cols; i++) { + fprintf(fh, "
"); + print_escaped_xml(fh, edt->pi.cinfo->col_data[i]); + fprintf(fh, "
\n"); + } + + fprintf(fh, "
\n\n"); +} + +void +write_psml_finale(FILE *fh) +{ + fputs("
\n", fh); +} + +void +write_csv_preamble(FILE *fh _U_) +{ + write_headers = TRUE; +} + +static gchar *csv_massage_str(const gchar *source, const gchar *exceptions) +{ + gchar *csv_str; + gchar *tmp_str; + + csv_str = g_strescape(source, exceptions); + tmp_str = csv_str; + while ( (tmp_str = strstr(tmp_str, "\\\"")) != NULL ) + *tmp_str = '\"'; + return csv_str; +} + +static void csv_write_str(const char *str, char sep, FILE *fh) +{ + gchar *csv_str; + + csv_str = csv_massage_str(str, NULL); + fprintf(fh, "\"%s\"%c", csv_str, sep); + g_free(csv_str); +} + +void +proto_tree_write_csv(epan_dissect_t *edt, FILE *fh) +{ + gint i; + + /* if this is the first packet, we have to write the CSV header */ + if(write_headers) { + for(i=0; i < edt->pi.cinfo->num_cols - 1; i++) + csv_write_str(edt->pi.cinfo->col_title[i], ',', fh); + csv_write_str(edt->pi.cinfo->col_title[i], '\n', fh); + write_headers = FALSE; + } + + for(i=0; i < edt->pi.cinfo->num_cols - 1; i++) + csv_write_str(edt->pi.cinfo->col_data[i], ',', fh); + csv_write_str(edt->pi.cinfo->col_data[i], '\n', fh); +} + +void +write_csv_finale(FILE *fh _U_) +{ + +} + +void +write_carrays_preamble(FILE *fh _U_) +{ + +} + +void +proto_tree_write_carrays(const guint8 *pd, guint32 len, guint32 num, FILE *fh) +{ + guint32 i = 0; + + if (!len) + return; + + fprintf(fh, "char pkt%u[] = {\n", num); + + for (i = 0; i < len; i++) { + + fprintf(fh, "0x%02x", *(pd + i)); + + if (i == (len - 1)) { + fprintf(fh, " };\n\n"); + break; + } + + if (!((i + 1) % 8)) { + fprintf(fh, ", \n"); + } else { + fprintf(fh, ", "); + } + } +} + +void +write_carrays_finale(FILE *fh _U_) +{ + +} + +/* + * Find the data source for a specified field, and return a pointer + * to the data in it. Returns NULL if the data is out of bounds. + */ +static const guint8 * +get_field_data(GSList *src_list, field_info *fi) +{ + GSList *src_le; + data_source *src; + tvbuff_t *src_tvb; + gint length, tvbuff_length; + + for (src_le = src_list; src_le != NULL; src_le = src_le->next) { + src = (data_source *)src_le->data; + src_tvb = src->tvb; + if (fi->ds_tvb == src_tvb) { + /* + * Found it. + * + * XXX - a field can have a length that runs past + * the end of the tvbuff. Ideally, that should + * be fixed when adding an item to the protocol + * tree, but checking the length when doing + * that could be expensive. Until we fix that, + * we'll do the check here. + */ + tvbuff_length = tvb_length_remaining(src_tvb, + fi->start); + if (tvbuff_length < 0) { + return NULL; + } + length = fi->length; + if (length > tvbuff_length) + length = tvbuff_length; + return tvb_get_ptr(src_tvb, fi->start, length); + } + } + g_assert_not_reached(); + return NULL; /* not found */ +} + +/* Print a string, escaping out certain characters that need to + * escaped out for XML. */ +static void +print_escaped_xml(FILE *fh, const char *unescaped_string) +{ + const char *p; + char temp_str[8]; + + for (p = unescaped_string; *p != '\0'; p++) { + switch (*p) { + case '&': + fputs("&", fh); + break; + case '<': + fputs("<", fh); + break; + case '>': + fputs(">", fh); + break; + case '"': + fputs(""", fh); + break; + case '\'': + fputs("'", fh); + break; + default: + if (g_ascii_isprint(*p)) + fputc(*p, fh); + else { + g_snprintf(temp_str, sizeof(temp_str), "\\x%x", (guint8)*p); + fputs(temp_str, fh); + } + } + } +} -void print_hex_data(FILE *fh, gint format, epan_dissect_t *edt) +static void +write_pdml_field_hex_value(write_pdml_data *pdata, field_info *fi) +{ + int i; + const guint8 *pd; + + if (!fi->ds_tvb) + return; + + if (fi->length > tvb_length_remaining(fi->ds_tvb, fi->start)) { + fprintf(pdata->fh, "field length invalid!"); + return; + } + + /* Find the data for this field. */ + pd = get_field_data(pdata->src_list, fi); + + if (pd) { + /* Print a simple hex dump */ + for (i = 0 ; i < fi->length; i++) { + fprintf(pdata->fh, "%02x", pd[i]); + } + } +} + +gboolean +print_hex_data(print_stream_t *stream, epan_dissect_t *edt) { gboolean multiple_sources; GSList *src_le; data_source *src; tvbuff_t *tvb; - char *name; + const char *name; char *line; const guchar *cp; guint length; @@ -524,29 +848,31 @@ void print_hex_data(FILE *fh, gint format, epan_dissect_t *edt) for (src_le = edt->pi.data_src; src_le != NULL; src_le = src_le->next) { - src = src_le->data; + src = (data_source *)src_le->data; tvb = src->tvb; if (multiple_sources) { - name = src->name; - print_line(fh, 0, format, ""); - line = g_malloc(strlen(name) + 2); /* :\0 */ - strcpy(line, name); - strcat(line, ":"); - print_line(fh, 0, format, line); + name = get_data_source_name(src); + print_line(stream, 0, ""); + line = g_strdup_printf("%s:", name); + print_line(stream, 0, line); g_free(line); } length = tvb_length(tvb); + if (length == 0) + return TRUE; cp = tvb_get_ptr(tvb, 0, length); - print_hex_data_buffer(fh, cp, length, - edt->pi.fd->flags.encoding, format); + if (!print_hex_data_buffer(stream, cp, length, + edt->pi.fd->flags.encoding)) + return FALSE; } + return TRUE; } /* * This routine is based on a routine created by Dan Lasley * . * - * It was modified for Ethereal by Gilbert Ramirez and others. + * It was modified for Wireshark by Gilbert Ramirez and others. */ #define MAX_OFFSET_LEN 8 /* max length of hex offset of bytes */ @@ -564,9 +890,9 @@ void print_hex_data(FILE *fh, gint format, epan_dissect_t *edt) offset, 2 blanks separating offset from data dump, data dump */ -static void -print_hex_data_buffer(FILE *fh, register const guchar *cp, - register guint length, char_enc encoding, gint format) +static gboolean +print_hex_data_buffer(print_stream_t *stream, const guchar *cp, + guint length, packet_char_enc encoding) { register unsigned int ad, i, j, k, l; guchar c; @@ -576,7 +902,8 @@ print_hex_data_buffer(FILE *fh, register const guchar *cp, '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; - print_line(fh, 0, format, ""); + if (!print_line(stream, 0, "")) + return FALSE; /* * How many of the leading digits of the offset will we supply? @@ -604,7 +931,6 @@ print_hex_data_buffer(FILE *fh, register const guchar *cp, * Start of a new line. */ j = 0; - k = 0; l = use_digits; do { l--; @@ -624,7 +950,7 @@ print_hex_data_buffer(FILE *fh, register const guchar *cp, line[j++] = binhex[c>>4]; line[j++] = binhex[c&0xf]; j++; - if (encoding == CHAR_EBCDIC) { + if (encoding == PACKET_CHAR_ENC_CHAR_EBCDIC) { c = EBCDIC_to_ASCII1(c); } line[k++] = c >= ' ' && c < 0x7f ? c : '.'; @@ -637,10 +963,12 @@ print_hex_data_buffer(FILE *fh, register const guchar *cp, * and advance the offset. */ line[k] = '\0'; - print_line(fh, 0, format, line); + if (!print_line(stream, 0, line)) + return FALSE; ad += 16; } } + return TRUE; } static @@ -650,6 +978,11 @@ void ps_clean_string(unsigned char *out, const unsigned char *in, int rd, wr; char c; + if (in == NULL) { + out[0] = '\0'; + return; + } + for (rd = 0, wr = 0 ; wr < outbuf_size; rd++, wr++ ) { c = in[rd]; switch (c) { @@ -672,78 +1005,690 @@ void ps_clean_string(unsigned char *out, const unsigned char *in, } /* Some formats need stuff at the beginning of the output */ -void -print_preamble(FILE *fh, gint format) +gboolean +print_preamble(print_stream_t *self, gchar *filename) { - switch(format) { - case(PR_FMT_TEXT): - /* do nothing */ - break; - case(PR_FMT_PS): - print_ps_preamble(fh); - break; - case(PR_FMT_PDML): - fputs("\n", fh); - fputs("\n", PACKAGE, VERSION); - break; - default: - g_assert_not_reached(); - } + return (self->ops->print_preamble)(self, filename); +} + +gboolean +print_line(print_stream_t *self, int indent, const char *line) +{ + return (self->ops->print_line)(self, indent, line); +} + +/* Insert bookmark */ +gboolean +print_bookmark(print_stream_t *self, const gchar *name, const gchar *title) +{ + return (self->ops->print_bookmark)(self, name, title); +} + +gboolean +new_page(print_stream_t *self) +{ + return (self->ops->new_page)(self); } /* Some formats need stuff at the end of the output */ -void -print_finale(FILE *fh, gint format) +gboolean +print_finale(print_stream_t *self) { - switch(format) { - case(PR_FMT_TEXT): - /* do nothing */ - break; - case(PR_FMT_PS): - print_ps_finale(fh); - break; - case(PR_FMT_PDML): - fputs("\n", fh); - break; - default: - g_assert_not_reached(); + return (self->ops->print_finale)(self); +} + +gboolean +destroy_print_stream(print_stream_t *self) +{ + return (self->ops->destroy)(self); +} + +typedef struct { + int to_file; + FILE *fh; +} output_text; + +static gboolean +print_preamble_text(print_stream_t *self _U_, gchar *filename _U_) +{ + /* do nothing */ + return TRUE; /* always succeeds */ +} + +static gboolean +print_line_text(print_stream_t *self, int indent, const char *line) +{ + output_text *output = (output_text *)self->data; + char space[MAX_INDENT+1]; + int i; + int num_spaces; + + /* Prepare the tabs for printing, depending on tree level */ + num_spaces = indent * 4; + if (num_spaces > MAX_INDENT) { + num_spaces = MAX_INDENT; } + for (i = 0; i < num_spaces; i++) { + space[i] = ' '; + } + /* The string is NUL-terminated */ + space[num_spaces] = '\0'; + + fputs(space, output->fh); + fputs(line, output->fh); + putc('\n', output->fh); + return !ferror(output->fh); } -void -print_line(FILE *fh, int indent, gint format, char *line) +static gboolean +print_bookmark_text(print_stream_t *self _U_, const gchar *name _U_, + const gchar *title _U_) { - char space[MAX_INDENT+1]; - int i; - int num_spaces; - char psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */ - - switch(format) { - case(PR_FMT_TEXT): - /* Prepare the tabs for printing, depending on tree level */ - num_spaces = indent * 4; - if (num_spaces > MAX_INDENT) { - num_spaces = MAX_INDENT; - } - for (i = 0; i < num_spaces; i++) { - space[i] = ' '; - } - /* The string is NUL-terminated */ - space[num_spaces] = '\0'; - - fputs(space, fh); - fputs(line, fh); - putc('\n', fh); - break; - case(PR_FMT_PS): - ps_clean_string(psbuffer, line, MAX_PS_LINE_LENGTH); - fprintf(fh, "%d (%s) putline\n", indent, psbuffer); - break; - case(PR_FMT_PDML): - /* do nothing */ - break; - default: - g_assert_not_reached(); + /* do nothing */ + return TRUE; +} + +static gboolean +new_page_text(print_stream_t *self) +{ + output_text *output = (output_text *)self->data; + + fputs("\f", output->fh); + return !ferror(output->fh); +} + +static gboolean +print_finale_text(print_stream_t *self _U_) +{ + /* do nothing */ + return TRUE; /* always succeeds */ +} + +static gboolean +destroy_text(print_stream_t *self) +{ + output_text *output = (output_text *)self->data; + gboolean ret; + + ret = close_print_dest(output->to_file, output->fh); + g_free(output); + g_free(self); + return ret; +} + +static const print_stream_ops_t print_text_ops = { + print_preamble_text, + print_line_text, + print_bookmark_text, + new_page_text, + print_finale_text, + destroy_text +}; + +static print_stream_t * +print_stream_text_alloc(int to_file, FILE *fh) +{ + print_stream_t *stream; + output_text *output; + + output = (output_text *)g_malloc(sizeof *output); + output->to_file = to_file; + output->fh = fh; + stream = (print_stream_t *)g_malloc(sizeof (print_stream_t)); + stream->ops = &print_text_ops; + stream->data = output; + + return stream; +} + +print_stream_t * +print_stream_text_new(int to_file, const char *dest) +{ + FILE *fh; + + fh = open_print_dest(to_file, dest); + if (fh == NULL) + return NULL; + + return print_stream_text_alloc(to_file, fh); +} + +print_stream_t * +print_stream_text_stdio_new(FILE *fh) +{ + return print_stream_text_alloc(TRUE, fh); +} + +typedef struct { + int to_file; + FILE *fh; +} output_ps; + +static gboolean +print_preamble_ps(print_stream_t *self, gchar *filename) +{ + output_ps *output = (output_ps *)self->data; + unsigned char psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */ + + print_ps_preamble(output->fh); + + fputs("%% the page title\n", output->fh); + ps_clean_string(psbuffer, filename, MAX_PS_LINE_LENGTH); + fprintf(output->fh, "/ws_pagetitle (%s - Wireshark " VERSION "%s) def\n", psbuffer, wireshark_svnversion); + fputs("\n", output->fh); + return !ferror(output->fh); +} + +static gboolean +print_line_ps(print_stream_t *self, int indent, const char *line) +{ + output_ps *output = (output_ps *)self->data; + unsigned char psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */ + + ps_clean_string(psbuffer, line, MAX_PS_LINE_LENGTH); + fprintf(output->fh, "%d (%s) putline\n", indent, psbuffer); + return !ferror(output->fh); +} + +static gboolean +print_bookmark_ps(print_stream_t *self, const gchar *name, const gchar *title) +{ + output_ps *output = (output_ps *)self->data; + unsigned char psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */ + + /* + * See the Adobe "pdfmark reference": + * + * http://partners.adobe.com/asn/acrobat/docs/pdfmark.pdf + * + * The pdfmark stuff tells code that turns PostScript into PDF + * things that it should do. + * + * The /OUT stuff creates a bookmark that goes to the + * destination with "name" as the name and "title" as the title. + * + * The "/DEST" creates the destination. + */ + ps_clean_string(psbuffer, title, MAX_PS_LINE_LENGTH); + fprintf(output->fh, "[/Dest /%s /Title (%s) /OUT pdfmark\n", name, + psbuffer); + fputs("[/View [/XYZ -4 currentpoint matrix currentmatrix matrix defaultmatrix\n", + output->fh); + fputs("matrix invertmatrix matrix concatmatrix transform exch pop 20 add null]\n", + output->fh); + fprintf(output->fh, "/Dest /%s /DEST pdfmark\n", name); + return !ferror(output->fh); +} + +static gboolean +new_page_ps(print_stream_t *self) +{ + output_ps *output = (output_ps *)self->data; + + fputs("formfeed\n", output->fh); + return !ferror(output->fh); +} + +static gboolean +print_finale_ps(print_stream_t *self) +{ + output_ps *output = (output_ps *)self->data; + + print_ps_finale(output->fh); + return !ferror(output->fh); +} + +static gboolean +destroy_ps(print_stream_t *self) +{ + output_ps *output = (output_ps *)self->data; + gboolean ret; + + ret = close_print_dest(output->to_file, output->fh); + g_free(output); + g_free(self); + return ret; +} + +static const print_stream_ops_t print_ps_ops = { + print_preamble_ps, + print_line_ps, + print_bookmark_ps, + new_page_ps, + print_finale_ps, + destroy_ps +}; + +static print_stream_t * +print_stream_ps_alloc(int to_file, FILE *fh) +{ + print_stream_t *stream; + output_ps *output; + + output = (output_ps *)g_malloc(sizeof *output); + output->to_file = to_file; + output->fh = fh; + stream = (print_stream_t *)g_malloc(sizeof (print_stream_t)); + stream->ops = &print_ps_ops; + stream->data = output; + + return stream; +} + +print_stream_t * +print_stream_ps_new(int to_file, const char *dest) +{ + FILE *fh; + + fh = open_print_dest(to_file, dest); + if (fh == NULL) + return NULL; + + return print_stream_ps_alloc(to_file, fh); +} + +print_stream_t * +print_stream_ps_stdio_new(FILE *fh) +{ + return print_stream_ps_alloc(TRUE, fh); +} + +output_fields_t* output_fields_new(void) +{ + output_fields_t* fields = g_new(output_fields_t, 1); + fields->print_header = FALSE; + fields->separator = '\t'; + fields->occurrence = 'a'; + fields->aggregator = ','; + fields->fields = NULL; /*Do lazy initialisation */ + fields->field_indicies = NULL; + fields->field_values = NULL; + fields->quote='\0'; + return fields; +} + +gsize output_fields_num_fields(output_fields_t* fields) +{ + g_assert(fields); + + if(NULL == fields->fields) { + return 0; + } else { + return fields->fields->len; + } +} + +void output_fields_free(output_fields_t* fields) +{ + g_assert(fields); + + if(NULL != fields->field_indicies) { + /* Keys are stored in fields->fields, values are + * integers. + */ + g_hash_table_destroy(fields->field_indicies); + } + if(NULL != fields->fields) { + gsize i; + for(i = 0; i < fields->fields->len; ++i) { + gchar* field = (gchar *)g_ptr_array_index(fields->fields,i); + g_free(field); + } + g_ptr_array_free(fields->fields, TRUE); + } + + g_free(fields); +} + +void output_fields_add(output_fields_t* fields, const gchar* field) +{ + gchar* field_copy; + + g_assert(fields); + g_assert(field); + + + if(NULL == fields->fields) { + fields->fields = g_ptr_array_new(); + } + + field_copy = g_strdup(field); + + g_ptr_array_add(fields->fields, field_copy); +} + +gboolean output_fields_set_option(output_fields_t* info, gchar* option) +{ + const gchar* option_name; + const gchar* option_value; + + g_assert(info); + g_assert(option); + + if('\0' == *option) { + return FALSE; /* Is this guarded against by option parsing? */ + } + option_name = strtok(option,"="); + if (!option_name) { + return FALSE; + } + option_value = option + strlen(option_name) + 1; + if(0 == strcmp(option_name, "header")) { + switch(NULL == option_value ? '\0' : *option_value) { + case 'n': + info->print_header = FALSE; + break; + case 'y': + info->print_header = TRUE; + break; + default: + return FALSE; + } + return TRUE; + } + + if(0 == strcmp(option_name,"separator")) { + switch(NULL == option_value ? '\0' : *option_value) { + case '\0': + return FALSE; + case '/': + switch(*++option_value) { + case 't': + info->separator = '\t'; + break; + case 's': + info->separator = ' '; + break; + default: + info->separator = '\\'; + } + break; + default: + info->separator = *option_value; + break; + } + return TRUE; + } + + if(0 == strcmp(option_name, "occurrence")) { + switch(NULL == option_value ? '\0' : *option_value) { + case 'f': + case 'l': + case 'a': + info->occurrence = *option_value; + break; + default: + return FALSE; + } + return TRUE; + } + + if(0 == strcmp(option_name,"aggregator")) { + switch(NULL == option_value ? '\0' : *option_value) { + case '\0': + return FALSE; + case '/': + switch(*++option_value) { + case 's': + info->aggregator = ' '; + break; + default: + info->aggregator = '\\'; + } + break; + default: + info->aggregator = *option_value; + break; + } + return TRUE; + } + + if(0 == strcmp(option_name, "quote")) { + switch(NULL == option_value ? '\0' : *option_value) { + default: /* Fall through */ + case '\0': + info->quote='\0'; + return FALSE; + case 'd': + info->quote='"'; + break; + case 's': + info->quote='\''; + break; + case 'n': + info->quote='\0'; + break; + } + return TRUE; + } + + return FALSE; +} + +void output_fields_list_options(FILE *fh) +{ + fprintf(fh, "TShark: The available options for field output \"E\" are:\n"); + fputs("header=y|n Print field abbreviations as first line of output (def: N: no)\n", fh); + fputs("separator=/t|/s| Set the separator to use;\n \"/t\" = tab, \"/s\" = space (def: /t: tab)\n", fh); + 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); + fputs("aggregator=,|/s| Set the aggregator to use;\n \",\" = comma, \"/s\" = space (def: ,: comma)\n", fh); + 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); +} + + +void write_fields_preamble(output_fields_t* fields, FILE *fh) +{ + gsize i; + + g_assert(fields); + g_assert(fh); + + if(!fields->print_header) { + return; + } + + for(i = 0; i < fields->fields->len; ++i) { + const gchar* field = (const gchar *)g_ptr_array_index(fields->fields,i); + if(i != 0 ) { + fputc(fields->separator, fh); + } + fputs(field, fh); + } + fputc('\n', fh); +} + +static void proto_tree_get_node_field_values(proto_node *node, gpointer data) +{ + write_field_data_t *call_data; + field_info *fi; + gpointer field_index; + + call_data = (write_field_data_t *)data; + fi = PNODE_FINFO(node); + + g_assert(fi && "dissection with an invisible proto tree?"); + + field_index = g_hash_table_lookup(call_data->fields->field_indicies, fi->hfinfo->abbrev); + if(NULL != field_index) { + const gchar* value; + + value = get_node_field_value(fi, call_data->edt); /* ep_alloced string */ + + if(NULL != value && '\0' != *value) { + guint actual_index; + actual_index = GPOINTER_TO_UINT(field_index); + /* Unwrap change made to disambiguiate zero / null */ + if ( call_data->fields->field_values[actual_index - 1] == NULL ) { + call_data->fields->field_values[actual_index - 1] = ep_strbuf_new(value); + } else if ( call_data->fields->occurrence == 'l' ) { + /* print only the value of the last occurrence of the field */ + ep_strbuf_printf(call_data->fields->field_values[actual_index - 1],"%s",value); + } else if ( call_data->fields->occurrence == 'a' ) { + /* print the value of all accurrences of the field */ + ep_strbuf_append_printf(call_data->fields->field_values[actual_index - 1], + "%c%s",call_data->fields->aggregator,value); + } + } + } + + /* Recurse here. */ + if (node->first_child != NULL) { + proto_tree_children_foreach(node, proto_tree_get_node_field_values, + call_data); + } +} + +void proto_tree_write_fields(output_fields_t* fields, epan_dissect_t *edt, FILE *fh) +{ + gsize i; + + write_field_data_t data; + + g_assert(fields); + g_assert(edt); + g_assert(fh); + + data.fields = fields; + data.edt = edt; + + if(NULL == fields->field_indicies) { + /* Prepare a lookup table from string abbreviation for field to its index. */ + fields->field_indicies = g_hash_table_new(g_str_hash, g_str_equal); + + i = 0; + while( i < fields->fields->len) { + gchar* field = (gchar *)g_ptr_array_index(fields->fields, i); + /* Store field indicies +1 so that zero is not a valid value, + * and can be distinguished from NULL as a pointer. + */ + ++i; + g_hash_table_insert(fields->field_indicies, field, GUINT_TO_POINTER(i)); + } + } + + /* Buffer to store values for this packet */ + fields->field_values = ep_alloc_array0(emem_strbuf_t*, fields->fields->len); + + proto_tree_children_foreach(edt->tree, proto_tree_get_node_field_values, + &data); + + for(i = 0; i < fields->fields->len; ++i) { + if(0 != i) { + fputc(fields->separator, fh); + } + if(NULL != fields->field_values[i]) { + if(fields->quote != '\0') { + fputc(fields->quote, fh); + } + fputs(fields->field_values[i]->str, fh); + if(fields->quote != '\0') { + fputc(fields->quote, fh); + } + } + } +} + +void write_fields_finale(output_fields_t* fields _U_ , FILE *fh _U_) +{ + /* Nothing to do */ +} + +/* Returns an ep_alloced string or a static constant*/ +const gchar* get_node_field_value(field_info* fi, epan_dissect_t* edt) +{ + if (fi->hfinfo->id == hf_text_only) { + /* Text label. + * Get the text */ + if (fi->rep) { + return fi->rep->representation; + } + else { + return get_field_hex_value(edt->pi.data_src, fi); + } + } + else if (fi->hfinfo->id == proto_data) { + /* Uninterpreted data, i.e., the "Data" protocol, is + * printed as a field instead of a protocol. */ + return get_field_hex_value(edt->pi.data_src, fi); + } + else { + /* Normal protocols and fields */ + gchar *dfilter_string; + size_t chop_len; + + switch (fi->hfinfo->type) + { + case FT_PROTOCOL: + /* Print out the full details for the protocol. */ + if (fi->rep) { + return fi->rep->representation; + } else { + /* Just print out the protocol abbreviation */ + return fi->hfinfo->abbrev;; + } + case FT_NONE: + /* Return "1" so that the presence of a field of type + * FT_NONE can be checked when using -T fields */ + return "1"; + default: + /* XXX - this is a hack until we can just call + * fvalue_to_string_repr() for *all* FT_* types. */ + dfilter_string = proto_construct_match_selected_string(fi, + edt); + if (dfilter_string != NULL) { + chop_len = strlen(fi->hfinfo->abbrev) + 4; /* for " == " */ + + /* XXX - Remove double-quotes. Again, once we + * can call fvalue_to_string_repr(), we can + * ask it not to produce the version for + * display-filters, and thus, no + * double-quotes. */ + if (dfilter_string[strlen(dfilter_string)-1] == '"') { + dfilter_string[strlen(dfilter_string)-1] = '\0'; + chop_len++; + } + + return &(dfilter_string[chop_len]); + } else { + return get_field_hex_value(edt->pi.data_src, fi); + } + } + } +} + +static const gchar* +get_field_hex_value(GSList* src_list, field_info *fi) +{ + const guint8 *pd; + + if (!fi->ds_tvb) + return NULL; + + if (fi->length > tvb_length_remaining(fi->ds_tvb, fi->start)) { + return "field length invalid!"; + } + + /* Find the data for this field. */ + pd = get_field_data(src_list, fi); + + if (pd) { + int i; + gchar* buffer; + gchar* p; + int len; + const int chars_per_byte = 2; + + len = chars_per_byte * fi->length; + buffer = ep_alloc_array(gchar, len + 1); + buffer[len] = '\0'; /* Ensure NULL termination in bad cases */ + p = buffer; + /* Print a simple hex dump */ + for (i = 0 ; i < fi->length; i++) { + g_snprintf(p, chars_per_byte+1, "%02x", pd[i]); + p += chars_per_byte; + } + return buffer; + } else { + return NULL; } }