From 5800abad4620cbd3885b2460ee0383ced0cf6e3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stig=20Bj=C3=B8rlykke?= Date: Tue, 11 Mar 2008 18:23:16 +0000 Subject: [PATCH] From Francesco Fondelli (bug 2349): Attached is a patch to export packets data as "C Arrays". I often have the need to [re]send data captured with wireshark using a raw/pf_packet socket. Output format is one char[] per packet, it looks like almost the same as the one produced by "Follow TCP stream". svn path=/trunk/; revision=24604 --- AUTHORS | 1 + file.c | 59 ++++++++++++++++++++++++++++++++++++ file.h | 9 ++++++ gtk/main.h | 7 +++++ gtk/menu.c | 2 ++ gtk/print_dlg.c | 71 ++++++++++++++++++++++++++++++++++++++++++-- gtk/win32-file-dlg.c | 5 +++- gtk/win32-file-dlg.h | 3 +- print.c | 39 ++++++++++++++++++++++++ print.h | 4 +++ 10 files changed, 196 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index 4319ec8826..e4db07988b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -2293,6 +2293,7 @@ Francesco Fondelli { RSVP/OSPF Extensions for Support of Diffserv-aware MPLS-TE, RFC 4124 Linux Packet Generator support rval_to_str() and alike + Export the capture file into C Arrays format } Bill Meier { diff --git a/file.c b/file.c index fa71a63f41..cffbc033ce 100644 --- a/file.c +++ b/file.c @@ -2399,6 +2399,65 @@ cf_write_csv_packets(capture_file *cf, print_args_t *print_args) return CF_PRINT_OK; } +static gboolean +write_carrays_packet(capture_file *cf _U_, frame_data *fdata, + union wtap_pseudo_header *pseudo_header _U_, + const guint8 *pd, void *argsp) +{ + FILE *fh = argsp; + + proto_tree_write_carrays(pd, fdata->cap_len, fdata->num, fh); + return !ferror(fh); +} + +cf_print_status_t +cf_write_carrays_packets(capture_file *cf, print_args_t *print_args) +{ + FILE *fh; + psp_return_t ret; + + fh = eth_fopen(print_args->file, "w"); + + if (fh == NULL) + return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */ + + write_carrays_preamble(fh); + + if (ferror(fh)) { + fclose(fh); + return CF_PRINT_WRITE_ERROR; + } + + /* Iterate through the list of packets, printing the packets we were + told to print. */ + ret = process_specified_packets(cf, &print_args->range, + "Writing C Arrays", + "selected packets", TRUE, + write_carrays_packet, fh); + switch (ret) { + case PSP_FINISHED: + /* Completed successfully. */ + break; + case PSP_STOPPED: + /* Well, the user decided to abort the printing. */ + break; + case PSP_FAILED: + /* Error while printing. */ + fclose(fh); + return CF_PRINT_WRITE_ERROR; + } + + write_carrays_finale(fh); + + if (ferror(fh)) { + fclose(fh); + return CF_PRINT_WRITE_ERROR; + } + + fclose(fh); + return CF_PRINT_OK; +} + /* Scan through the packet list and change all columns that use the "command-line-specified" time stamp format to use the current value of that format. */ diff --git a/file.h b/file.h index 03bb8a7fd7..89e5b89ce4 100644 --- a/file.h +++ b/file.h @@ -335,6 +335,15 @@ cf_print_status_t cf_write_psml_packets(capture_file *cf, print_args_t *print_ar */ cf_print_status_t cf_write_csv_packets(capture_file *cf, print_args_t *print_args); +/** + * Print (export) the capture file into C Arrays format. + * + * @param cf the capture file + * @param print_args the arguments what and how to export + * @return one of cf_print_status_t + */ +cf_print_status_t cf_write_carrays_packets(capture_file *cf, print_args_t *print_args); + /** * Find Packet in protocol tree. * diff --git a/gtk/main.h b/gtk/main.h index dfb8b4568c..e2268bef27 100644 --- a/gtk/main.h +++ b/gtk/main.h @@ -221,6 +221,13 @@ extern void export_pdml_cmd_cb(GtkWidget *widget, gpointer data); */ extern void export_csv_cmd_cb(GtkWidget *widget, gpointer data); +/** User requested "Export as C Arrays" by menu. + * + * @param widget parent widget (unused) + * @param data unused + */ +extern void export_carrays_cmd_cb(GtkWidget *widget, gpointer data); + /** User requested "Expand Tree" by menu. * * @param widget parent widget (unused) diff --git a/gtk/menu.c b/gtk/menu.c index 88d1041960..df4c576835 100644 --- a/gtk/menu.c +++ b/gtk/menu.c @@ -468,6 +468,8 @@ static GtkItemFactoryEntry menu_items[] = 0, NULL, NULL), ITEM_FACTORY_ENTRY("/File/Export/as \"_CSV\" (Comma Separated Values packet summary) file...", NULL, export_csv_cmd_cb, 0, NULL, NULL), + ITEM_FACTORY_ENTRY("/File/Export/as \"C _Arrays\" (packet bytes) file...", NULL, export_carrays_cmd_cb, + 0, NULL, NULL), ITEM_FACTORY_ENTRY("/File/Export/", NULL, NULL, 0, "", NULL), ITEM_FACTORY_ENTRY("/File/Export/as XML - \"P_SML\" (packet summary) file...", NULL, export_psml_cmd_cb, 0, NULL, NULL), diff --git a/gtk/print_dlg.c b/gtk/print_dlg.c index 11bf7ae08d..6c988b39b8 100644 --- a/gtk/print_dlg.c +++ b/gtk/print_dlg.c @@ -67,7 +67,8 @@ typedef enum { output_action_export_ps, /* export to postscript */ output_action_export_psml, /* export to packet summary markup language */ output_action_export_pdml, /* export to packet data markup language */ - output_action_export_csv /* export to csv file */ + output_action_export_csv, /* export to csv file */ + output_action_export_carrays /* export to C array file */ } output_action_e; @@ -95,6 +96,7 @@ static void print_destroy_cb(GtkWidget *win, gpointer user_data); #define PRINT_PDML_RB_KEY "printer_pdml_radio_button" #define PRINT_PSML_RB_KEY "printer_psml_radio_button" #define PRINT_CSV_RB_KEY "printer_csv_radio_button" +#define PRINT_CARRAYS_RB_KEY "printer_carrays_radio_button" #define PRINT_DEST_CB_KEY "printer_destination_check_button" #define PRINT_SUMMARY_CB_KEY "printer_summary_check_button" @@ -411,6 +413,54 @@ export_csv_cmd_cb(GtkWidget *widget _U_, gpointer data _U_) SIGNAL_CONNECT(export_csv_win, "destroy", print_destroy_cb, &export_csv_win); } +/* + * Keep a static pointer to the current "Export carrays" window, if any, so that if + * somebody tries to do "File:Export to carrays" while there's already a "Export carrays" window + * up, we just pop up the existing one, rather than creating a new one. + */ +static GtkWidget *export_carrays_win = NULL; + +static print_args_t export_carrays_args; + +static gboolean export_carrays_prefs_init = FALSE; + +void +export_carrays_cmd_cb(GtkWidget *widget _U_, gpointer data _U_) +{ + print_args_t *args = &export_carrays_args; + +#if GTK_MAJOR_VERSION >= 2 && _WIN32 + win32_export_file(GDK_WINDOW_HWND(top_level->window), export_type_carrays); + return; +#endif + + if (export_carrays_win != NULL) { + /* There's already a "Export carrays" dialog box; reactivate it. */ + reactivate_window(export_carrays_win); + return; + } + + /* get settings from preferences (and other initial values) only once */ + if(export_carrays_prefs_init == FALSE) { + export_carrays_prefs_init = TRUE; + args->format = PR_FMT_TEXT; + args->to_file = TRUE; + args->file = g_strdup(""); + args->cmd = g_strdup(""); + args->print_summary = FALSE; + args->print_dissections = print_dissections_none; + args->print_hex = FALSE; + args->print_formfeed = FALSE; + } + + /* init the printing range */ + packet_range_init(&args->range); + + export_carrays_win = open_print_dialog("Wireshark: Export as \"C Arrays\" File", + output_action_export_carrays, args); + SIGNAL_CONNECT(export_carrays_win, "destroy", print_destroy_cb, &export_carrays_win); +} + static void print_browse_file_cb(GtkWidget *file_bt, GtkWidget *file_te) { @@ -432,7 +482,7 @@ open_print_dialog(const char *title, output_action_e action, print_args_t *args) GtkWidget *main_vb; GtkWidget *printer_fr, *printer_vb, *export_format_lb; - GtkWidget *text_rb, *ps_rb, *pdml_rb, *psml_rb, *csv_rb; + GtkWidget *text_rb, *ps_rb, *pdml_rb, *psml_rb, *csv_rb, *carrays_rb; GtkWidget *printer_tb, *dest_cb; #ifndef _WIN32 GtkWidget *cmd_lb, *cmd_te; @@ -535,6 +585,16 @@ open_print_dialog(const char *title, output_action_e action, print_args_t *args) gtk_box_pack_start(GTK_BOX(printer_vb), csv_rb, FALSE, FALSE, 0); /* gtk_widget_show(csv_rb); */ + carrays_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(text_rb, "C Arrays", accel_group); + if (action == output_action_export_carrays) + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(carrays_rb), TRUE); + gtk_tooltips_set_tip (tooltips, carrays_rb, + "Print output in C Arrays format, " + "a text file suitable for use in C/C++ programs. " + "One char[] for each packet.", NULL); + gtk_box_pack_start(GTK_BOX(printer_vb), carrays_rb, FALSE, FALSE, 0); + /* gtk_widget_show(carrays_rb); */ + /* printer table */ #ifndef _WIN32 printer_tb = gtk_table_new(2, 3, FALSE); @@ -741,6 +801,7 @@ open_print_dialog(const char *title, output_action_e action, print_args_t *args) OBJECT_SET_DATA(ok_bt, PRINT_PDML_RB_KEY, pdml_rb); OBJECT_SET_DATA(ok_bt, PRINT_PSML_RB_KEY, psml_rb); OBJECT_SET_DATA(ok_bt, PRINT_CSV_RB_KEY, csv_rb); + OBJECT_SET_DATA(ok_bt, PRINT_CARRAYS_RB_KEY, carrays_rb); OBJECT_SET_DATA(ok_bt, PRINT_DEST_CB_KEY, dest_cb); #ifndef _WIN32 OBJECT_SET_DATA(ok_bt, PRINT_CMD_TE_KEY, cmd_te); @@ -869,6 +930,7 @@ print_ok_cb(GtkWidget *ok_bt, gpointer parent_w) gchar *dirname; gboolean export_as_pdml = FALSE, export_as_psml = FALSE; gboolean export_as_csv = FALSE; + gboolean export_as_carrays = FALSE; #ifdef _WIN32 gboolean win_printer = FALSE; int tmp_fd; @@ -946,6 +1008,9 @@ print_ok_cb(GtkWidget *ok_bt, gpointer parent_w) button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_CSV_RB_KEY); if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button))) export_as_csv = TRUE; + button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_CARRAYS_RB_KEY); + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button))) + export_as_carrays = TRUE; button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_SUMMARY_CB_KEY); args->print_summary = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button)); @@ -985,6 +1050,8 @@ print_ok_cb(GtkWidget *ok_bt, gpointer parent_w) status = cf_write_psml_packets(&cfile, args); else if (export_as_csv) status = cf_write_csv_packets(&cfile, args); + else if (export_as_carrays) + status = cf_write_carrays_packets(&cfile, args); else { switch (args->format) { diff --git a/gtk/win32-file-dlg.c b/gtk/win32-file-dlg.c index 950c851a85..0aa819a0f6 100644 --- a/gtk/win32-file-dlg.c +++ b/gtk/win32-file-dlg.c @@ -505,9 +505,12 @@ win32_export_file(HWND h_wnd, export_type_e export_type) { } status = cf_print_packets(&cfile, &print_args); break; - case export_type_csv: /* CSV */ + case export_type_csv: /* CSV */ status = cf_write_csv_packets(&cfile, &print_args); break; + case export_type_carrays: /* C Arrays */ + status = cf_write_carrays_packets(&cfile, &print_args); + break; case export_type_psml: /* PSML */ status = cf_write_psml_packets(&cfile, &print_args); break; diff --git a/gtk/win32-file-dlg.h b/gtk/win32-file-dlg.h index edce057cab..15f9260d91 100644 --- a/gtk/win32-file-dlg.h +++ b/gtk/win32-file-dlg.h @@ -30,7 +30,8 @@ typedef enum { export_type_ps, export_type_csv, export_type_psml, - export_type_pdml + export_type_pdml, + export_type_carrays } export_type_e; /** Open the "Open" dialog box. diff --git a/print.c b/print.c index a4fca368de..4a24b8023f 100644 --- a/print.c +++ b/print.c @@ -628,6 +628,45 @@ 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. diff --git a/print.h b/print.h index 1187651ff0..cf81d7d79e 100644 --- a/print.h +++ b/print.h @@ -137,6 +137,10 @@ extern void write_csv_preamble(FILE *fh); extern void proto_tree_write_csv(epan_dissect_t *edt, FILE *fh); extern void write_csv_finale(FILE *fh); +extern void write_carrays_preamble(FILE *fh); +extern void proto_tree_write_carrays(const guint8 *pd, guint32 len, guint32 num, FILE *fh); +extern void write_carrays_finale(FILE *fh); + extern void write_fields_preamble(output_fields_t* fields, FILE *fh); extern void proto_tree_write_fields(output_fields_t* fields, epan_dissect_t *edt, FILE *fh); extern void write_fields_finale(output_fields_t* fields, FILE *fh);