X-Git-Url: http://git.samba.org/samba.git/?p=obnox%2Fwireshark%2Fwip.git;a=blobdiff_plain;f=print.c;h=b0a897fa036fcd8a644d41bc85ffc568d826635e;hp=e36b09e4ba614151252c325999a5d6f928bc4ea4;hb=1178fc300507386adaebbb7a25aaae4356d32c31;hpb=377d786c164c68d16736c96d1e50db9c00859360 diff --git a/print.c b/print.c index e36b09e4ba..b0a897fa03 100644 --- a/print.c +++ b/print.c @@ -5,8 +5,8 @@ * * 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 @@ -24,10 +24,6 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* With MSVC and a libethereal.dll this file needs to import some variables - in a special way. Therefore _NEED_VAR_IMPORT_ is defined. */ -#define _NEED_VAR_IMPORT_ - #ifdef HAVE_CONFIG_H # include "config.h" #endif @@ -39,11 +35,14 @@ #include #include #include -#include +#include +#include "packet-range.h" #include "print.h" #include "ps.h" -#include "util.h" +#include "version_info.h" +#include +#include #include #include @@ -57,7 +56,7 @@ typedef struct { GSList *src_list; print_dissections_e print_dissections; gboolean print_hex_for_data; - char_enc encoding; + packet_char_enc encoding; epan_dissect_t *edt; } print_data; @@ -68,18 +67,35 @@ typedef struct { 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; + GPtrArray* fields; + GHashTable* field_indicies; + const gchar** field_values; + gchar quote; +}; + +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_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, char_enc encoding); + 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, char *unescaped_string); +static void print_escaped_xml(FILE *fh, const char *unescaped_string); static void print_pdml_geninfo(proto_tree *tree, FILE *fh); +static void proto_tree_get_node_field_values(proto_node *node, gpointer data); + static FILE * open_print_dest(int to_file, const char *dest) { @@ -87,7 +103,7 @@ open_print_dest(int to_file, const char *dest) /* Open the file or command for output */ if (to_file) - fh = fopen(dest, "w"); + fh = ws_fopen(dest, "w"); else fh = popen(dest, "w"); @@ -134,12 +150,14 @@ proto_tree_print(print_args_t *print_args, epan_dissect_t *edt, 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 (PROTO_ITEM_IS_HIDDEN(node)) return; @@ -157,11 +175,19 @@ void proto_tree_print_node(proto_node *node, gpointer data) proto_item_fill_label(fi, label_str); } + 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 (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). */ if (fi->hfinfo->id == proto_data && pdata->print_hex_for_data) { @@ -215,6 +241,10 @@ proto_tree_write_pdml(epan_dissect_t *edt, FILE *fh) data.src_list = edt->pi.data_src; data.edt = edt; + /* We shouldn't be called with a NULL pointer here because we've + * created a visible protocol tree */ + g_assert(data.src_list); + fprintf(fh, "\n"); /* Print a "geninfo" protocol as required by PDML */ @@ -230,18 +260,40 @@ proto_tree_write_pdml(epan_dissect_t *edt, FILE *fh) static void proto_tree_write_node_pdml(proto_node *node, gpointer data) { - field_info *fi = PITEM_FINFO(node); + field_info *fi = PNODE_FINFO(node); write_pdml_data *pdata = (write_pdml_data*) data; - gchar *label_ptr; + 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 */ @@ -252,7 +304,9 @@ proto_tree_write_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); @@ -268,16 +322,15 @@ proto_tree_write_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); - write_pdml_field_hex_value(pdata, fi); - fputs("\"/>\n", pdata->fh); - } /* Normal protocols and fields */ else { @@ -290,8 +343,8 @@ proto_tree_write_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 + /* 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 @@ -299,9 +352,9 @@ proto_tree_write_node_pdml(proto_node *node, gpointer data) * 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 + * 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); @@ -325,13 +378,19 @@ proto_tree_write_node_pdml(proto_node *node, gpointer data) 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 " == " */ @@ -348,9 +407,25 @@ proto_tree_write_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); - write_pdml_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); + } } } @@ -373,21 +448,35 @@ proto_tree_write_node_pdml(proto_node *node, gpointer data) 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 @@ -403,40 +492,40 @@ print_pdml_geninfo(proto_tree *tree, FILE *fh) 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(fh, @@ -450,7 +539,7 @@ print_pdml_geninfo(proto_tree *tree, FILE *fh) /* Print geninfo.len */ fprintf(fh, -" \n", +" \n", len, len, frame_finfo->length); /* Print geninfo.caplen */ @@ -461,7 +550,7 @@ print_pdml_geninfo(proto_tree *tree, FILE *fh) /* Print geninfo.timestamp */ 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(fh, @@ -486,9 +575,10 @@ void proto_tree_write_psml(epan_dissect_t *edt, FILE *fh) { gint i; + static gboolean structure_written = FALSE; /* if this is the first packet, we have to create the PSML structure output */ - if(edt->pi.fd->num == 1) { + if(!structure_written) { fprintf(fh, "\n"); for(i=0; i < edt->pi.cinfo->num_cols; i++) { @@ -498,6 +588,8 @@ proto_tree_write_psml(epan_dissect_t *edt, FILE *fh) } fprintf(fh, "\n\n"); + + structure_written = TRUE; } fprintf(fh, "\n"); @@ -517,6 +609,76 @@ write_psml_finale(FILE *fh) fputs("\n", fh); } +void +write_csv_preamble(FILE *fh _U_) +{ + +} + +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(edt->pi.fd->num == 1) { + for(i=0; i < edt->pi.cinfo->num_cols - 1; i++) + fprintf(fh, "\"%s\",", edt->pi.cinfo->col_title[i]); + + fprintf(fh, "\"%s\"\n", edt->pi.cinfo->col_title[i]); + } + + for(i=0; i < edt->pi.cinfo->num_cols - 1; i++) + fprintf(fh, "\"%s\",", edt->pi.cinfo->col_data[i]); + + fprintf(fh, "\"%s\"\n", edt->pi.cinfo->col_data[i]); +} + +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. @@ -530,7 +692,7 @@ get_field_data(GSList *src_list, field_info *fi) gint length, tvbuff_length; for (src_le = src_list; src_le != NULL; src_le = src_le->next) { - src = src_le->data; + src = (data_source *)src_le->data; src_tvb = src->tvb; if (fi->ds_tvb == src_tvb) { /* @@ -561,9 +723,10 @@ get_field_data(GSList *src_list, field_info *fi) /* Print a string, escaping out certain characters that need to * escaped out for XML. */ static void -print_escaped_xml(FILE *fh, char *unescaped_string) +print_escaped_xml(FILE *fh, const char *unescaped_string) { - unsigned char *p; + const char *p; + char temp_str[8]; for (p = unescaped_string; *p != '\0'; p++) { switch (*p) { @@ -583,7 +746,12 @@ print_escaped_xml(FILE *fh, char *unescaped_string) fputs("'", fh); break; default: - fputc(*p, fh); + if (g_ascii_isprint(*p)) + fputc(*p, fh); + else { + g_snprintf(temp_str, sizeof(temp_str), "\\x%x", (guint8)*p); + fputs(temp_str, fh); + } } } } @@ -594,6 +762,9 @@ 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; @@ -617,11 +788,15 @@ print_hex_data(print_stream_t *stream, epan_dissect_t *edt) GSList *src_le; data_source *src; tvbuff_t *tvb; - char *name; + const char *name; char *line; const guchar *cp; guint length; + /* We shouldn't be called with a NULL pointer here because we've + * created a visible protocol tree */ + g_assert(edt->pi.data_src); + /* * Set "multiple_sources" iff this frame has more than one * data source; if it does, we need to print the name of @@ -632,18 +807,18 @@ print_hex_data(print_stream_t *stream, 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; + name = get_data_source_name(src); print_line(stream, 0, ""); - line = g_malloc(strlen(name) + 2); /* :\0 */ - strcpy(line, name); - strcat(line, ":"); + 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); if (!print_hex_data_buffer(stream, cp, length, edt->pi.fd->flags.encoding)) @@ -656,7 +831,7 @@ print_hex_data(print_stream_t *stream, epan_dissect_t *edt) * 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 */ @@ -676,7 +851,7 @@ print_hex_data(print_stream_t *stream, epan_dissect_t *edt) static gboolean print_hex_data_buffer(print_stream_t *stream, const guchar *cp, - guint length, char_enc encoding) + guint length, packet_char_enc encoding) { register unsigned int ad, i, j, k, l; guchar c; @@ -715,7 +890,6 @@ print_hex_data_buffer(print_stream_t *stream, const guchar *cp, * Start of a new line. */ j = 0; - k = 0; l = use_digits; do { l--; @@ -735,7 +909,7 @@ print_hex_data_buffer(print_stream_t *stream, 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 : '.'; @@ -838,7 +1012,7 @@ print_preamble_text(print_stream_t *self _U_, gchar *filename _U_) static gboolean print_line_text(print_stream_t *self, int indent, const char *line) { - output_text *output = self->data; + output_text *output = (output_text *)self->data; char space[MAX_INDENT+1]; int i; int num_spaces; @@ -871,7 +1045,7 @@ print_bookmark_text(print_stream_t *self _U_, const gchar *name _U_, static gboolean new_page_text(print_stream_t *self) { - output_text *output = self->data; + output_text *output = (output_text *)self->data; fputs("\f", output->fh); return !ferror(output->fh); @@ -887,7 +1061,7 @@ print_finale_text(print_stream_t *self _U_) static gboolean destroy_text(print_stream_t *self) { - output_text *output = self->data; + output_text *output = (output_text *)self->data; gboolean ret; ret = close_print_dest(output->to_file, output->fh); @@ -905,21 +1079,16 @@ static const print_stream_ops_t print_text_ops = { destroy_text }; -print_stream_t * -print_stream_text_new(int to_file, const char *dest) +static print_stream_t * +print_stream_text_alloc(int to_file, FILE *fh) { - FILE *fh; print_stream_t *stream; output_text *output; - fh = open_print_dest(to_file, dest); - if (fh == NULL) - return NULL; - - output = g_malloc(sizeof *output); + output = (output_text *)g_malloc(sizeof *output); output->to_file = to_file; output->fh = fh; - stream = g_malloc(sizeof (print_stream_t)); + stream = (print_stream_t *)g_malloc(sizeof (print_stream_t)); stream->ops = &print_text_ops; stream->data = output; @@ -927,19 +1096,21 @@ print_stream_text_new(int to_file, const char *dest) } print_stream_t * -print_stream_text_stdio_new(FILE *fh) +print_stream_text_new(int to_file, const char *dest) { - print_stream_t *stream; - output_text *output; + FILE *fh; - output = g_malloc(sizeof *output); - output->to_file = TRUE; - output->fh = fh; - stream = g_malloc(sizeof (print_stream_t)); - stream->ops = &print_text_ops; - stream->data = output; + fh = open_print_dest(to_file, dest); + if (fh == NULL) + return NULL; - return stream; + 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 { @@ -950,17 +1121,17 @@ typedef struct { static gboolean print_preamble_ps(print_stream_t *self, gchar *filename) { - output_ps *output = self->data; - char psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */ + output_ps *output = (output_ps *)self->data; + unsigned char psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */ print_ps_preamble(output->fh); - fputs("%% Set the font to 10 point\n", output->fh); - fputs("/Courier findfont 10 scalefont setfont\n", output->fh); + fputs("%% Set the font to 8 point\n", output->fh); + fputs("/Courier findfont 8 scalefont setfont\n", output->fh); fputs("\n", output->fh); fputs("%% the page title\n", output->fh); ps_clean_string(psbuffer, filename, MAX_PS_LINE_LENGTH); - fprintf(output->fh, "/eth_pagetitle (%s - Ethereal) def\n", psbuffer); + fprintf(output->fh, "/ws_pagetitle (%s - Wireshark " VERSION "%s) def\n", psbuffer, wireshark_svnversion); fputs("\n", output->fh); return !ferror(output->fh); } @@ -968,8 +1139,8 @@ print_preamble_ps(print_stream_t *self, gchar *filename) static gboolean print_line_ps(print_stream_t *self, int indent, const char *line) { - output_ps *output = self->data; - char psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */ + 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); @@ -979,8 +1150,8 @@ print_line_ps(print_stream_t *self, int indent, const char *line) static gboolean print_bookmark_ps(print_stream_t *self, const gchar *name, const gchar *title) { - output_ps *output = self->data; - char psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */ + output_ps *output = (output_ps *)self->data; + unsigned char psbuffer[MAX_PS_LINE_LENGTH]; /* static sized buffer! */ /* * See the Adobe "pdfmark reference": @@ -1009,7 +1180,7 @@ print_bookmark_ps(print_stream_t *self, const gchar *name, const gchar *title) static gboolean new_page_ps(print_stream_t *self) { - output_ps *output = self->data; + output_ps *output = (output_ps *)self->data; fputs("formfeed\n", output->fh); return !ferror(output->fh); @@ -1018,7 +1189,7 @@ new_page_ps(print_stream_t *self) static gboolean print_finale_ps(print_stream_t *self) { - output_ps *output = self->data; + output_ps *output = (output_ps *)self->data; print_ps_finale(output->fh); return !ferror(output->fh); @@ -1027,7 +1198,7 @@ print_finale_ps(print_stream_t *self) static gboolean destroy_ps(print_stream_t *self) { - output_ps *output = self->data; + output_ps *output = (output_ps *)self->data; gboolean ret; ret = close_print_dest(output->to_file, output->fh); @@ -1045,39 +1216,387 @@ static const print_stream_ops_t print_ps_ops = { destroy_ps }; -print_stream_t * -print_stream_ps_new(int to_file, const char *dest) +static print_stream_t * +print_stream_ps_alloc(int to_file, FILE *fh) { - FILE *fh; print_stream_t *stream; output_ps *output; - fh = open_print_dest(to_file, dest); - if (fh == NULL) - return NULL; - - output = g_malloc(sizeof *output); + output = (output_ps *)g_malloc(sizeof *output); output->to_file = to_file; output->fh = fh; - stream = g_malloc(sizeof (print_stream_t)); + 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) { - print_stream_t *stream; - output_ps *output; + return print_stream_ps_alloc(TRUE, fh); +} - output = g_malloc(sizeof *output); - output->to_file = TRUE; - output->fh = fh; - stream = g_malloc(sizeof (print_stream_t)); - stream->ops = &print_ps_ops; - stream->data = output; +output_fields_t* output_fields_new() +{ + output_fields_t* fields = g_new(output_fields_t, 1); + fields->print_header = FALSE; + fields->separator = '\t'; + fields->fields = NULL; /*Do lazy initialisation */ + fields->field_indicies = NULL; + fields->field_values = NULL; + fields->quote='\0'; + return fields; +} - return stream; +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,"="); + 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, "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; \"/t\" = tab,\n \"/s\" = space (def: /t: tab)\n", fh); + fputs("quote=d|s|n Print either d: double-quotes, s: single quotes or n: no quotes around field values (def: n: none)\n", fh); +} + + +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 */ + call_data->fields->field_values[actual_index - 1] = 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(const gchar*, 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], 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; + } }