Replace "n/a" with an em dash.
[metze/wireshark/wip.git] / ui / qt / mtp3_summary_dialog.cpp
1 /* mtp3_summary_dialog.cpp
2  *
3  * Wireshark - Network traffic analyzer
4  * By Gerald Combs <gerald@wireshark.org>
5  * Copyright 1998 Gerald Combs
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25
26 #include "mtp3_summary_dialog.h"
27 #include <ui_mtp3_summary_dialog.h>
28
29 #include "config.h"
30
31 #include <glib.h>
32
33 #include "globals.h"
34 #include "summary.h"
35
36 #include <epan/tap.h>
37
38 #include <epan/dissectors/packet-mtp3.h>
39
40 #include "wsutil/utf8_entities.h"
41
42 #include "ui/capture_globals.h"
43 #include "ui/simple_dialog.h"
44
45 #include "qt_ui_utils.h"
46
47 #include <QTextStream>
48
49 typedef struct _mtp3_stat_si_code_t {
50     int                 num_msus;
51     int                 size;
52 } mtp3_stat_si_code_t;
53
54 typedef struct _mtp3_stat_t {
55     mtp3_addr_pc_t              addr_opc;
56     mtp3_addr_pc_t              addr_dpc;
57     mtp3_stat_si_code_t         mtp3_si_code[MTP3_NUM_SI_CODE];
58 } mtp3_stat_t;
59
60 #define MTP3_MAX_NUM_OPC_DPC    50
61
62 static mtp3_stat_t mtp3_stat[MTP3_MAX_NUM_OPC_DPC];
63 static size_t mtp3_num_used;
64
65 Mtp3SummaryDialog::Mtp3SummaryDialog(QWidget &parent, CaptureFile &capture_file) :
66     WiresharkDialog(parent, capture_file),
67     ui(new Ui::Mtp3SummaryDialog)
68 {
69     ui->setupUi(this);
70
71     setWindowSubtitle(tr("MTP3 Summary"));
72     updateWidgets();
73 }
74
75 Mtp3SummaryDialog::~Mtp3SummaryDialog()
76 {
77     delete ui;
78 }
79
80 QString Mtp3SummaryDialog::summaryToHtml()
81 {
82     summary_tally summary;
83     memset(&summary, 0, sizeof(summary_tally));
84
85     QString section_tmpl;
86     QString table_begin, table_end;
87     QString table_row_begin, table_ul_row_begin, table_row_end;
88     QString table_vheader_tmpl, table_hheader15_tmpl, table_hheader25_tmpl;
89     QString table_data_tmpl;
90
91     section_tmpl = "<p><strong>%1</strong></p>\n";
92     table_begin = "<p><table>\n";
93     table_end = "</table></p>\n";
94     table_row_begin = "<tr>\n";
95     table_ul_row_begin = "<tr style=\"border-bottom: 1px solid gray;\">\n";
96     table_row_end = "</tr>\n";
97     table_vheader_tmpl = "<td width=\"50%\">%1:</td>"; // <th align="left"> looked odd
98     table_hheader15_tmpl = "<td width=\"15%\"><u>%1</u></td>";
99     table_hheader25_tmpl = "<td width=\"25%\"><u>%1</u></td>";
100     table_data_tmpl = "<td>%1</td>";
101
102     if (cap_file_.isValid()) {
103         /* initial computations */
104         summary_fill_in(cap_file_.capFile(), &summary);
105 #ifdef HAVE_LIBPCAP
106         summary_fill_in_capture(cap_file_.capFile(), &global_capture_opts, &summary);
107 #endif
108     }
109
110     QString summary_str;
111     QTextStream out(&summary_str);
112
113     // File Section
114     out << section_tmpl.arg(tr("File"));
115     out << table_begin;
116
117     out << table_row_begin
118         << table_vheader_tmpl.arg(tr("Name"))
119         << table_data_tmpl.arg(summary.filename)
120         << table_row_end;
121
122     out << table_row_begin
123         << table_vheader_tmpl.arg(tr("Length"))
124         << table_data_tmpl.arg(file_size_to_qstring(summary.file_length))
125         << table_row_end;
126
127     QString format_str = wtap_file_type_subtype_string(summary.file_type);
128     if (summary.iscompressed) {
129         format_str.append(tr(" (gzip compressed)"));
130     }
131     out << table_row_begin
132         << table_vheader_tmpl.arg(tr("Format"))
133         << table_data_tmpl.arg(format_str)
134         << table_row_end;
135
136     if (summary.has_snap) {
137         out << table_row_begin
138             << table_vheader_tmpl.arg(tr("Snapshot length"))
139             << table_data_tmpl.arg(summary.snap)
140             << table_row_end;
141     }
142
143     out << table_end;
144
145     // Data Section
146     out << section_tmpl.arg(tr("Data"));
147     out << table_begin;
148
149     if (summary.packet_count_ts == summary.packet_count &&
150             summary.packet_count >= 1)
151     {
152         // start time
153         out << table_row_begin
154             << table_vheader_tmpl.arg(tr("First packet"))
155             << table_data_tmpl.arg(time_t_to_qstring((time_t)summary.start_time))
156             << table_row_end;
157
158         // stop time
159         out << table_row_begin
160             << table_vheader_tmpl.arg(tr("Last packet"))
161             << table_data_tmpl.arg(time_t_to_qstring((time_t)summary.stop_time))
162             << table_row_end;
163
164         // elapsed seconds (capture duration)
165         if (summary.packet_count_ts > 1)
166         {
167             /* elapsed seconds */
168             QString elapsed_str;
169             unsigned int elapsed_time = (unsigned int)summary.elapsed_time;
170             if (elapsed_time/86400)
171             {
172                 elapsed_str = QString("%1 days ").arg(elapsed_time / 86400);
173             }
174
175             elapsed_str += QString("%1:%2:%3")
176                     .arg(elapsed_time % 86400 / 3600, 2, 10, QChar('0'))
177                     .arg(elapsed_time % 3600 / 60, 2, 10, QChar('0'))
178                     .arg(elapsed_time % 60, 2, 10, QChar('0'));
179             out << table_row_begin
180                 << table_vheader_tmpl.arg(tr("Elapsed"))
181                 << table_data_tmpl.arg(elapsed_str)
182                 << table_row_end;
183         }
184     }
185
186     // count
187     out << table_row_begin
188         << table_vheader_tmpl.arg(tr("Packets"))
189         << table_data_tmpl.arg(summary.packet_count)
190         << table_row_end;
191
192     out << table_end;
193
194     QString n_a = UTF8_EM_DASH;
195     int total_msus = 0;
196     int total_bytes = 0;
197     double seconds = summary.stop_time - summary.start_time;
198
199     // SI Section
200     out << section_tmpl.arg(tr("Service Indicator (SI) Totals"));
201     out << table_begin;
202
203     out << table_row_begin
204         << table_hheader25_tmpl.arg(tr("SI"))
205         << table_hheader15_tmpl.arg(tr("MSUs"))
206         << table_hheader15_tmpl.arg(tr("MSUs/s"))
207         << table_hheader15_tmpl.arg(tr("Bytes"))
208         << table_hheader15_tmpl.arg(tr("Bytes/MSU"))
209         << table_hheader15_tmpl.arg(tr("Bytes/s"))
210         << table_row_end;
211
212     for (size_t ws_si_code = 0; ws_si_code < MTP3_NUM_SI_CODE; ws_si_code++) {
213         int si_msus = 0;
214         int si_bytes = 0;
215         QString msus_s_str = n_a;
216         QString bytes_msu_str = n_a;
217         QString bytes_s_str = n_a;
218
219         for (size_t stat_idx = 0; stat_idx < mtp3_num_used; stat_idx++) {
220             si_msus += mtp3_stat[stat_idx].mtp3_si_code[ws_si_code].num_msus;
221             si_bytes += mtp3_stat[stat_idx].mtp3_si_code[ws_si_code].size;
222         }
223         total_msus += si_msus;
224         total_bytes += si_bytes;
225
226         if (seconds > 0) {
227             msus_s_str = QString("%1").arg(si_msus / seconds, 1, 'f', 1);
228             bytes_s_str = QString("%1").arg(si_bytes / seconds, 1, 'f', 1);
229         }
230
231         if (si_msus > 0) {
232             bytes_msu_str = QString("%1").arg((double) si_bytes / si_msus, 1, 'f', 1);
233         }
234
235         out << table_row_begin
236             << table_data_tmpl.arg(mtp3_service_indicator_code_short_vals[ws_si_code].strptr)
237             << table_data_tmpl.arg(si_msus)
238             << table_data_tmpl.arg(msus_s_str)
239             << table_data_tmpl.arg(si_bytes)
240             << table_data_tmpl.arg(bytes_msu_str)
241             << table_data_tmpl.arg(bytes_s_str)
242             << table_row_end;
243     }
244
245     out << table_end;
246
247     // Totals Section
248
249     QString total_msus_s_str = n_a;
250     QString total_bytes_msu_str = n_a;
251     QString total_bytes_s_str = n_a;
252
253     if (seconds > 0) {
254         total_msus_s_str = QString("%1").arg(total_msus / seconds, 1, 'f', 1);
255         total_bytes_s_str = QString("%1").arg(total_bytes / seconds, 1, 'f', 1);
256     }
257     if (total_msus > 0) {
258         total_bytes_msu_str = QString("%1").arg((double) total_bytes / total_msus, 1, 'f', 1);
259     }
260
261     out << section_tmpl.arg(tr("Totals"));
262     out << table_begin;
263
264     out << table_row_begin
265         << table_vheader_tmpl.arg(tr("Total MSUs"))
266         << table_data_tmpl.arg(total_msus)
267         << table_row_end;
268
269     out << table_row_begin
270         << table_vheader_tmpl.arg(tr("MSUs/s"))
271         << table_data_tmpl.arg(total_msus_s_str)
272         << table_row_end;
273
274     out << table_row_begin
275         << table_vheader_tmpl.arg(tr("Total Bytes"))
276         << table_data_tmpl.arg(total_bytes)
277         << table_row_end;
278
279     out << table_row_begin
280         << table_vheader_tmpl.arg(tr("Average Bytes/MSU"))
281         << table_data_tmpl.arg(total_bytes_msu_str)
282         << table_row_end;
283
284     out << table_row_begin
285         << table_vheader_tmpl.arg(tr("Average Bytes/s"))
286         << table_data_tmpl.arg(total_bytes_s_str)
287         << table_row_end;
288
289     out << table_end;
290
291     return summary_str;
292 }
293
294 void Mtp3SummaryDialog::updateWidgets()
295 {
296     ui->summaryTextEdit->setHtml(summaryToHtml());
297
298     WiresharkDialog::updateWidgets();
299 }
300
301 extern "C" {
302
303 static void
304 mtp3_summary_reset(
305     void        *tapdata)
306 {
307     mtp3_stat_t     (*stat_p)[MTP3_MAX_NUM_OPC_DPC] = (mtp3_stat_t(*)[MTP3_MAX_NUM_OPC_DPC])tapdata;
308
309     mtp3_num_used = 0;
310     memset(stat_p, 0, MTP3_MAX_NUM_OPC_DPC * sizeof(mtp3_stat_t));
311 }
312
313
314 static gboolean
315 mtp3_summary_packet(
316     void            *tapdata,
317     packet_info     *,
318     epan_dissect_t  *,
319     const void      *data)
320 {
321     mtp3_stat_t           (*stat_p)[MTP3_MAX_NUM_OPC_DPC] = (mtp3_stat_t(*)[MTP3_MAX_NUM_OPC_DPC])tapdata;
322     const mtp3_tap_rec_t  *data_p = (const mtp3_tap_rec_t *)data;
323     size_t                 i;
324
325     if (data_p->mtp3_si_code >= MTP3_NUM_SI_CODE)
326     {
327         /*
328          * we thought this si_code was not used ?
329          * is MTP3_NUM_SI_CODE out of date ?
330          */
331         return(FALSE);
332     }
333
334     /*
335      * look for opc/dpc pair
336      */
337     i = 0;
338     while (i < mtp3_num_used)
339     {
340         if (memcmp(&data_p->addr_opc, &(*stat_p)[i].addr_opc, sizeof(mtp3_addr_pc_t)) == 0)
341         {
342             if (memcmp(&data_p->addr_dpc, &(*stat_p)[i].addr_dpc, sizeof(mtp3_addr_pc_t)) == 0)
343             {
344                 break;
345             }
346         }
347
348         i++;
349     }
350
351     if (i == mtp3_num_used)
352     {
353         if (mtp3_num_used == MTP3_MAX_NUM_OPC_DPC)
354         {
355             /*
356              * too many
357              */
358             return(FALSE);
359         }
360
361         mtp3_num_used++;
362     }
363
364     (*stat_p)[i].addr_opc = data_p->addr_opc;
365     (*stat_p)[i].addr_dpc = data_p->addr_dpc;
366     (*stat_p)[i].mtp3_si_code[data_p->mtp3_si_code].num_msus++;
367     (*stat_p)[i].mtp3_si_code[data_p->mtp3_si_code].size += data_p->size;
368
369     return(TRUE);
370 }
371
372 void
373 register_tap_listener_qt_mtp3_summary(void)
374 {
375     GString     *err_p;
376
377     memset((void *) &mtp3_stat, 0, sizeof(mtp3_stat));
378
379     err_p =
380     register_tap_listener("mtp3", &mtp3_stat, NULL, 0,
381         mtp3_summary_reset,
382         mtp3_summary_packet,
383         NULL);
384
385     if (err_p != NULL)
386     {
387         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_p->str);
388         g_string_free(err_p, TRUE);
389
390         exit(1);
391     }
392 }
393
394 } // extern "C"
395
396 /*
397  * Editor modelines
398  *
399  * Local Variables:
400  * c-basic-offset: 4
401  * tab-width: 8
402  * indent-tabs-mode: nil
403  * End:
404  *
405  * ex: set shiftwidth=4 tabstop=8 expandtab:
406  * :indentSize=4:tabSize=8:noTabs=true:
407  */