/src/wireshark/epan/column-utils.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* column-utils.c |
2 | | * Routines for column utilities. |
3 | | * |
4 | | * Wireshark - Network traffic analyzer |
5 | | * By Gerald Combs <gerald@wireshark.org> |
6 | | * Copyright 1998 Gerald Combs |
7 | | * |
8 | | * SPDX-License-Identifier: GPL-2.0-or-later |
9 | | */ |
10 | | |
11 | | #include "config.h" |
12 | | |
13 | | #include <stdio.h> |
14 | | #include <string.h> |
15 | | #include <time.h> |
16 | | #include <locale.h> |
17 | | #include <limits.h> |
18 | | |
19 | | #include "column-utils.h" |
20 | | #include "timestamp.h" |
21 | | #include "to_str.h" |
22 | | #include "packet_info.h" |
23 | | #include "wsutil/pint.h" |
24 | | #include "addr_resolv.h" |
25 | | #include "address_types.h" |
26 | | #include "osi-utils.h" |
27 | | #include "value_string.h" |
28 | | #include "column-info.h" |
29 | | #include "column.h" |
30 | | #include "proto.h" |
31 | | |
32 | | #include <epan/strutil.h> |
33 | | #include <epan/epan.h> |
34 | | #include <epan/dfilter/dfilter.h> |
35 | | |
36 | | #include <wsutil/inet_cidr.h> |
37 | | #include <wsutil/utf8_entities.h> |
38 | | #include <wsutil/ws_assert.h> |
39 | | #include <wsutil/unicode-utils.h> |
40 | | #include <wsutil/time_util.h> |
41 | | |
42 | | #ifdef HAVE_LUA |
43 | | #include <epan/wslua/wslua.h> |
44 | | #endif |
45 | | |
46 | | #define COL_BUF_MAX_LEN (((COL_MAX_INFO_LEN) > (COL_MAX_LEN)) ? \ |
47 | | (COL_MAX_INFO_LEN) : (COL_MAX_LEN)) |
48 | | |
49 | | /* Used for locale decimal point */ |
50 | | static char *col_decimal_point; |
51 | | |
52 | | /* Used to indicate updated column information, e.g. a new request/response. */ |
53 | | static bool col_data_changed_; |
54 | | |
55 | | static int proto_cols; |
56 | | static int ett_cols; |
57 | | |
58 | | /* Allocate all the data structures for constructing column data, given |
59 | | the number of columns. */ |
60 | | void |
61 | | col_setup(column_info *cinfo, const int num_cols) |
62 | 14 | { |
63 | 14 | int i; |
64 | | |
65 | 14 | col_decimal_point = localeconv()->decimal_point; |
66 | 14 | cinfo->num_cols = num_cols; |
67 | 14 | cinfo->columns = g_new(col_item_t, num_cols); |
68 | 14 | cinfo->col_first = g_new(int, NUM_COL_FMTS); |
69 | 14 | cinfo->col_last = g_new(int, NUM_COL_FMTS); |
70 | 112 | for (i = 0; i < num_cols; i++) { |
71 | 98 | cinfo->columns[i].col_custom_fields_ids = NULL; |
72 | 98 | } |
73 | 14 | cinfo->col_expr.col_expr = g_new(const char*, num_cols + 1); |
74 | 14 | cinfo->col_expr.col_expr_val = g_new(char*, num_cols + 1); |
75 | | |
76 | 672 | for (i = 0; i < NUM_COL_FMTS; i++) { |
77 | 658 | cinfo->col_first[i] = -1; |
78 | 658 | cinfo->col_last[i] = -1; |
79 | 658 | } |
80 | 14 | cinfo->prime_regex = g_regex_new(COL_CUSTOM_PRIME_REGEX, |
81 | 14 | (GRegexCompileFlags) (G_REGEX_RAW), |
82 | 14 | 0, NULL); |
83 | 14 | } |
84 | | |
85 | | static void |
86 | | col_custom_free_cb(void *data) |
87 | 0 | { |
88 | 0 | col_custom_t *col_custom = (col_custom_t*)data; |
89 | 0 | dfilter_free(col_custom->dfilter); |
90 | 0 | g_free(col_custom->dftext); |
91 | 0 | g_free(col_custom); |
92 | 0 | } |
93 | | |
94 | | static void |
95 | | col_custom_fields_ids_free(GSList** custom_fields_id) |
96 | 0 | { |
97 | 0 | if (*custom_fields_id != NULL) { |
98 | 0 | g_slist_free_full(*custom_fields_id, col_custom_free_cb); |
99 | 0 | } |
100 | 0 | *custom_fields_id = NULL; |
101 | 0 | } |
102 | | |
103 | | /* Cleanup all the data structures for constructing column data; undoes |
104 | | the allocations that col_setup() does. */ |
105 | | void |
106 | | col_cleanup(column_info *cinfo) |
107 | 0 | { |
108 | 0 | int i; |
109 | 0 | col_item_t* col_item; |
110 | |
|
111 | 0 | if (!cinfo) |
112 | 0 | return; |
113 | | |
114 | 0 | for (i = 0; i < cinfo->num_cols; i++) { |
115 | 0 | col_item = &cinfo->columns[i]; |
116 | 0 | g_free(col_item->fmt_matx); |
117 | 0 | g_free(col_item->col_title); |
118 | 0 | g_free(col_item->col_custom_fields); |
119 | 0 | dfilter_free(col_item->col_custom_dfilter); |
120 | | /* col_item->col_data points to col_buf or static memory */ |
121 | 0 | g_free(col_item->col_buf); |
122 | 0 | g_free(cinfo->col_expr.col_expr_val[i]); |
123 | 0 | col_custom_fields_ids_free(&col_item->col_custom_fields_ids); |
124 | 0 | } |
125 | |
|
126 | 0 | g_free(cinfo->columns); |
127 | 0 | g_free(cinfo->col_first); |
128 | 0 | g_free(cinfo->col_last); |
129 | | /* |
130 | | * XXX - MSVC doesn't correctly handle the "const" qualifier; it thinks |
131 | | * "const XXX **" means "pointer to const pointer to XXX", i.e. that |
132 | | * it's a pointer to something that's "const"ant, not "pointer to |
133 | | * pointer to const XXX", i.e. that it's a pointer to a pointer to |
134 | | * something that's "const"ant. Cast its bogus complaints away. |
135 | | */ |
136 | 0 | g_free((char **)cinfo->col_expr.col_expr); |
137 | 0 | g_free(cinfo->col_expr.col_expr_val); |
138 | 0 | if (cinfo->prime_regex) |
139 | 0 | g_regex_unref(cinfo->prime_regex); |
140 | 0 | } |
141 | | |
142 | | /* Initialize the data structures for constructing column data. */ |
143 | | void |
144 | | col_init(column_info *cinfo, const struct epan_session *epan) |
145 | 0 | { |
146 | 0 | int i; |
147 | 0 | col_item_t* col_item; |
148 | |
|
149 | 0 | if (!cinfo) |
150 | 0 | return; |
151 | | |
152 | 0 | for (i = 0; i < cinfo->num_cols; i++) { |
153 | 0 | col_item = &cinfo->columns[i]; |
154 | 0 | col_item->col_buf[0] = '\0'; |
155 | 0 | col_item->col_data = col_item->col_buf; |
156 | 0 | col_item->col_fence = 0; |
157 | 0 | col_item->writable = true; |
158 | 0 | cinfo->col_expr.col_expr[i] = ""; |
159 | 0 | cinfo->col_expr.col_expr_val[i][0] = '\0'; |
160 | 0 | } |
161 | 0 | cinfo->writable = true; |
162 | 0 | cinfo->epan = epan; |
163 | 0 | } |
164 | | |
165 | | bool |
166 | | col_get_writable(column_info *cinfo, const int col) |
167 | 7.98M | { |
168 | 7.98M | int i; |
169 | 7.98M | col_item_t* col_item; |
170 | | |
171 | 7.98M | if (cinfo == NULL) |
172 | 7.98M | return false; |
173 | | |
174 | | /* "global" (not) writeability will always override |
175 | | an individual column */ |
176 | 0 | if ((col == -1) || (cinfo->writable == false)) |
177 | 0 | return cinfo->writable; |
178 | | |
179 | 0 | if (cinfo->col_first[col] >= 0) { |
180 | 0 | for (i = cinfo->col_first[col]; i <= cinfo->col_last[col]; i++) { |
181 | 0 | col_item = &cinfo->columns[i]; |
182 | 0 | if (col_item->fmt_matx[col]) { |
183 | 0 | return col_item->writable; |
184 | 0 | } |
185 | 0 | } |
186 | 0 | } |
187 | 0 | return false; |
188 | 0 | } |
189 | | |
190 | | void |
191 | | col_set_writable(column_info *cinfo, const int col, const bool writable) |
192 | 196k | { |
193 | 196k | int i; |
194 | 196k | col_item_t* col_item; |
195 | | |
196 | 196k | if (cinfo) { |
197 | 0 | if (col == -1) { |
198 | 0 | cinfo->writable = writable; |
199 | 0 | } else if (cinfo->col_first[col] >= 0) { |
200 | 0 | for (i = cinfo->col_first[col]; i <= cinfo->col_last[col]; i++) { |
201 | 0 | col_item = &cinfo->columns[i]; |
202 | 0 | if (col_item->fmt_matx[col]) { |
203 | 0 | col_item->writable = writable; |
204 | 0 | } |
205 | 0 | } |
206 | 0 | } |
207 | 0 | } |
208 | 196k | } |
209 | | |
210 | | /* Checks to see if a particular packet information element is needed for the packet list */ |
211 | | #define CHECK_COL(cinfo, el) \ |
212 | | /* We are constructing columns, and they're writable */ \ |
213 | 7.88M | (col_get_writable(cinfo, el) && \ |
214 | 7.88M | /* There is at least one column in that format */ \ |
215 | 7.88M | ((cinfo)->col_first[el] >= 0)) |
216 | | |
217 | | /* Sets the fence for a column to be at the end of the column. */ |
218 | | void |
219 | | col_set_fence(column_info *cinfo, const int el) |
220 | 36.8k | { |
221 | 36.8k | int i; |
222 | 36.8k | col_item_t* col_item; |
223 | | |
224 | 36.8k | if (!CHECK_COL(cinfo, el)) |
225 | 36.8k | return; |
226 | | |
227 | 0 | for (i = cinfo->col_first[el]; i <= cinfo->col_last[el]; i++) { |
228 | 0 | col_item = &cinfo->columns[i]; |
229 | 0 | if (col_item->fmt_matx[el]) { |
230 | 0 | col_item->col_fence = (int)strlen(col_item->col_data); |
231 | 0 | } |
232 | 0 | } |
233 | 0 | } |
234 | | |
235 | | /* Clear the fence for a column. */ |
236 | | void |
237 | | col_clear_fence(column_info *cinfo, const int el) |
238 | 1.16k | { |
239 | 1.16k | int i; |
240 | 1.16k | col_item_t* col_item; |
241 | | |
242 | 1.16k | if (!CHECK_COL(cinfo, el)) |
243 | 1.16k | return; |
244 | | |
245 | 0 | for (i = cinfo->col_first[el]; i <= cinfo->col_last[el]; i++) { |
246 | 0 | col_item = &cinfo->columns[i]; |
247 | 0 | if (col_item->fmt_matx[el]) { |
248 | 0 | col_item->col_fence = 0; |
249 | 0 | } |
250 | 0 | } |
251 | 0 | } |
252 | | |
253 | | /* Gets the text of a column */ |
254 | | const char * |
255 | | col_get_text(column_info *cinfo, const int el) |
256 | 4.41k | { |
257 | 4.41k | int i; |
258 | 4.41k | const char* text = NULL; |
259 | 4.41k | col_item_t* col_item; |
260 | | |
261 | 4.41k | if (!(cinfo && (cinfo)->col_first[el] >= 0)) { |
262 | 4.41k | return NULL; |
263 | 4.41k | } |
264 | | |
265 | 0 | for (i = cinfo->col_first[el]; i <= cinfo->col_last[el]; i++) { |
266 | 0 | col_item = &cinfo->columns[i]; |
267 | 0 | if (col_item->fmt_matx[el]) { |
268 | 0 | text = (col_item->col_data); |
269 | 0 | } |
270 | 0 | } |
271 | 0 | return text; |
272 | 4.41k | } |
273 | | |
274 | | |
275 | | /* Use this to clear out a column, especially if you're going to be |
276 | | appending to it later; at least on some platforms, it's more |
277 | | efficient than using "col_add_str()" with a null string, and |
278 | | more efficient than "col_set_str()" with a null string if you |
279 | | later append to it, as the later append will cause a string |
280 | | copy to be done. */ |
281 | | void |
282 | | col_clear(column_info *cinfo, const int el) |
283 | 284k | { |
284 | 284k | int i; |
285 | 284k | col_item_t* col_item; |
286 | | |
287 | 284k | if (!CHECK_COL(cinfo, el)) |
288 | 284k | return; |
289 | | |
290 | 0 | for (i = cinfo->col_first[el]; i <= cinfo->col_last[el]; i++) { |
291 | 0 | col_item = &cinfo->columns[i]; |
292 | 0 | if (col_item->fmt_matx[el]) { |
293 | | /* |
294 | | * At this point, either |
295 | | * |
296 | | * 1) col_data[i] is equal to col_buf[i], in which case we |
297 | | * don't have to worry about copying col_data[i] to |
298 | | * col_buf[i]; |
299 | | * |
300 | | * 2) col_data[i] isn't equal to col_buf[i], in which case |
301 | | * the only thing that's been done to the column is |
302 | | * "col_set_str()" calls and possibly "col_set_fence()" |
303 | | * calls, in which case the fence is either unset and |
304 | | * at the beginning of the string or set and at the end |
305 | | * of the string - if it's at the beginning, we're just |
306 | | * going to clear the column, and if it's at the end, |
307 | | * we don't do anything. |
308 | | */ |
309 | 0 | if (col_item->col_buf == col_item->col_data || col_item->col_fence == 0) { |
310 | | /* |
311 | | * The fence isn't at the end of the column, or the column wasn't |
312 | | * last set with "col_set_str()", so clear the column out. |
313 | | */ |
314 | 0 | col_item->col_buf[col_item->col_fence] = '\0'; |
315 | 0 | col_item->col_data = col_item->col_buf; |
316 | 0 | } |
317 | 0 | cinfo->col_expr.col_expr[i] = ""; |
318 | 0 | cinfo->col_expr.col_expr_val[i][0] = '\0'; |
319 | 0 | } |
320 | 0 | } |
321 | 0 | } |
322 | | |
323 | | #define COL_CHECK_APPEND(col_item, max_len) \ |
324 | 0 | if (col_item->col_data != col_item->col_buf) { \ |
325 | 0 | /* This was set with "col_set_str()"; copy the string they \ |
326 | 0 | set it to into the buffer, so we can append to it. */ \ |
327 | 0 | (void) g_strlcpy(col_item->col_buf, col_item->col_data, max_len); \ |
328 | 0 | col_item->col_data = col_item->col_buf; \ |
329 | 0 | } |
330 | | |
331 | | #define COL_CHECK_REF_TIME(fd, buf) \ |
332 | 0 | if (fd->ref_time) { \ |
333 | 0 | (void) g_strlcpy(buf, "*REF*", COL_MAX_LEN ); \ |
334 | 0 | return; \ |
335 | 0 | } |
336 | | |
337 | | /* The same as CHECK_COL(), but without the check to see if the column is writable. */ |
338 | 0 | #define HAVE_CUSTOM_COLS(cinfo) ((cinfo) && (cinfo)->col_first[COL_CUSTOM] >= 0) |
339 | | |
340 | | bool |
341 | | have_custom_cols(column_info *cinfo) |
342 | 0 | { |
343 | 0 | return HAVE_CUSTOM_COLS(cinfo); |
344 | 0 | } |
345 | | |
346 | | bool |
347 | | have_field_extractors(void) |
348 | 0 | { |
349 | | #ifdef HAVE_LUA |
350 | | return wslua_has_field_extractors(); |
351 | | #else |
352 | 0 | return false; |
353 | 0 | #endif |
354 | 0 | } |
355 | | |
356 | | /* search in edt tree custom fields */ |
357 | | void col_custom_set_edt(epan_dissect_t *edt, column_info *cinfo) |
358 | 0 | { |
359 | 0 | int i; |
360 | 0 | col_item_t* col_item; |
361 | |
|
362 | 0 | if (!HAVE_CUSTOM_COLS(cinfo)) |
363 | 0 | return; |
364 | | |
365 | 0 | for (i = cinfo->col_first[COL_CUSTOM]; |
366 | 0 | i <= cinfo->col_last[COL_CUSTOM]; i++) { |
367 | 0 | col_item = &cinfo->columns[i]; |
368 | 0 | if (col_item->fmt_matx[COL_CUSTOM] && |
369 | 0 | col_item->col_custom_fields && |
370 | 0 | col_item->col_custom_fields_ids) { |
371 | 0 | col_item->col_data = col_item->col_buf; |
372 | 0 | cinfo->col_expr.col_expr[i] = epan_custom_set(edt, col_item->col_custom_fields_ids, |
373 | 0 | col_item->col_custom_occurrence, |
374 | 0 | get_column_display_format(i) == COLUMN_DISPLAY_DETAILS, |
375 | 0 | col_item->col_buf, |
376 | 0 | cinfo->col_expr.col_expr_val[i], |
377 | 0 | COL_MAX_LEN); |
378 | 0 | } |
379 | 0 | } |
380 | 0 | } |
381 | | |
382 | | #if 0 |
383 | | // Needed if we create _ws.col.custom |
384 | | static void |
385 | | col_custom_set(proto_tree *tree, column_info *cinfo) |
386 | | { |
387 | | int i; |
388 | | col_item_t* col_item; |
389 | | |
390 | | if (!HAVE_CUSTOM_COLS(cinfo)) |
391 | | return; |
392 | | |
393 | | for (i = cinfo->col_first[COL_CUSTOM]; |
394 | | i <= cinfo->col_last[COL_CUSTOM]; i++) { |
395 | | col_item = &cinfo->columns[i]; |
396 | | if (col_item->fmt_matx[COL_CUSTOM] && |
397 | | col_item->col_custom_fields && |
398 | | col_item->col_custom_fields_ids) { |
399 | | col_item->col_data = col_item->col_buf; |
400 | | cinfo->col_expr.col_expr[i] = proto_custom_set(tree, col_item->col_custom_fields_ids, |
401 | | col_item->col_custom_occurrence, |
402 | | get_column_display_format(i) == COLUMN_DISPLAY_DETAILS, |
403 | | col_item->col_buf, |
404 | | cinfo->col_expr.col_expr_val[i], |
405 | | COL_MAX_LEN); |
406 | | } |
407 | | } |
408 | | } |
409 | | #endif |
410 | | |
411 | | void |
412 | | col_custom_prime_edt(epan_dissect_t *edt, column_info *cinfo) |
413 | 0 | { |
414 | 0 | int i; |
415 | 0 | col_item_t* col_item; |
416 | |
|
417 | 0 | if (!HAVE_CUSTOM_COLS(cinfo)) |
418 | 0 | return; |
419 | | |
420 | 0 | for (i = cinfo->col_first[COL_CUSTOM]; |
421 | 0 | i <= cinfo->col_last[COL_CUSTOM]; i++) { |
422 | 0 | col_item = &cinfo->columns[i]; |
423 | |
|
424 | 0 | if (col_item->fmt_matx[COL_CUSTOM] && |
425 | 0 | col_item->col_custom_dfilter) { |
426 | 0 | if (get_column_display_format(i) == COLUMN_DISPLAY_DETAILS) { |
427 | 0 | epan_dissect_prime_with_dfilter_print(edt, col_item->col_custom_dfilter); |
428 | 0 | } else { |
429 | 0 | epan_dissect_prime_with_dfilter(edt, col_item->col_custom_dfilter); |
430 | 0 | } |
431 | 0 | } |
432 | 0 | } |
433 | 0 | } |
434 | | |
435 | | char* |
436 | | col_custom_get_filter(epan_dissect_t *edt, column_info *cinfo, const int col) |
437 | 0 | { |
438 | 0 | col_item_t* col_item; |
439 | |
|
440 | 0 | ws_assert(cinfo); |
441 | 0 | ws_assert(col < cinfo->num_cols); |
442 | |
|
443 | 0 | col_item = &cinfo->columns[col]; |
444 | 0 | if (col_item->fmt_matx[COL_CUSTOM] && |
445 | 0 | col_item->col_custom_fields && |
446 | 0 | col_item->col_custom_fields_ids) { |
447 | |
|
448 | 0 | return proto_custom_get_filter(edt, col_item->col_custom_fields_ids, |
449 | 0 | col_item->col_custom_occurrence); |
450 | 0 | } |
451 | 0 | return NULL; |
452 | 0 | } |
453 | | |
454 | | void |
455 | | col_append_lstr(column_info *cinfo, const int el, const char *str1, ...) |
456 | 19.4k | { |
457 | 19.4k | va_list ap; |
458 | 19.4k | size_t pos, max_len; |
459 | 19.4k | int i; |
460 | 19.4k | const char *str; |
461 | 19.4k | col_item_t* col_item; |
462 | | |
463 | 19.4k | if (!CHECK_COL(cinfo, el)) |
464 | 19.4k | return; |
465 | | |
466 | 0 | if (el == COL_INFO) |
467 | 0 | max_len = COL_MAX_INFO_LEN; |
468 | 0 | else |
469 | 0 | max_len = COL_MAX_LEN; |
470 | |
|
471 | 0 | for (i = cinfo->col_first[el]; i <= cinfo->col_last[el]; i++) { |
472 | 0 | col_item = &cinfo->columns[i]; |
473 | 0 | if (col_item->fmt_matx[el]) { |
474 | | /* |
475 | | * First arrange that we can append, if necessary. |
476 | | */ |
477 | 0 | COL_CHECK_APPEND(col_item, max_len); |
478 | |
|
479 | 0 | pos = strlen(col_item->col_buf); |
480 | 0 | if (pos >= max_len) |
481 | 0 | return; |
482 | | |
483 | 0 | va_start(ap, str1); |
484 | 0 | str = str1; |
485 | 0 | do { |
486 | 0 | if (G_UNLIKELY(str == NULL)) { |
487 | 0 | str = "(null)"; |
488 | 0 | } |
489 | 0 | WS_UTF_8_CHECK(str, -1); |
490 | 0 | pos = ws_label_strcpy(col_item->col_buf, max_len, pos, str, 0); |
491 | |
|
492 | 0 | } while (pos < max_len && (str = va_arg(ap, const char *)) != COL_ADD_LSTR_TERMINATOR); |
493 | 0 | va_end(ap); |
494 | 0 | } |
495 | 0 | } |
496 | 0 | } |
497 | | |
498 | | void |
499 | | col_append_str_uint(column_info *cinfo, const int col, const char *abbrev, uint32_t val, const char *sep) |
500 | 97.2k | { |
501 | 97.2k | char buf[16]; |
502 | | |
503 | 97.2k | if (!CHECK_COL(cinfo, col)) |
504 | 97.2k | return; |
505 | | |
506 | 0 | uint32_to_str_buf(val, buf, sizeof(buf)); |
507 | 0 | col_append_lstr(cinfo, col, sep ? sep : "", abbrev, "=", buf, COL_ADD_LSTR_TERMINATOR); |
508 | 0 | } |
509 | | |
510 | | static inline void |
511 | | col_snprint_port(char *buf, size_t buf_siz, port_type typ, uint16_t val) |
512 | 0 | { |
513 | 0 | const char *str; |
514 | |
|
515 | 0 | if (gbl_resolv_flags.transport_name && |
516 | 0 | (str = try_serv_name_lookup(typ, val)) != NULL) { |
517 | 0 | snprintf(buf, buf_siz, "%s(%"PRIu16")", str, val); |
518 | 0 | } else { |
519 | 0 | snprintf(buf, buf_siz, "%"PRIu16, val); |
520 | 0 | } |
521 | 0 | } |
522 | | |
523 | | void |
524 | | col_append_ports(column_info *cinfo, const int col, port_type typ, uint16_t src, uint16_t dst) |
525 | 60.2k | { |
526 | 60.2k | char buf_src[32], buf_dst[32]; |
527 | | |
528 | 60.2k | if (!CHECK_COL(cinfo, col)) |
529 | 60.2k | return; |
530 | | |
531 | 0 | col_snprint_port(buf_src, 32, typ, src); |
532 | 0 | col_snprint_port(buf_dst, 32, typ, dst); |
533 | 0 | col_append_lstr(cinfo, col, buf_src, " " UTF8_RIGHTWARDS_ARROW " ", buf_dst, COL_ADD_LSTR_TERMINATOR); |
534 | 0 | } |
535 | | |
536 | | void |
537 | | col_append_frame_number(packet_info *pinfo, const int col, const char *fmt_str, unsigned frame_num) |
538 | 0 | { |
539 | 0 | col_append_fstr(pinfo->cinfo, col, fmt_str, frame_num); |
540 | 0 | if (!pinfo->fd->visited) { |
541 | 0 | col_data_changed_ = true; |
542 | 0 | } |
543 | 0 | } |
544 | | |
545 | | static void |
546 | | col_do_append_fstr(column_info *cinfo, const int el, const char *separator, const char *format, va_list ap) |
547 | 0 | { |
548 | 0 | size_t len, max_len, sep_len, pos; |
549 | 0 | int i; |
550 | 0 | col_item_t* col_item; |
551 | 0 | char tmp[COL_BUF_MAX_LEN]; |
552 | |
|
553 | 0 | sep_len = (separator) ? strlen(separator) : 0; |
554 | |
|
555 | 0 | if (el == COL_INFO) |
556 | 0 | max_len = COL_MAX_INFO_LEN; |
557 | 0 | else |
558 | 0 | max_len = COL_MAX_LEN; |
559 | |
|
560 | 0 | for (i = cinfo->col_first[el]; i <= cinfo->col_last[el]; i++) { |
561 | 0 | col_item = &cinfo->columns[i]; |
562 | 0 | if (col_item->fmt_matx[el]) { |
563 | | /* |
564 | | * First arrange that we can append, if necessary. |
565 | | */ |
566 | 0 | COL_CHECK_APPEND(col_item, max_len); |
567 | |
|
568 | 0 | len = strlen(col_item->col_buf); |
569 | | |
570 | | /* |
571 | | * If we have a separator, append it if the column isn't empty. |
572 | | */ |
573 | 0 | if (sep_len != 0 && len != 0) { |
574 | 0 | (void) ws_label_strcat(col_item->col_buf, max_len, separator, 0); |
575 | 0 | len += sep_len; |
576 | 0 | } |
577 | |
|
578 | 0 | if (len < max_len) { |
579 | 0 | va_list ap2; |
580 | |
|
581 | 0 | va_copy(ap2, ap); |
582 | 0 | pos = vsnprintf(tmp, sizeof(tmp), format, ap2); |
583 | 0 | va_end(ap2); |
584 | 0 | if (pos >= max_len) { |
585 | 0 | ws_utf8_truncate(tmp, max_len - 1); |
586 | 0 | } |
587 | 0 | WS_UTF_8_CHECK(tmp, -1); |
588 | 0 | ws_label_strcpy(col_item->col_buf, max_len, len, tmp, 0); |
589 | 0 | } |
590 | 0 | } |
591 | 0 | } |
592 | 0 | } |
593 | | |
594 | | /* Appends a vararg list to a packet info string. */ |
595 | | void |
596 | | col_append_fstr(column_info *cinfo, const int el, const char *format, ...) |
597 | 363k | { |
598 | 363k | va_list ap; |
599 | | |
600 | 363k | if (!CHECK_COL(cinfo, el)) |
601 | 363k | return; |
602 | | |
603 | 0 | va_start(ap, format); |
604 | 0 | col_do_append_fstr(cinfo, el, NULL, format, ap); |
605 | 0 | va_end(ap); |
606 | 0 | } |
607 | | |
608 | | /* Appends a vararg list to a packet info string. |
609 | | * Prefixes it with the given separator if the column is not empty. |
610 | | */ |
611 | | void |
612 | | col_append_sep_fstr(column_info *cinfo, const int el, const char *separator, |
613 | | const char *format, ...) |
614 | 28.4k | { |
615 | 28.4k | va_list ap; |
616 | | |
617 | 28.4k | if (!CHECK_COL(cinfo, el)) |
618 | 28.4k | return; |
619 | | |
620 | 0 | if (separator == NULL) |
621 | 0 | separator = ", "; /* default */ |
622 | |
|
623 | 0 | va_start(ap, format); |
624 | 0 | col_do_append_fstr(cinfo, el, separator, format, ap); |
625 | 0 | va_end(ap); |
626 | 0 | } |
627 | | |
628 | | /* Prepends a vararg list to a packet info string. */ |
629 | | void |
630 | | col_prepend_fstr(column_info *cinfo, const int el, const char *format, ...) |
631 | 1.03k | { |
632 | 1.03k | va_list ap; |
633 | 1.03k | int i; |
634 | 1.03k | char orig_buf[COL_BUF_MAX_LEN]; |
635 | 1.03k | const char *orig; |
636 | 1.03k | size_t max_len, pos; |
637 | 1.03k | col_item_t* col_item; |
638 | 1.03k | char tmp[COL_BUF_MAX_LEN]; |
639 | | |
640 | 1.03k | if (!CHECK_COL(cinfo, el)) |
641 | 1.03k | return; |
642 | | |
643 | 0 | if (el == COL_INFO) |
644 | 0 | max_len = COL_MAX_INFO_LEN; |
645 | 0 | else |
646 | 0 | max_len = COL_MAX_LEN; |
647 | |
|
648 | 0 | for (i = cinfo->col_first[el]; i <= cinfo->col_last[el]; i++) { |
649 | 0 | col_item = &cinfo->columns[i]; |
650 | 0 | if (col_item->fmt_matx[el]) { |
651 | 0 | if (col_item->col_data != col_item->col_buf) { |
652 | | /* This was set with "col_set_str()"; which is effectively const */ |
653 | 0 | orig = col_item->col_data; |
654 | 0 | } else { |
655 | 0 | (void) g_strlcpy(orig_buf, col_item->col_buf, max_len); |
656 | 0 | orig = orig_buf; |
657 | 0 | } |
658 | 0 | va_start(ap, format); |
659 | 0 | pos = vsnprintf(tmp, sizeof(tmp), format, ap); |
660 | 0 | va_end(ap); |
661 | 0 | if (pos >= max_len) { |
662 | 0 | ws_utf8_truncate(tmp, max_len - 1); |
663 | 0 | } |
664 | 0 | WS_UTF_8_CHECK(tmp, -1); |
665 | 0 | pos = ws_label_strcpy(col_item->col_buf, max_len, 0, tmp, 0); |
666 | | |
667 | | /* |
668 | | * Move the fence, unless it's at the beginning of the string. |
669 | | */ |
670 | 0 | if (col_item->col_fence > 0) |
671 | 0 | col_item->col_fence += (int) strlen(col_item->col_buf); |
672 | | |
673 | | /* |
674 | | * Append the original data. |
675 | | */ |
676 | 0 | ws_label_strcpy(col_item->col_buf, max_len, pos, orig, 0); |
677 | 0 | col_item->col_data = col_item->col_buf; |
678 | 0 | } |
679 | 0 | } |
680 | 0 | } |
681 | | void |
682 | | col_prepend_fence_fstr(column_info *cinfo, const int el, const char *format, ...) |
683 | 3.83k | { |
684 | 3.83k | va_list ap; |
685 | 3.83k | int i; |
686 | 3.83k | char orig_buf[COL_BUF_MAX_LEN]; |
687 | 3.83k | const char *orig; |
688 | 3.83k | size_t max_len, pos; |
689 | 3.83k | col_item_t* col_item; |
690 | 3.83k | char tmp[COL_BUF_MAX_LEN]; |
691 | | |
692 | 3.83k | if (!CHECK_COL(cinfo, el)) |
693 | 3.83k | return; |
694 | | |
695 | 0 | if (el == COL_INFO) |
696 | 0 | max_len = COL_MAX_INFO_LEN; |
697 | 0 | else |
698 | 0 | max_len = COL_MAX_LEN; |
699 | |
|
700 | 0 | for (i = cinfo->col_first[el]; i <= cinfo->col_last[el]; i++) { |
701 | 0 | col_item = &cinfo->columns[i]; |
702 | 0 | if (col_item->fmt_matx[el]) { |
703 | 0 | if (col_item->col_data != col_item->col_buf) { |
704 | | /* This was set with "col_set_str()"; which is effectively const */ |
705 | 0 | orig = col_item->col_data; |
706 | 0 | } else { |
707 | 0 | (void) g_strlcpy(orig_buf, col_item->col_buf, max_len); |
708 | 0 | orig = orig_buf; |
709 | 0 | } |
710 | 0 | va_start(ap, format); |
711 | 0 | pos = vsnprintf(tmp, sizeof(tmp), format, ap); |
712 | 0 | va_end(ap); |
713 | 0 | if (pos >= max_len) { |
714 | 0 | ws_utf8_truncate(tmp, max_len - 1); |
715 | 0 | } |
716 | 0 | WS_UTF_8_CHECK(tmp, -1); |
717 | 0 | pos = ws_label_strcpy(col_item->col_buf, max_len, 0, tmp, 0); |
718 | | |
719 | | /* |
720 | | * Move the fence if it exists, else create a new fence at the |
721 | | * end of the prepended data. |
722 | | */ |
723 | 0 | if (col_item->col_fence > 0) { |
724 | 0 | col_item->col_fence += (int) strlen(col_item->col_buf); |
725 | 0 | } else { |
726 | 0 | col_item->col_fence = (int) strlen(col_item->col_buf); |
727 | 0 | } |
728 | | /* |
729 | | * Append the original data. |
730 | | */ |
731 | 0 | ws_label_strcpy(col_item->col_buf, max_len, pos, orig, 0); |
732 | 0 | col_item->col_data = col_item->col_buf; |
733 | 0 | } |
734 | 0 | } |
735 | 0 | } |
736 | | |
737 | | /* Use this if "str" points to something that won't stay around (and |
738 | | must thus be copied). */ |
739 | | void |
740 | | col_add_str(column_info *cinfo, const int el, const char* str) |
741 | 5.87M | { |
742 | 5.87M | int i; |
743 | 5.87M | size_t max_len; |
744 | 5.87M | col_item_t* col_item; |
745 | | |
746 | 5.87M | if (!CHECK_COL(cinfo, el)) |
747 | 5.87M | return; |
748 | | |
749 | 0 | if (el == COL_INFO) |
750 | 0 | max_len = COL_MAX_INFO_LEN; |
751 | 0 | else |
752 | 0 | max_len = COL_MAX_LEN; |
753 | |
|
754 | 0 | for (i = cinfo->col_first[el]; i <= cinfo->col_last[el]; i++) { |
755 | 0 | col_item = &cinfo->columns[i]; |
756 | 0 | if (col_item->fmt_matx[el]) { |
757 | 0 | if (col_item->col_fence != 0) { |
758 | | /* |
759 | | * We will append the string after the fence. |
760 | | * First arrange that we can append, if necessary. |
761 | | */ |
762 | 0 | COL_CHECK_APPEND(col_item, max_len); |
763 | 0 | } else { |
764 | | /* |
765 | | * There's no fence, so we can just write to the string. |
766 | | */ |
767 | 0 | col_item->col_data = col_item->col_buf; |
768 | 0 | } |
769 | 0 | WS_UTF_8_CHECK(str, -1); |
770 | 0 | (void) ws_label_strcpy(col_item->col_buf, max_len, col_item->col_fence, str, 0); |
771 | 0 | } |
772 | 0 | } |
773 | 0 | } |
774 | | |
775 | | /* Use this if "str" points to something that will stay around (and thus |
776 | | needn't be copied). */ |
777 | | void |
778 | | col_set_str(column_info *cinfo, const int el, const char* str) |
779 | 684k | { |
780 | 684k | int i; |
781 | 684k | size_t max_len; |
782 | 684k | col_item_t* col_item; |
783 | | |
784 | 684k | DISSECTOR_ASSERT(str); |
785 | | |
786 | 684k | if (!CHECK_COL(cinfo, el)) |
787 | 684k | return; |
788 | | |
789 | 0 | if (el == COL_INFO) |
790 | 0 | max_len = COL_MAX_INFO_LEN; |
791 | 0 | else |
792 | 0 | max_len = COL_MAX_LEN; |
793 | |
|
794 | 0 | for (i = cinfo->col_first[el]; i <= cinfo->col_last[el]; i++) { |
795 | 0 | col_item = &cinfo->columns[i]; |
796 | 0 | if (col_item->fmt_matx[el]) { |
797 | 0 | if (col_item->col_fence != 0) { |
798 | | /* |
799 | | * We will append the string after the fence. |
800 | | * First arrange that we can append, if necessary. |
801 | | */ |
802 | 0 | COL_CHECK_APPEND(col_item, max_len); |
803 | |
|
804 | 0 | (void) g_strlcpy(&col_item->col_buf[col_item->col_fence], str, max_len - col_item->col_fence); |
805 | 0 | } else { |
806 | | /* |
807 | | * There's no fence, so we can just set the column to point |
808 | | * to the string. |
809 | | */ |
810 | 0 | col_item->col_data = str; |
811 | 0 | } |
812 | 0 | } |
813 | 0 | } |
814 | 0 | } |
815 | | |
816 | | void |
817 | | col_add_lstr(column_info *cinfo, const int el, const char *str1, ...) |
818 | 81 | { |
819 | 81 | va_list ap; |
820 | 81 | int i; |
821 | 81 | size_t pos; |
822 | 81 | size_t max_len; |
823 | 81 | const char *str; |
824 | 81 | col_item_t* col_item; |
825 | | |
826 | 81 | if (!CHECK_COL(cinfo, el)) |
827 | 81 | return; |
828 | | |
829 | 0 | if (el == COL_INFO) |
830 | 0 | max_len = COL_MAX_INFO_LEN; |
831 | 0 | else |
832 | 0 | max_len = COL_MAX_LEN; |
833 | |
|
834 | 0 | for (i = cinfo->col_first[el]; i <= cinfo->col_last[el]; i++) { |
835 | 0 | col_item = &cinfo->columns[i]; |
836 | 0 | if (col_item->fmt_matx[el]) { |
837 | 0 | pos = col_item->col_fence; |
838 | 0 | if (pos != 0) { |
839 | | /* |
840 | | * We will append the string after the fence. |
841 | | * First arrange that we can append, if necessary. |
842 | | */ |
843 | 0 | COL_CHECK_APPEND(col_item, max_len); |
844 | 0 | } else { |
845 | | /* |
846 | | * There's no fence, so we can just write to the string. |
847 | | */ |
848 | 0 | col_item->col_data = col_item->col_buf; |
849 | 0 | } |
850 | |
|
851 | 0 | va_start(ap, str1); |
852 | 0 | str = str1; |
853 | 0 | do { |
854 | 0 | if (G_UNLIKELY(str == NULL)) { |
855 | 0 | str = "(null)"; |
856 | 0 | } |
857 | 0 | WS_UTF_8_CHECK(str, -1); |
858 | 0 | pos = ws_label_strcpy(col_item->col_buf, max_len, pos, str, 0); |
859 | |
|
860 | 0 | } while (pos < max_len && (str = va_arg(ap, const char *)) != COL_ADD_LSTR_TERMINATOR); |
861 | 0 | va_end(ap); |
862 | 0 | } |
863 | 0 | } |
864 | 0 | } |
865 | | |
866 | | /* Adds a vararg list to a packet info string. */ |
867 | | void |
868 | | col_add_fstr(column_info *cinfo, const int el, const char *format, ...) |
869 | 181k | { |
870 | 181k | va_list ap; |
871 | 181k | int i, pos; |
872 | 181k | int max_len; |
873 | 181k | col_item_t* col_item; |
874 | 181k | char tmp[COL_BUF_MAX_LEN]; |
875 | | |
876 | 181k | if (!CHECK_COL(cinfo, el)) |
877 | 181k | return; |
878 | | |
879 | 0 | if (el == COL_INFO) |
880 | 0 | max_len = COL_MAX_INFO_LEN; |
881 | 0 | else |
882 | 0 | max_len = COL_MAX_LEN; |
883 | |
|
884 | 0 | for (i = cinfo->col_first[el]; i <= cinfo->col_last[el]; i++) { |
885 | 0 | col_item = &cinfo->columns[i]; |
886 | 0 | if (col_item->fmt_matx[el]) { |
887 | 0 | if (col_item->col_fence != 0) { |
888 | | /* |
889 | | * We will append the string after the fence. |
890 | | * First arrange that we can append, if necessary. |
891 | | */ |
892 | 0 | COL_CHECK_APPEND(col_item, max_len); |
893 | 0 | } else { |
894 | | /* |
895 | | * There's no fence, so we can just write to the string. |
896 | | */ |
897 | 0 | col_item->col_data = col_item->col_buf; |
898 | 0 | } |
899 | 0 | va_start(ap, format); |
900 | 0 | pos = vsnprintf(tmp, sizeof(tmp), format, ap); |
901 | 0 | va_end(ap); |
902 | 0 | if (pos >= max_len) { |
903 | 0 | ws_utf8_truncate(tmp, max_len - 1); |
904 | 0 | } |
905 | 0 | WS_UTF_8_CHECK(tmp, -1); |
906 | 0 | ws_label_strcpy(col_item->col_buf, max_len, col_item->col_fence, tmp, 0); |
907 | 0 | } |
908 | 0 | } |
909 | 0 | } |
910 | | |
911 | | static void |
912 | | col_do_append_str(column_info *cinfo, const int el, const char* separator, |
913 | | const char* str) |
914 | 0 | { |
915 | 0 | int i; |
916 | 0 | size_t len, max_len; |
917 | 0 | col_item_t* col_item; |
918 | |
|
919 | 0 | if (el == COL_INFO) |
920 | 0 | max_len = COL_MAX_INFO_LEN; |
921 | 0 | else |
922 | 0 | max_len = COL_MAX_LEN; |
923 | |
|
924 | 0 | for (i = cinfo->col_first[el]; i <= cinfo->col_last[el]; i++) { |
925 | 0 | col_item = &cinfo->columns[i]; |
926 | 0 | if (col_item->fmt_matx[el]) { |
927 | | /* |
928 | | * First arrange that we can append, if necessary. |
929 | | */ |
930 | 0 | COL_CHECK_APPEND(col_item, max_len); |
931 | |
|
932 | 0 | len = col_item->col_buf[0]; |
933 | | |
934 | | /* |
935 | | * If we have a separator, append it if the column isn't empty. |
936 | | */ |
937 | 0 | if (separator != NULL) { |
938 | 0 | if (len != 0) { |
939 | 0 | (void) ws_label_strcat(col_item->col_buf, max_len, separator, 0); |
940 | 0 | } |
941 | 0 | } |
942 | 0 | WS_UTF_8_CHECK(str, -1); |
943 | 0 | (void) ws_label_strcat(col_item->col_buf, max_len, str, 0); |
944 | 0 | } |
945 | 0 | } |
946 | 0 | } |
947 | | |
948 | | void |
949 | | col_append_str(column_info *cinfo, const int el, const char* str) |
950 | 182k | { |
951 | 182k | if (!CHECK_COL(cinfo, el)) |
952 | 182k | return; |
953 | | |
954 | 0 | col_do_append_str(cinfo, el, NULL, str); |
955 | 0 | } |
956 | | |
957 | | void |
958 | | col_append_sep_str(column_info *cinfo, const int el, const char* separator, |
959 | | const char* str) |
960 | 62.3k | { |
961 | 62.3k | if (!CHECK_COL(cinfo, el)) |
962 | 62.3k | return; |
963 | | |
964 | 0 | if (separator == NULL) |
965 | 0 | separator = ", "; /* default */ |
966 | |
|
967 | 0 | col_do_append_str(cinfo, el, separator, str); |
968 | 0 | } |
969 | | |
970 | | /* --------------------------------- */ |
971 | | bool |
972 | | col_has_time_fmt(column_info *cinfo, const int col) |
973 | 0 | { |
974 | 0 | col_item_t* col_item = &cinfo->columns[col]; |
975 | 0 | return ((col_item->fmt_matx[COL_CLS_TIME]) || |
976 | 0 | (col_item->fmt_matx[COL_ABS_TIME]) || |
977 | 0 | (col_item->fmt_matx[COL_ABS_YMD_TIME]) || |
978 | 0 | (col_item->fmt_matx[COL_ABS_YDOY_TIME]) || |
979 | 0 | (col_item->fmt_matx[COL_UTC_TIME]) || |
980 | 0 | (col_item->fmt_matx[COL_UTC_YMD_TIME]) || |
981 | 0 | (col_item->fmt_matx[COL_UTC_YDOY_TIME]) || |
982 | 0 | (col_item->fmt_matx[COL_REL_TIME]) || |
983 | 0 | (col_item->fmt_matx[COL_DELTA_TIME]) || |
984 | 0 | (col_item->fmt_matx[COL_DELTA_TIME_DIS])); |
985 | 0 | } |
986 | | |
987 | | static int |
988 | | get_frame_timestamp_precision(const frame_data *fd) |
989 | 0 | { |
990 | 0 | int tsprecision; |
991 | |
|
992 | 0 | tsprecision = timestamp_get_precision(); |
993 | 0 | if (tsprecision == TS_PREC_AUTO) |
994 | 0 | tsprecision = fd->tsprec; |
995 | 0 | else if (tsprecision < 0) |
996 | 0 | ws_assert_not_reached(); |
997 | | |
998 | | /* |
999 | | * Time stamp precision values higher than the maximum |
1000 | | * precision we support can't be handled. Just display |
1001 | | * those times with the maximum precision we support. |
1002 | | */ |
1003 | 0 | if (tsprecision > WS_TSPREC_MAX) |
1004 | 0 | tsprecision = WS_TSPREC_MAX; |
1005 | |
|
1006 | 0 | return tsprecision; |
1007 | 0 | } |
1008 | | |
1009 | | static int |
1010 | | get_default_timestamp_precision(void) |
1011 | 0 | { |
1012 | 0 | int tsprecision; |
1013 | |
|
1014 | 0 | tsprecision = timestamp_get_precision(); |
1015 | 0 | if (tsprecision == TS_PREC_AUTO) |
1016 | 0 | tsprecision = WS_TSPREC_MAX; /* default to the maximum precision we support */ |
1017 | 0 | else if (tsprecision < 0) |
1018 | 0 | ws_assert_not_reached(); |
1019 | | |
1020 | | /* |
1021 | | * Time stamp precision values higher than the maximum |
1022 | | * precision we support can't be handled. Just display |
1023 | | * those times with the maximum precision we support. |
1024 | | */ |
1025 | 0 | if (tsprecision > WS_TSPREC_MAX) |
1026 | 0 | tsprecision = WS_TSPREC_MAX; |
1027 | |
|
1028 | 0 | return tsprecision; |
1029 | 0 | } |
1030 | | |
1031 | | static void |
1032 | | set_abs_ymd_time(const frame_data *fd, char *buf, char *decimal_point, bool local) |
1033 | 0 | { |
1034 | 0 | if (!fd->has_ts) { |
1035 | 0 | buf[0] = '\0'; |
1036 | 0 | return; |
1037 | 0 | } |
1038 | 0 | format_nstime_as_iso8601(buf, COL_MAX_LEN, &fd->abs_ts, decimal_point, local, get_frame_timestamp_precision(fd)); |
1039 | 0 | } |
1040 | | |
1041 | | static void |
1042 | | col_set_abs_ymd_time(const frame_data *fd, column_info *cinfo, const int col) |
1043 | 0 | { |
1044 | 0 | set_abs_ymd_time(fd, cinfo->columns[col].col_buf, col_decimal_point, true); |
1045 | 0 | cinfo->col_expr.col_expr[col] = "frame.time"; |
1046 | 0 | (void) g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->columns[col].col_buf,COL_MAX_LEN); |
1047 | |
|
1048 | 0 | cinfo->columns[col].col_data = cinfo->columns[col].col_buf; |
1049 | 0 | } |
1050 | | |
1051 | | static void |
1052 | | col_set_utc_ymd_time(const frame_data *fd, column_info *cinfo, const int col) |
1053 | 0 | { |
1054 | 0 | set_abs_ymd_time(fd, cinfo->columns[col].col_buf, col_decimal_point, false); |
1055 | 0 | cinfo->col_expr.col_expr[col] = "frame.time"; |
1056 | 0 | (void) g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->columns[col].col_buf,COL_MAX_LEN); |
1057 | |
|
1058 | 0 | cinfo->columns[col].col_data = cinfo->columns[col].col_buf; |
1059 | 0 | } |
1060 | | |
1061 | | static void |
1062 | | set_abs_ydoy_time(const frame_data *fd, char *buf, char *decimal_point, bool local) |
1063 | 0 | { |
1064 | 0 | struct tm tm, *tmp; |
1065 | 0 | char *ptr; |
1066 | 0 | size_t remaining; |
1067 | 0 | int num_bytes; |
1068 | 0 | int tsprecision; |
1069 | |
|
1070 | 0 | if (!fd->has_ts) { |
1071 | 0 | buf[0] = '\0'; |
1072 | 0 | return; |
1073 | 0 | } |
1074 | | |
1075 | 0 | if (local) |
1076 | 0 | tmp = ws_localtime_r(&fd->abs_ts.secs, &tm); |
1077 | 0 | else |
1078 | 0 | tmp = ws_gmtime_r(&fd->abs_ts.secs, &tm); |
1079 | 0 | if (tmp == NULL) { |
1080 | 0 | snprintf(buf, COL_MAX_LEN, "Not representable"); |
1081 | 0 | return; |
1082 | 0 | } |
1083 | 0 | ptr = buf; |
1084 | 0 | remaining = COL_MAX_LEN; |
1085 | 0 | num_bytes = snprintf(ptr, remaining,"%04d/%03d %02d:%02d:%02d", |
1086 | 0 | tmp->tm_year + 1900, |
1087 | 0 | tmp->tm_yday + 1, |
1088 | 0 | tmp->tm_hour, |
1089 | 0 | tmp->tm_min, |
1090 | 0 | tmp->tm_sec); |
1091 | 0 | if (num_bytes < 0) { |
1092 | | /* |
1093 | | * That got an error. |
1094 | | * Not much else we can do. |
1095 | | */ |
1096 | 0 | snprintf(ptr, remaining, "snprintf() failed"); |
1097 | 0 | return; |
1098 | 0 | } |
1099 | 0 | if ((unsigned int)num_bytes >= remaining) { |
1100 | | /* |
1101 | | * That filled up or would have overflowed the buffer. |
1102 | | * Nothing more we can do. |
1103 | | */ |
1104 | 0 | return; |
1105 | 0 | } |
1106 | 0 | ptr += num_bytes; |
1107 | 0 | remaining -= num_bytes; |
1108 | |
|
1109 | 0 | tsprecision = get_frame_timestamp_precision(fd); |
1110 | 0 | if (tsprecision != 0) { |
1111 | | /* |
1112 | | * Append the fractional part. |
1113 | | * Get the nsecs as a 32-bit unsigned value, as it should never |
1114 | | * be negative, so we treat it as unsigned. |
1115 | | */ |
1116 | 0 | num_bytes = format_fractional_part_nsecs(ptr, remaining, (uint32_t)fd->abs_ts.nsecs, decimal_point, tsprecision); |
1117 | 0 | } |
1118 | |
|
1119 | 0 | if (!local) { |
1120 | | /* |
1121 | | * format_fractional_part_nsecs, unlike snprintf, returns the |
1122 | | * number of bytes copied (not "would have copied"), so we |
1123 | | * don't check for overflow here. |
1124 | | */ |
1125 | 0 | ptr += num_bytes; |
1126 | 0 | remaining -= num_bytes; |
1127 | |
|
1128 | 0 | if (remaining == 1 && num_bytes > 0) { |
1129 | | /* |
1130 | | * If we copied a fractional part but there's only room |
1131 | | * for the terminating '\0', replace the last digit of |
1132 | | * the fractional part with the "Z". (Remaining is at |
1133 | | * least 1, otherwise we would have returned above.) |
1134 | | */ |
1135 | 0 | ptr--; |
1136 | 0 | remaining++; |
1137 | 0 | } |
1138 | 0 | (void)g_strlcpy(ptr, "Z", remaining); |
1139 | 0 | } |
1140 | 0 | } |
1141 | | |
1142 | | static void |
1143 | | col_set_abs_ydoy_time(const frame_data *fd, column_info *cinfo, const int col) |
1144 | 0 | { |
1145 | 0 | set_abs_ydoy_time(fd, cinfo->columns[col].col_buf, col_decimal_point, true); |
1146 | 0 | cinfo->col_expr.col_expr[col] = "frame.time"; |
1147 | 0 | (void) g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->columns[col].col_buf,COL_MAX_LEN); |
1148 | |
|
1149 | 0 | cinfo->columns[col].col_data = cinfo->columns[col].col_buf; |
1150 | 0 | } |
1151 | | |
1152 | | static void |
1153 | | col_set_utc_ydoy_time(const frame_data *fd, column_info *cinfo, const int col) |
1154 | 0 | { |
1155 | 0 | set_abs_ydoy_time(fd, cinfo->columns[col].col_buf, col_decimal_point, false); |
1156 | 0 | cinfo->col_expr.col_expr[col] = "frame.time"; |
1157 | 0 | (void) g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->columns[col].col_buf,COL_MAX_LEN); |
1158 | |
|
1159 | 0 | cinfo->columns[col].col_data = cinfo->columns[col].col_buf; |
1160 | 0 | } |
1161 | | |
1162 | | static void |
1163 | | set_time_seconds(const frame_data *fd, const nstime_t *ts, char *buf) |
1164 | 0 | { |
1165 | 0 | ws_assert(fd->has_ts); |
1166 | |
|
1167 | 0 | display_signed_time(buf, COL_MAX_LEN, ts, get_frame_timestamp_precision(fd)); |
1168 | 0 | } |
1169 | | |
1170 | | static void |
1171 | | set_time_hour_min_sec(const frame_data *fd, const nstime_t *ts, char *buf, char *decimal_point) |
1172 | 0 | { |
1173 | 0 | time_t secs = ts->secs; |
1174 | 0 | uint32_t nsecs; |
1175 | 0 | bool negative = false; |
1176 | 0 | char *ptr; |
1177 | 0 | size_t remaining; |
1178 | 0 | int num_bytes; |
1179 | 0 | int tsprecision; |
1180 | |
|
1181 | 0 | ws_assert(fd->has_ts); |
1182 | |
|
1183 | 0 | if (secs < 0) { |
1184 | 0 | secs = -secs; |
1185 | 0 | negative = true; |
1186 | 0 | } |
1187 | 0 | if (ts->nsecs >= 0) { |
1188 | 0 | nsecs = ts->nsecs; |
1189 | 0 | } else if (G_LIKELY(ts->nsecs != INT_MIN)) { |
1190 | | /* |
1191 | | * This isn't the smallest negative number that fits in 32 |
1192 | | * bits, so we can compute its negative and store it in a |
1193 | | * 32-bit unsigned int variable. |
1194 | | */ |
1195 | 0 | nsecs = -ts->nsecs; |
1196 | 0 | negative = true; |
1197 | 0 | } else { |
1198 | | /* |
1199 | | * -2147483648 is the smallest number that fits in a signed |
1200 | | * 2's complement 32-bit variable, and its negative doesn't |
1201 | | * fit in 32 bits. |
1202 | | * |
1203 | | * Just cast it to a 32-bit unsigned int value to set the |
1204 | | * 32-bit unsigned int variable to 2147483648. |
1205 | | * |
1206 | | * Note that, on platforms where both integers and long |
1207 | | * integers are 32-bit, such as 32-bit UN*Xes and both |
1208 | | * 32-bit *and* 64-bit Windows, making the variable in |
1209 | | * question a long will not avoid undefined behavior. |
1210 | | */ |
1211 | 0 | nsecs = (uint32_t)ts->nsecs; |
1212 | 0 | negative = true; |
1213 | 0 | } |
1214 | 0 | ptr = buf; |
1215 | 0 | remaining = COL_MAX_LEN; |
1216 | 0 | if (secs >= (60*60)) { |
1217 | 0 | num_bytes = snprintf(ptr, remaining, "%s%dh %2dm %2d", |
1218 | 0 | negative ? "- " : "", |
1219 | 0 | (int32_t) secs / (60 * 60), |
1220 | 0 | (int32_t) (secs / 60) % 60, |
1221 | 0 | (int32_t) secs % 60); |
1222 | 0 | } else if (secs >= 60) { |
1223 | 0 | num_bytes = snprintf(ptr, remaining, "%s%dm %2d", |
1224 | 0 | negative ? "- " : "", |
1225 | 0 | (int32_t) secs / 60, |
1226 | 0 | (int32_t) secs % 60); |
1227 | 0 | } else { |
1228 | 0 | num_bytes = snprintf(ptr, remaining, "%s%d", |
1229 | 0 | negative ? "- " : "", |
1230 | 0 | (int32_t) secs); |
1231 | 0 | } |
1232 | 0 | if (num_bytes < 0) { |
1233 | | /* |
1234 | | * That got an error. |
1235 | | * Not much else we can do. |
1236 | | */ |
1237 | 0 | snprintf(ptr, remaining, "snprintf() failed"); |
1238 | 0 | return; |
1239 | 0 | } |
1240 | 0 | if ((unsigned int)num_bytes >= remaining) { |
1241 | | /* |
1242 | | * That filled up or would have overflowed the buffer. |
1243 | | * Nothing more we can do. |
1244 | | */ |
1245 | 0 | return; |
1246 | 0 | } |
1247 | 0 | ptr += num_bytes; |
1248 | 0 | remaining -= num_bytes; |
1249 | |
|
1250 | 0 | tsprecision = get_frame_timestamp_precision(fd); |
1251 | 0 | if (tsprecision != 0) { |
1252 | | /* |
1253 | | * Append the fractional part. |
1254 | | */ |
1255 | 0 | num_bytes = format_fractional_part_nsecs(ptr, remaining, nsecs, decimal_point, tsprecision); |
1256 | 0 | if ((unsigned int)num_bytes >= remaining) { |
1257 | | /* |
1258 | | * That filled up or would have overflowed the buffer. |
1259 | | * Nothing more we can do. |
1260 | | */ |
1261 | 0 | return; |
1262 | 0 | } |
1263 | 0 | ptr += num_bytes; |
1264 | 0 | remaining -= num_bytes; |
1265 | 0 | } |
1266 | | |
1267 | | /* Append the "s" for seconds. */ |
1268 | 0 | snprintf(ptr, remaining, "s"); |
1269 | 0 | } |
1270 | | |
1271 | | static void |
1272 | | col_set_rel_time(const frame_data *fd, column_info *cinfo, const int col) |
1273 | 0 | { |
1274 | 0 | nstime_t del_rel_ts; |
1275 | |
|
1276 | 0 | if (!fd->has_ts) { |
1277 | 0 | cinfo->columns[col].col_buf[0] = '\0'; |
1278 | 0 | return; |
1279 | 0 | } |
1280 | | |
1281 | 0 | frame_delta_abs_time(cinfo->epan, fd, fd->frame_ref_num, &del_rel_ts); |
1282 | |
|
1283 | 0 | switch (timestamp_get_seconds_type()) { |
1284 | 0 | case TS_SECONDS_DEFAULT: |
1285 | 0 | set_time_seconds(fd, &del_rel_ts, cinfo->columns[col].col_buf); |
1286 | 0 | cinfo->col_expr.col_expr[col] = "frame.time_relative"; |
1287 | 0 | (void) g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->columns[col].col_buf,COL_MAX_LEN); |
1288 | 0 | break; |
1289 | 0 | case TS_SECONDS_HOUR_MIN_SEC: |
1290 | 0 | set_time_hour_min_sec(fd, &del_rel_ts, cinfo->columns[col].col_buf, col_decimal_point); |
1291 | 0 | cinfo->col_expr.col_expr[col] = "frame.time_relative"; |
1292 | 0 | set_time_seconds(fd, &del_rel_ts, cinfo->col_expr.col_expr_val[col]); |
1293 | 0 | break; |
1294 | 0 | default: |
1295 | 0 | ws_assert_not_reached(); |
1296 | 0 | } |
1297 | 0 | cinfo->columns[col].col_data = cinfo->columns[col].col_buf; |
1298 | 0 | } |
1299 | | |
1300 | | static void |
1301 | | col_set_delta_time(const frame_data *fd, column_info *cinfo, const int col) |
1302 | 0 | { |
1303 | 0 | nstime_t del_cap_ts; |
1304 | |
|
1305 | 0 | if (!fd->has_ts) { |
1306 | 0 | cinfo->columns[col].col_buf[0] = '\0'; |
1307 | 0 | return; |
1308 | 0 | } |
1309 | | |
1310 | 0 | frame_delta_abs_time(cinfo->epan, fd, fd->num - 1, &del_cap_ts); |
1311 | |
|
1312 | 0 | switch (timestamp_get_seconds_type()) { |
1313 | 0 | case TS_SECONDS_DEFAULT: |
1314 | 0 | set_time_seconds(fd, &del_cap_ts, cinfo->columns[col].col_buf); |
1315 | 0 | cinfo->col_expr.col_expr[col] = "frame.time_delta"; |
1316 | 0 | (void) g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->columns[col].col_buf,COL_MAX_LEN); |
1317 | 0 | break; |
1318 | 0 | case TS_SECONDS_HOUR_MIN_SEC: |
1319 | 0 | set_time_hour_min_sec(fd, &del_cap_ts, cinfo->columns[col].col_buf, col_decimal_point); |
1320 | 0 | cinfo->col_expr.col_expr[col] = "frame.time_delta"; |
1321 | 0 | set_time_seconds(fd, &del_cap_ts, cinfo->col_expr.col_expr_val[col]); |
1322 | 0 | break; |
1323 | 0 | default: |
1324 | 0 | ws_assert_not_reached(); |
1325 | 0 | } |
1326 | | |
1327 | 0 | cinfo->columns[col].col_data = cinfo->columns[col].col_buf; |
1328 | 0 | } |
1329 | | |
1330 | | static void |
1331 | | col_set_delta_time_dis(const frame_data *fd, column_info *cinfo, const int col) |
1332 | 0 | { |
1333 | 0 | nstime_t del_dis_ts; |
1334 | |
|
1335 | 0 | if (!fd->has_ts) { |
1336 | 0 | cinfo->columns[col].col_buf[0] = '\0'; |
1337 | 0 | return; |
1338 | 0 | } |
1339 | | |
1340 | 0 | frame_delta_abs_time(cinfo->epan, fd, fd->prev_dis_num, &del_dis_ts); |
1341 | |
|
1342 | 0 | switch (timestamp_get_seconds_type()) { |
1343 | 0 | case TS_SECONDS_DEFAULT: |
1344 | 0 | set_time_seconds(fd, &del_dis_ts, cinfo->columns[col].col_buf); |
1345 | 0 | cinfo->col_expr.col_expr[col] = "frame.time_delta_displayed"; |
1346 | 0 | (void) g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->columns[col].col_buf,COL_MAX_LEN); |
1347 | 0 | break; |
1348 | 0 | case TS_SECONDS_HOUR_MIN_SEC: |
1349 | 0 | set_time_hour_min_sec(fd, &del_dis_ts, cinfo->columns[col].col_buf, col_decimal_point); |
1350 | 0 | cinfo->col_expr.col_expr[col] = "frame.time_delta_displayed"; |
1351 | 0 | set_time_seconds(fd, &del_dis_ts, cinfo->col_expr.col_expr_val[col]); |
1352 | 0 | break; |
1353 | 0 | default: |
1354 | 0 | ws_assert_not_reached(); |
1355 | 0 | } |
1356 | | |
1357 | 0 | cinfo->columns[col].col_data = cinfo->columns[col].col_buf; |
1358 | 0 | } |
1359 | | |
1360 | | /* |
1361 | | * Time, without date. |
1362 | | */ |
1363 | | static void |
1364 | | set_abs_time(const frame_data *fd, char *buf, char *decimal_point, bool local) |
1365 | 0 | { |
1366 | 0 | struct tm tm, *tmp; |
1367 | 0 | char *ptr; |
1368 | 0 | size_t remaining; |
1369 | 0 | int num_bytes; |
1370 | 0 | int tsprecision; |
1371 | |
|
1372 | 0 | if (!fd->has_ts) { |
1373 | 0 | *buf = '\0'; |
1374 | 0 | return; |
1375 | 0 | } |
1376 | | |
1377 | 0 | ptr = buf; |
1378 | 0 | remaining = COL_MAX_LEN; |
1379 | |
|
1380 | 0 | if (local) |
1381 | 0 | tmp = ws_localtime_r(&fd->abs_ts.secs, &tm); |
1382 | 0 | else |
1383 | 0 | tmp = ws_gmtime_r(&fd->abs_ts.secs, &tm); |
1384 | 0 | if (tmp == NULL) { |
1385 | 0 | snprintf(ptr, remaining, "Not representable"); |
1386 | 0 | return; |
1387 | 0 | } |
1388 | | |
1389 | | /* Integral part. */ |
1390 | 0 | num_bytes = snprintf(ptr, remaining, "%02d:%02d:%02d", |
1391 | 0 | tmp->tm_hour, |
1392 | 0 | tmp->tm_min, |
1393 | 0 | tmp->tm_sec); |
1394 | 0 | if (num_bytes < 0) { |
1395 | | /* |
1396 | | * That got an error. |
1397 | | * Not much else we can do. |
1398 | | */ |
1399 | 0 | snprintf(ptr, remaining, "snprintf() failed"); |
1400 | 0 | return; |
1401 | 0 | } |
1402 | 0 | if ((unsigned int)num_bytes >= remaining) { |
1403 | | /* |
1404 | | * That filled up or would have overflowed the buffer. |
1405 | | * Nothing more we can do. |
1406 | | */ |
1407 | 0 | return; |
1408 | 0 | } |
1409 | 0 | ptr += num_bytes; |
1410 | 0 | remaining -= num_bytes; |
1411 | |
|
1412 | 0 | tsprecision = get_frame_timestamp_precision(fd); |
1413 | 0 | if (tsprecision != 0) { |
1414 | | /* |
1415 | | * Append the fractional part. |
1416 | | * Get the nsecs as a 32-bit unsigned value, as it should never |
1417 | | * be negative, so we treat it as unsigned. |
1418 | | */ |
1419 | 0 | format_fractional_part_nsecs(ptr, remaining, (uint32_t)fd->abs_ts.nsecs, decimal_point, tsprecision); |
1420 | 0 | } |
1421 | |
|
1422 | 0 | if (!local) { |
1423 | | /* |
1424 | | * format_fractional_part_nsecs, unlike snprintf, returns the |
1425 | | * number of bytes copied (not "would have copied"), so we |
1426 | | * don't check for overflow here. |
1427 | | */ |
1428 | 0 | ptr += num_bytes; |
1429 | 0 | remaining -= num_bytes; |
1430 | |
|
1431 | 0 | if (remaining == 1 && num_bytes > 0) { |
1432 | | /* |
1433 | | * If we copied a fractional part but there's only room |
1434 | | * for the terminating '\0', replace the last digit of |
1435 | | * the fractional part with the "Z". (Remaining is at |
1436 | | * least 1, otherwise we would have returned above.) |
1437 | | */ |
1438 | 0 | ptr--; |
1439 | 0 | remaining++; |
1440 | 0 | } |
1441 | 0 | (void)g_strlcpy(ptr, "Z", remaining); |
1442 | 0 | } |
1443 | 0 | } |
1444 | | |
1445 | | static void |
1446 | | col_set_abs_time(const frame_data *fd, column_info *cinfo, const int col) |
1447 | 0 | { |
1448 | 0 | set_abs_time(fd, cinfo->columns[col].col_buf, col_decimal_point, true); |
1449 | 0 | cinfo->col_expr.col_expr[col] = "frame.time"; |
1450 | 0 | (void) g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->columns[col].col_buf,COL_MAX_LEN); |
1451 | |
|
1452 | 0 | cinfo->columns[col].col_data = cinfo->columns[col].col_buf; |
1453 | 0 | } |
1454 | | |
1455 | | static void |
1456 | | col_set_utc_time(const frame_data *fd, column_info *cinfo, const int col) |
1457 | 0 | { |
1458 | 0 | set_abs_time(fd, cinfo->columns[col].col_buf, col_decimal_point, false); |
1459 | 0 | cinfo->col_expr.col_expr[col] = "frame.time"; |
1460 | 0 | (void) g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->columns[col].col_buf,COL_MAX_LEN); |
1461 | |
|
1462 | 0 | cinfo->columns[col].col_data = cinfo->columns[col].col_buf; |
1463 | 0 | } |
1464 | | |
1465 | | static bool |
1466 | | set_epoch_time(const frame_data *fd, char *buf) |
1467 | 0 | { |
1468 | 0 | if (!fd->has_ts) { |
1469 | 0 | buf[0] = '\0'; |
1470 | 0 | return false; |
1471 | 0 | } |
1472 | 0 | display_epoch_time(buf, COL_MAX_LEN, &fd->abs_ts, get_frame_timestamp_precision(fd)); |
1473 | 0 | return true; |
1474 | 0 | } |
1475 | | |
1476 | | static void |
1477 | | col_set_epoch_time(const frame_data *fd, column_info *cinfo, const int col) |
1478 | 0 | { |
1479 | 0 | if (set_epoch_time(fd, cinfo->columns[col].col_buf)) { |
1480 | 0 | cinfo->col_expr.col_expr[col] = "frame.time_delta"; |
1481 | 0 | (void) g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->columns[col].col_buf,COL_MAX_LEN); |
1482 | 0 | } |
1483 | 0 | cinfo->columns[col].col_data = cinfo->columns[col].col_buf; |
1484 | 0 | } |
1485 | | |
1486 | | void |
1487 | | set_fd_time(const epan_t *epan, frame_data *fd, char *buf) |
1488 | 0 | { |
1489 | |
|
1490 | 0 | switch (timestamp_get_type()) { |
1491 | 0 | case TS_ABSOLUTE: |
1492 | 0 | set_abs_time(fd, buf, col_decimal_point, true); |
1493 | 0 | break; |
1494 | | |
1495 | 0 | case TS_ABSOLUTE_WITH_YMD: |
1496 | 0 | set_abs_ymd_time(fd, buf, col_decimal_point, true); |
1497 | 0 | break; |
1498 | | |
1499 | 0 | case TS_ABSOLUTE_WITH_YDOY: |
1500 | 0 | set_abs_ydoy_time(fd, buf, col_decimal_point, true); |
1501 | 0 | break; |
1502 | | |
1503 | 0 | case TS_RELATIVE: |
1504 | 0 | if (fd->has_ts) { |
1505 | 0 | nstime_t del_rel_ts; |
1506 | |
|
1507 | 0 | frame_delta_abs_time(epan, fd, fd->frame_ref_num, &del_rel_ts); |
1508 | |
|
1509 | 0 | switch (timestamp_get_seconds_type()) { |
1510 | 0 | case TS_SECONDS_DEFAULT: |
1511 | 0 | set_time_seconds(fd, &del_rel_ts, buf); |
1512 | 0 | break; |
1513 | 0 | case TS_SECONDS_HOUR_MIN_SEC: |
1514 | 0 | set_time_seconds(fd, &del_rel_ts, buf); |
1515 | 0 | break; |
1516 | 0 | default: |
1517 | 0 | ws_assert_not_reached(); |
1518 | 0 | } |
1519 | 0 | } else { |
1520 | 0 | buf[0] = '\0'; |
1521 | 0 | } |
1522 | 0 | break; |
1523 | | |
1524 | 0 | case TS_DELTA: |
1525 | 0 | if (fd->has_ts) { |
1526 | 0 | nstime_t del_cap_ts; |
1527 | |
|
1528 | 0 | frame_delta_abs_time(epan, fd, fd->num - 1, &del_cap_ts); |
1529 | |
|
1530 | 0 | switch (timestamp_get_seconds_type()) { |
1531 | 0 | case TS_SECONDS_DEFAULT: |
1532 | 0 | set_time_seconds(fd, &del_cap_ts, buf); |
1533 | 0 | break; |
1534 | 0 | case TS_SECONDS_HOUR_MIN_SEC: |
1535 | 0 | set_time_hour_min_sec(fd, &del_cap_ts, buf, col_decimal_point); |
1536 | 0 | break; |
1537 | 0 | default: |
1538 | 0 | ws_assert_not_reached(); |
1539 | 0 | } |
1540 | 0 | } else { |
1541 | 0 | buf[0] = '\0'; |
1542 | 0 | } |
1543 | 0 | break; |
1544 | | |
1545 | 0 | case TS_DELTA_DIS: |
1546 | 0 | if (fd->has_ts) { |
1547 | 0 | nstime_t del_dis_ts; |
1548 | |
|
1549 | 0 | frame_delta_abs_time(epan, fd, fd->prev_dis_num, &del_dis_ts); |
1550 | |
|
1551 | 0 | switch (timestamp_get_seconds_type()) { |
1552 | 0 | case TS_SECONDS_DEFAULT: |
1553 | 0 | set_time_seconds(fd, &del_dis_ts, buf); |
1554 | 0 | break; |
1555 | 0 | case TS_SECONDS_HOUR_MIN_SEC: |
1556 | 0 | set_time_hour_min_sec(fd, &del_dis_ts, buf, col_decimal_point); |
1557 | 0 | break; |
1558 | 0 | default: |
1559 | 0 | ws_assert_not_reached(); |
1560 | 0 | } |
1561 | 0 | } else { |
1562 | 0 | buf[0] = '\0'; |
1563 | 0 | } |
1564 | 0 | break; |
1565 | | |
1566 | 0 | case TS_EPOCH: |
1567 | 0 | set_epoch_time(fd, buf); |
1568 | 0 | break; |
1569 | | |
1570 | 0 | case TS_UTC: |
1571 | 0 | set_abs_time(fd, buf, col_decimal_point, false); |
1572 | 0 | break; |
1573 | | |
1574 | 0 | case TS_UTC_WITH_YMD: |
1575 | 0 | set_abs_ymd_time(fd, buf, col_decimal_point, false); |
1576 | 0 | break; |
1577 | | |
1578 | 0 | case TS_UTC_WITH_YDOY: |
1579 | 0 | set_abs_ydoy_time(fd, buf, col_decimal_point, false); |
1580 | 0 | break; |
1581 | | |
1582 | 0 | case TS_NOT_SET: |
1583 | | /* code is missing for this case, but I don't know which [jmayer20051219] */ |
1584 | 0 | ws_assert_not_reached(); |
1585 | 0 | break; |
1586 | 0 | } |
1587 | 0 | } |
1588 | | |
1589 | | static void |
1590 | | col_set_cls_time(const frame_data *fd, column_info *cinfo, const int col) |
1591 | 0 | { |
1592 | 0 | switch (timestamp_get_type()) { |
1593 | 0 | case TS_ABSOLUTE: |
1594 | 0 | col_set_abs_time(fd, cinfo, col); |
1595 | 0 | break; |
1596 | | |
1597 | 0 | case TS_ABSOLUTE_WITH_YMD: |
1598 | 0 | col_set_abs_ymd_time(fd, cinfo, col); |
1599 | 0 | break; |
1600 | | |
1601 | 0 | case TS_ABSOLUTE_WITH_YDOY: |
1602 | 0 | col_set_abs_ydoy_time(fd, cinfo, col); |
1603 | 0 | break; |
1604 | | |
1605 | 0 | case TS_RELATIVE: |
1606 | 0 | col_set_rel_time(fd, cinfo, col); |
1607 | 0 | break; |
1608 | | |
1609 | 0 | case TS_DELTA: |
1610 | 0 | col_set_delta_time(fd, cinfo, col); |
1611 | 0 | break; |
1612 | | |
1613 | 0 | case TS_DELTA_DIS: |
1614 | 0 | col_set_delta_time_dis(fd, cinfo, col); |
1615 | 0 | break; |
1616 | | |
1617 | 0 | case TS_EPOCH: |
1618 | 0 | col_set_epoch_time(fd, cinfo, col); |
1619 | 0 | break; |
1620 | | |
1621 | 0 | case TS_UTC: |
1622 | 0 | col_set_utc_time(fd, cinfo, col); |
1623 | 0 | break; |
1624 | | |
1625 | 0 | case TS_UTC_WITH_YMD: |
1626 | 0 | col_set_utc_ymd_time(fd, cinfo, col); |
1627 | 0 | break; |
1628 | | |
1629 | 0 | case TS_UTC_WITH_YDOY: |
1630 | 0 | col_set_utc_ydoy_time(fd, cinfo, col); |
1631 | 0 | break; |
1632 | | |
1633 | 0 | case TS_NOT_SET: |
1634 | | /* code is missing for this case, but I don't know which [jmayer20051219] */ |
1635 | 0 | ws_assert_not_reached(); |
1636 | 0 | break; |
1637 | 0 | } |
1638 | 0 | } |
1639 | | |
1640 | | /* Set the format of the variable time format. */ |
1641 | | static void |
1642 | | col_set_fmt_time(const frame_data *fd, column_info *cinfo, const int fmt, const int col) |
1643 | 0 | { |
1644 | 0 | COL_CHECK_REF_TIME(fd, cinfo->columns[col].col_buf); |
1645 | |
|
1646 | 0 | switch (fmt) { |
1647 | 0 | case COL_CLS_TIME: |
1648 | 0 | col_set_cls_time(fd, cinfo, col); |
1649 | 0 | break; |
1650 | | |
1651 | 0 | case COL_ABS_TIME: |
1652 | 0 | col_set_abs_time(fd, cinfo, col); |
1653 | 0 | break; |
1654 | | |
1655 | 0 | case COL_ABS_YMD_TIME: |
1656 | 0 | col_set_abs_ymd_time(fd, cinfo, col); |
1657 | 0 | break; |
1658 | | |
1659 | 0 | case COL_ABS_YDOY_TIME: |
1660 | 0 | col_set_abs_ydoy_time(fd, cinfo, col); |
1661 | 0 | break; |
1662 | | |
1663 | 0 | case COL_REL_TIME: |
1664 | 0 | col_set_rel_time(fd, cinfo, col); |
1665 | 0 | break; |
1666 | | |
1667 | 0 | case COL_DELTA_TIME: |
1668 | 0 | col_set_delta_time(fd, cinfo, col); |
1669 | 0 | break; |
1670 | | |
1671 | 0 | case COL_DELTA_TIME_DIS: |
1672 | 0 | col_set_delta_time_dis(fd, cinfo, col); |
1673 | 0 | break; |
1674 | | |
1675 | 0 | case COL_UTC_TIME: |
1676 | 0 | col_set_utc_time(fd, cinfo, col); |
1677 | 0 | break; |
1678 | | |
1679 | 0 | case COL_UTC_YMD_TIME: |
1680 | 0 | col_set_utc_ymd_time(fd, cinfo, col); |
1681 | 0 | break; |
1682 | | |
1683 | 0 | case COL_UTC_YDOY_TIME: |
1684 | 0 | col_set_utc_ydoy_time(fd, cinfo, col); |
1685 | 0 | break; |
1686 | | |
1687 | 0 | default: |
1688 | 0 | ws_assert_not_reached(); |
1689 | 0 | break; |
1690 | 0 | } |
1691 | 0 | } |
1692 | | |
1693 | | /* --------------------------- */ |
1694 | | /* Set the given (relative) time to a column element. |
1695 | | * |
1696 | | * Used by dissectors to set the time in a column |
1697 | | * |
1698 | | * @param cinfo the current packet row |
1699 | | * @param el the column to use, e.g. COL_INFO |
1700 | | * @param ts the time to set in the column |
1701 | | * @param fieldname the fieldname to use for creating a filter (when |
1702 | | * applying/preparing/copying as filter) |
1703 | | */ |
1704 | | void |
1705 | | col_set_time(column_info *cinfo, const int el, const nstime_t *ts, const char *fieldname) |
1706 | 0 | { |
1707 | 0 | int col; |
1708 | 0 | col_item_t* col_item; |
1709 | |
|
1710 | 0 | if (!CHECK_COL(cinfo, el)) |
1711 | 0 | return; |
1712 | | |
1713 | | /** @todo TODO: We don't respect fd->ref_time (no way to access 'fd') |
1714 | | COL_CHECK_REF_TIME(fd, buf); |
1715 | | */ |
1716 | | |
1717 | 0 | for (col = cinfo->col_first[el]; col <= cinfo->col_last[el]; col++) { |
1718 | 0 | col_item = &cinfo->columns[col]; |
1719 | 0 | if (col_item->fmt_matx[el]) { |
1720 | 0 | display_signed_time(col_item->col_buf, COL_MAX_LEN, ts, get_default_timestamp_precision()); |
1721 | 0 | col_item->col_data = col_item->col_buf; |
1722 | 0 | cinfo->col_expr.col_expr[col] = fieldname; |
1723 | 0 | (void) g_strlcpy(cinfo->col_expr.col_expr_val[col],col_item->col_buf,COL_MAX_LEN); |
1724 | 0 | } |
1725 | 0 | } |
1726 | 0 | } |
1727 | | |
1728 | | static void |
1729 | | col_set_addr(packet_info *pinfo, const int col, const address *addr, const bool is_src, |
1730 | | const bool fill_col_exprs, const bool res) |
1731 | 0 | { |
1732 | 0 | const char *name; |
1733 | 0 | col_item_t* col_item = &pinfo->cinfo->columns[col]; |
1734 | |
|
1735 | 0 | if (addr->type == AT_NONE) { |
1736 | | /* No address, nothing to do */ |
1737 | 0 | return; |
1738 | 0 | } |
1739 | | |
1740 | 0 | if (res && (name = address_to_name(addr)) != NULL) |
1741 | 0 | col_item->col_data = name; |
1742 | 0 | else { |
1743 | 0 | col_item->col_data = col_item->col_buf; |
1744 | 0 | address_to_str_buf(addr, col_item->col_buf, COL_MAX_LEN); |
1745 | 0 | } |
1746 | |
|
1747 | 0 | if (!fill_col_exprs) |
1748 | 0 | return; |
1749 | | |
1750 | 0 | pinfo->cinfo->col_expr.col_expr[col] = address_type_column_filter_string(addr, is_src); |
1751 | | /* For address types that have a filter, create a string */ |
1752 | 0 | if (strlen(pinfo->cinfo->col_expr.col_expr[col]) > 0) { |
1753 | 0 | address_to_str_buf(addr, pinfo->cinfo->col_expr.col_expr_val[col], COL_MAX_LEN); |
1754 | 0 | } else { |
1755 | | /* For address types that don't, use the internal column FT_STRING hfi */ |
1756 | 0 | pinfo->cinfo->col_expr.col_expr[col] = proto_registrar_get_nth(col_item->hf_id)->abbrev; |
1757 | 0 | (void) g_strlcpy(pinfo->cinfo->col_expr.col_expr_val[col], pinfo->cinfo->columns[col].col_data, COL_MAX_LEN); |
1758 | 0 | } |
1759 | 0 | } |
1760 | | |
1761 | | /* ------------------------ */ |
1762 | | static void |
1763 | | col_set_port(packet_info *pinfo, const int col, const bool is_res, const bool is_src, const bool fill_col_exprs _U_) |
1764 | 0 | { |
1765 | 0 | uint32_t port; |
1766 | 0 | col_item_t* col_item = &pinfo->cinfo->columns[col]; |
1767 | |
|
1768 | 0 | if (is_src) |
1769 | 0 | port = pinfo->srcport; |
1770 | 0 | else |
1771 | 0 | port = pinfo->destport; |
1772 | | |
1773 | | /* TODO: Use fill_col_exprs */ |
1774 | |
|
1775 | 0 | switch (pinfo->ptype) { |
1776 | 0 | case PT_SCTP: |
1777 | 0 | if (is_res) |
1778 | 0 | (void) g_strlcpy(col_item->col_buf, sctp_port_to_display(pinfo->pool, port), COL_MAX_LEN); |
1779 | 0 | else |
1780 | 0 | uint32_to_str_buf(port, col_item->col_buf, COL_MAX_LEN); |
1781 | 0 | break; |
1782 | | |
1783 | 0 | case PT_TCP: |
1784 | 0 | uint32_to_str_buf(port, pinfo->cinfo->col_expr.col_expr_val[col], COL_MAX_LEN); |
1785 | 0 | if (is_res) |
1786 | 0 | (void) g_strlcpy(col_item->col_buf, tcp_port_to_display(pinfo->pool, port), COL_MAX_LEN); |
1787 | 0 | else |
1788 | 0 | (void) g_strlcpy(col_item->col_buf, pinfo->cinfo->col_expr.col_expr_val[col], COL_MAX_LEN); |
1789 | 0 | if (is_src) |
1790 | 0 | pinfo->cinfo->col_expr.col_expr[col] = "tcp.srcport"; |
1791 | 0 | else |
1792 | 0 | pinfo->cinfo->col_expr.col_expr[col] = "tcp.dstport"; |
1793 | 0 | break; |
1794 | | |
1795 | 0 | case PT_UDP: |
1796 | 0 | uint32_to_str_buf(port, pinfo->cinfo->col_expr.col_expr_val[col], COL_MAX_LEN); |
1797 | 0 | if (is_res) |
1798 | 0 | (void) g_strlcpy(col_item->col_buf, udp_port_to_display(pinfo->pool, port), COL_MAX_LEN); |
1799 | 0 | else |
1800 | 0 | (void) g_strlcpy(col_item->col_buf, pinfo->cinfo->col_expr.col_expr_val[col], COL_MAX_LEN); |
1801 | 0 | if (is_src) |
1802 | 0 | pinfo->cinfo->col_expr.col_expr[col] = "udp.srcport"; |
1803 | 0 | else |
1804 | 0 | pinfo->cinfo->col_expr.col_expr[col] = "udp.dstport"; |
1805 | 0 | break; |
1806 | | |
1807 | 0 | case PT_DDP: |
1808 | 0 | if (is_src) |
1809 | 0 | pinfo->cinfo->col_expr.col_expr[col] = "ddp.src_socket"; |
1810 | 0 | else |
1811 | 0 | pinfo->cinfo->col_expr.col_expr[col] = "ddp.dst_socket"; |
1812 | 0 | uint32_to_str_buf(port, pinfo->cinfo->col_expr.col_expr_val[col], COL_MAX_LEN); |
1813 | 0 | (void) g_strlcpy(col_item->col_buf, pinfo->cinfo->col_expr.col_expr_val[col], COL_MAX_LEN); |
1814 | 0 | break; |
1815 | | |
1816 | 0 | case PT_IPX: |
1817 | | /* XXX - resolve IPX socket numbers */ |
1818 | 0 | snprintf(col_item->col_buf, COL_MAX_LEN, "0x%04x", port); |
1819 | 0 | (void) g_strlcpy(pinfo->cinfo->col_expr.col_expr_val[col], col_item->col_buf,COL_MAX_LEN); |
1820 | 0 | if (is_src) |
1821 | 0 | pinfo->cinfo->col_expr.col_expr[col] = "ipx.src.socket"; |
1822 | 0 | else |
1823 | 0 | pinfo->cinfo->col_expr.col_expr[col] = "ipx.dst.socket"; |
1824 | 0 | break; |
1825 | | |
1826 | 0 | case PT_IDP: |
1827 | | /* XXX - resolve IDP socket numbers */ |
1828 | 0 | snprintf(col_item->col_buf, COL_MAX_LEN, "0x%04x", port); |
1829 | 0 | (void) g_strlcpy(pinfo->cinfo->col_expr.col_expr_val[col], col_item->col_buf,COL_MAX_LEN); |
1830 | 0 | if (is_src) |
1831 | 0 | pinfo->cinfo->col_expr.col_expr[col] = "idp.src.socket"; |
1832 | 0 | else |
1833 | 0 | pinfo->cinfo->col_expr.col_expr[col] = "idp.dst.socket"; |
1834 | 0 | break; |
1835 | | |
1836 | 0 | case PT_USB: |
1837 | | /* XXX - resolve USB endpoint numbers */ |
1838 | 0 | snprintf(col_item->col_buf, COL_MAX_LEN, "0x%08x", port); |
1839 | 0 | (void) g_strlcpy(pinfo->cinfo->col_expr.col_expr_val[col], col_item->col_buf,COL_MAX_LEN); |
1840 | 0 | if (is_src) |
1841 | 0 | pinfo->cinfo->col_expr.col_expr[col] = "usb.src.endpoint"; |
1842 | 0 | else |
1843 | 0 | pinfo->cinfo->col_expr.col_expr[col] = "usb.dst.endpoint"; |
1844 | 0 | break; |
1845 | | |
1846 | 0 | default: |
1847 | 0 | break; |
1848 | 0 | } |
1849 | 0 | col_item->col_data = col_item->col_buf; |
1850 | 0 | } |
1851 | | |
1852 | | bool |
1853 | | col_based_on_frame_data(column_info *cinfo, const int col) |
1854 | 0 | { |
1855 | 0 | ws_assert(cinfo); |
1856 | 0 | ws_assert(col < cinfo->num_cols); |
1857 | |
|
1858 | 0 | switch (cinfo->columns[col].col_fmt) { |
1859 | 0 | case COL_NUMBER: |
1860 | 0 | case COL_NUMBER_DIS: |
1861 | 0 | case COL_CLS_TIME: |
1862 | 0 | case COL_ABS_TIME: |
1863 | 0 | case COL_ABS_YMD_TIME: |
1864 | 0 | case COL_ABS_YDOY_TIME: |
1865 | 0 | case COL_UTC_TIME: |
1866 | 0 | case COL_UTC_YMD_TIME: |
1867 | 0 | case COL_UTC_YDOY_TIME: |
1868 | 0 | case COL_REL_TIME: |
1869 | 0 | case COL_DELTA_TIME: |
1870 | 0 | case COL_DELTA_TIME_DIS: |
1871 | 0 | case COL_PACKET_LENGTH: |
1872 | 0 | case COL_CUMULATIVE_BYTES: |
1873 | 0 | return true; |
1874 | | |
1875 | 0 | default: |
1876 | 0 | return false; |
1877 | 0 | } |
1878 | 0 | } |
1879 | | |
1880 | | void |
1881 | | col_fill_in_frame_data(const frame_data *fd, column_info *cinfo, const int col, const bool fill_col_exprs) |
1882 | 0 | { |
1883 | 0 | col_item_t* col_item = &cinfo->columns[col]; |
1884 | |
|
1885 | 0 | switch (col_item->col_fmt) { |
1886 | 0 | case COL_NUMBER: |
1887 | 0 | uint32_to_str_buf(fd->num, col_item->col_buf, COL_MAX_LEN); |
1888 | 0 | col_item->col_data = col_item->col_buf; |
1889 | 0 | break; |
1890 | | |
1891 | 0 | case COL_NUMBER_DIS: |
1892 | 0 | uint32_to_str_buf(fd->dis_num, col_item->col_buf, COL_MAX_LEN); |
1893 | 0 | col_item->col_data = col_item->col_buf; |
1894 | 0 | break; |
1895 | | |
1896 | 0 | case COL_CLS_TIME: |
1897 | 0 | case COL_ABS_TIME: |
1898 | 0 | case COL_ABS_YMD_TIME: |
1899 | 0 | case COL_ABS_YDOY_TIME: |
1900 | 0 | case COL_UTC_TIME: |
1901 | 0 | case COL_UTC_YMD_TIME: |
1902 | 0 | case COL_UTC_YDOY_TIME: |
1903 | 0 | case COL_REL_TIME: |
1904 | 0 | case COL_DELTA_TIME: |
1905 | 0 | case COL_DELTA_TIME_DIS: |
1906 | | /* TODO: Pass on fill_col_exprs */ |
1907 | 0 | col_set_fmt_time(fd, cinfo, col_item->col_fmt, col); |
1908 | 0 | break; |
1909 | | |
1910 | 0 | case COL_PACKET_LENGTH: |
1911 | 0 | uint32_to_str_buf(fd->pkt_len, col_item->col_buf, COL_MAX_LEN); |
1912 | 0 | col_item->col_data = col_item->col_buf; |
1913 | 0 | break; |
1914 | | |
1915 | 0 | case COL_CUMULATIVE_BYTES: |
1916 | 0 | uint32_to_str_buf(fd->cum_bytes, col_item->col_buf, COL_MAX_LEN); |
1917 | 0 | col_item->col_data = col_item->col_buf; |
1918 | 0 | break; |
1919 | | |
1920 | 0 | default: |
1921 | 0 | break; |
1922 | 0 | } |
1923 | | |
1924 | 0 | if (!fill_col_exprs) |
1925 | 0 | return; |
1926 | | |
1927 | 0 | switch (col_item->col_fmt) { |
1928 | 0 | case COL_NUMBER: |
1929 | 0 | cinfo->col_expr.col_expr[col] = "frame.number"; |
1930 | 0 | (void) g_strlcpy(cinfo->col_expr.col_expr_val[col], col_item->col_buf, COL_MAX_LEN); |
1931 | 0 | break; |
1932 | | |
1933 | 0 | case COL_CLS_TIME: |
1934 | 0 | case COL_ABS_TIME: |
1935 | 0 | case COL_ABS_YMD_TIME: |
1936 | 0 | case COL_ABS_YDOY_TIME: |
1937 | 0 | case COL_UTC_TIME: |
1938 | 0 | case COL_UTC_YMD_TIME: |
1939 | 0 | case COL_UTC_YDOY_TIME: |
1940 | 0 | case COL_REL_TIME: |
1941 | 0 | case COL_DELTA_TIME: |
1942 | 0 | case COL_DELTA_TIME_DIS: |
1943 | | /* Already handled above */ |
1944 | 0 | break; |
1945 | | |
1946 | 0 | case COL_PACKET_LENGTH: |
1947 | 0 | cinfo->col_expr.col_expr[col] = "frame.len"; |
1948 | 0 | (void) g_strlcpy(cinfo->col_expr.col_expr_val[col], col_item->col_buf, COL_MAX_LEN); |
1949 | 0 | break; |
1950 | | |
1951 | 0 | case COL_CUMULATIVE_BYTES: |
1952 | 0 | case COL_NUMBER_DIS: |
1953 | 0 | break; |
1954 | | |
1955 | 0 | default: |
1956 | 0 | break; |
1957 | 0 | } |
1958 | 0 | } |
1959 | | |
1960 | | void |
1961 | | col_fill_in(packet_info *pinfo, const bool fill_col_exprs, const bool fill_fd_colums) |
1962 | 0 | { |
1963 | 0 | int i; |
1964 | 0 | col_item_t* col_item; |
1965 | |
|
1966 | 0 | if (!pinfo->cinfo) |
1967 | 0 | return; |
1968 | | |
1969 | 0 | for (i = 0; i < pinfo->cinfo->num_cols; i++) { |
1970 | 0 | col_item = &pinfo->cinfo->columns[i]; |
1971 | 0 | if (col_based_on_frame_data(pinfo->cinfo, i)) { |
1972 | 0 | if (fill_fd_colums) |
1973 | 0 | col_fill_in_frame_data(pinfo->fd, pinfo->cinfo, i, fill_col_exprs); |
1974 | 0 | } else { |
1975 | 0 | switch (col_item->col_fmt) { |
1976 | 0 | case COL_DEF_SRC: |
1977 | 0 | case COL_RES_SRC: /* COL_DEF_SRC is currently just like COL_RES_SRC */ |
1978 | 0 | col_set_addr(pinfo, i, &pinfo->src, true, fill_col_exprs, true); |
1979 | 0 | break; |
1980 | | |
1981 | 0 | case COL_UNRES_SRC: |
1982 | 0 | col_set_addr(pinfo, i, &pinfo->src, true, fill_col_exprs, false); |
1983 | 0 | break; |
1984 | | |
1985 | 0 | case COL_DEF_DL_SRC: |
1986 | 0 | case COL_RES_DL_SRC: |
1987 | 0 | col_set_addr(pinfo, i, &pinfo->dl_src, true, fill_col_exprs, true); |
1988 | 0 | break; |
1989 | | |
1990 | 0 | case COL_UNRES_DL_SRC: |
1991 | 0 | col_set_addr(pinfo, i, &pinfo->dl_src, true, fill_col_exprs, false); |
1992 | 0 | break; |
1993 | | |
1994 | 0 | case COL_DEF_NET_SRC: |
1995 | 0 | case COL_RES_NET_SRC: |
1996 | 0 | col_set_addr(pinfo, i, &pinfo->net_src, true, fill_col_exprs, true); |
1997 | 0 | break; |
1998 | | |
1999 | 0 | case COL_UNRES_NET_SRC: |
2000 | 0 | col_set_addr(pinfo, i, &pinfo->net_src, true, fill_col_exprs, false); |
2001 | 0 | break; |
2002 | | |
2003 | 0 | case COL_DEF_DST: |
2004 | 0 | case COL_RES_DST: /* COL_DEF_DST is currently just like COL_RES_DST */ |
2005 | 0 | col_set_addr(pinfo, i, &pinfo->dst, false, fill_col_exprs, true); |
2006 | 0 | break; |
2007 | | |
2008 | 0 | case COL_UNRES_DST: |
2009 | 0 | col_set_addr(pinfo, i, &pinfo->dst, false, fill_col_exprs, false); |
2010 | 0 | break; |
2011 | | |
2012 | 0 | case COL_DEF_DL_DST: |
2013 | 0 | case COL_RES_DL_DST: |
2014 | 0 | col_set_addr(pinfo, i, &pinfo->dl_dst, false, fill_col_exprs, true); |
2015 | 0 | break; |
2016 | | |
2017 | 0 | case COL_UNRES_DL_DST: |
2018 | 0 | col_set_addr(pinfo, i, &pinfo->dl_dst, false, fill_col_exprs, false); |
2019 | 0 | break; |
2020 | | |
2021 | 0 | case COL_DEF_NET_DST: |
2022 | 0 | case COL_RES_NET_DST: |
2023 | 0 | col_set_addr(pinfo, i, &pinfo->net_dst, false, fill_col_exprs, true); |
2024 | 0 | break; |
2025 | | |
2026 | 0 | case COL_UNRES_NET_DST: |
2027 | 0 | col_set_addr(pinfo, i, &pinfo->net_dst, false, fill_col_exprs, false); |
2028 | 0 | break; |
2029 | | |
2030 | 0 | case COL_DEF_SRC_PORT: |
2031 | 0 | case COL_RES_SRC_PORT: /* COL_DEF_SRC_PORT is currently just like COL_RES_SRC_PORT */ |
2032 | 0 | col_set_port(pinfo, i, true, true, fill_col_exprs); |
2033 | 0 | break; |
2034 | | |
2035 | 0 | case COL_UNRES_SRC_PORT: |
2036 | 0 | col_set_port(pinfo, i, false, true, fill_col_exprs); |
2037 | 0 | break; |
2038 | | |
2039 | 0 | case COL_DEF_DST_PORT: |
2040 | 0 | case COL_RES_DST_PORT: /* COL_DEF_DST_PORT is currently just like COL_RES_DST_PORT */ |
2041 | 0 | col_set_port(pinfo, i, true, false, fill_col_exprs); |
2042 | 0 | break; |
2043 | | |
2044 | 0 | case COL_UNRES_DST_PORT: |
2045 | 0 | col_set_port(pinfo, i, false, false, fill_col_exprs); |
2046 | 0 | break; |
2047 | | |
2048 | 0 | case COL_CUSTOM: |
2049 | | /* Formatting handled by col_custom_set_edt() / col_custom_get_filter() */ |
2050 | 0 | break; |
2051 | | |
2052 | 0 | case NUM_COL_FMTS: /* keep compiler happy - shouldn't get here */ |
2053 | 0 | ws_assert_not_reached(); |
2054 | 0 | break; |
2055 | 0 | default: |
2056 | 0 | if (col_item->col_fmt >= NUM_COL_FMTS) { |
2057 | 0 | ws_assert_not_reached(); |
2058 | 0 | } |
2059 | | /* |
2060 | | * Formatting handled by expert.c (COL_EXPERT), or individual |
2061 | | * dissectors. Fill in from the text using the internal hfid. |
2062 | | */ |
2063 | 0 | if (fill_col_exprs) { |
2064 | 0 | pinfo->cinfo->col_expr.col_expr[i] = proto_registrar_get_nth(col_item->hf_id)->abbrev; |
2065 | 0 | (void) g_strlcpy(pinfo->cinfo->col_expr.col_expr_val[i], pinfo->cinfo->columns[i].col_data, (col_item->col_fmt == COL_INFO) ? COL_MAX_INFO_LEN : COL_MAX_LEN); |
2066 | 0 | } |
2067 | 0 | break; |
2068 | 0 | } |
2069 | 0 | } |
2070 | 0 | } |
2071 | 0 | } |
2072 | | |
2073 | | /* |
2074 | | * Fill in columns if we got an error reading the packet. |
2075 | | * We set most columns to "???", fill in columns that don't need data read |
2076 | | * from the file, and set the Info column to an error message. |
2077 | | */ |
2078 | | void |
2079 | | col_fill_in_error(column_info *cinfo, frame_data *fdata, const bool fill_col_exprs, const bool fill_fd_colums) |
2080 | 0 | { |
2081 | 0 | int i; |
2082 | 0 | col_item_t* col_item; |
2083 | |
|
2084 | 0 | if (!cinfo) |
2085 | 0 | return; |
2086 | | |
2087 | 0 | for (i = 0; i < cinfo->num_cols; i++) { |
2088 | 0 | col_item = &cinfo->columns[i]; |
2089 | 0 | if (col_based_on_frame_data(cinfo, i)) { |
2090 | 0 | if (fill_fd_colums) |
2091 | 0 | col_fill_in_frame_data(fdata, cinfo, i, fill_col_exprs); |
2092 | 0 | } else if (col_item->col_fmt == COL_INFO) { |
2093 | | /* XXX - say more than this */ |
2094 | 0 | col_item->col_data = "Read error"; |
2095 | 0 | } else { |
2096 | 0 | if (col_item->col_fmt >= NUM_COL_FMTS) { |
2097 | 0 | ws_assert_not_reached(); |
2098 | 0 | } |
2099 | | /* |
2100 | | * No dissection was done, and these columns are set as the |
2101 | | * result of the dissection, so.... |
2102 | | */ |
2103 | 0 | col_item->col_data = "???"; |
2104 | 0 | break; |
2105 | 0 | } |
2106 | 0 | } |
2107 | 0 | } |
2108 | | |
2109 | 0 | bool col_data_changed(void) { |
2110 | 0 | bool cur_cdc = col_data_changed_; |
2111 | 0 | col_data_changed_ = false; |
2112 | 0 | return cur_cdc; |
2113 | 0 | } |
2114 | | |
2115 | | void |
2116 | | col_register_protocol(void) |
2117 | 14 | { |
2118 | | /* This gets called by proto_init() before column_register_fields() |
2119 | | * gets called by the preference modules actually getting registered. |
2120 | | */ |
2121 | 14 | if (proto_cols <= 0) { |
2122 | 14 | proto_cols = proto_get_id_by_filter_name("_ws.col"); |
2123 | 14 | } |
2124 | 14 | if (proto_cols <= 0) { |
2125 | 14 | proto_cols = proto_register_protocol("Wireshark Columns", "Columns", "_ws.col"); |
2126 | 14 | } |
2127 | 14 | static int *ett[] = { |
2128 | 14 | &ett_cols |
2129 | 14 | }; |
2130 | 14 | proto_register_subtree_array(ett, G_N_ELEMENTS(ett)); |
2131 | 14 | } |
2132 | | |
2133 | | void |
2134 | | col_dissect(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) |
2135 | 103k | { |
2136 | 103k | proto_item *ti; |
2137 | 103k | proto_tree *col_tree; |
2138 | | |
2139 | 103k | column_info *cinfo = pinfo->cinfo; |
2140 | | |
2141 | 103k | if (!cinfo) { |
2142 | 103k | return; |
2143 | 103k | } |
2144 | | |
2145 | 0 | if (proto_field_is_referenced(tree, proto_cols)) { |
2146 | | // XXX: Needed if we also create _ws.col.custom |
2147 | | //col_custom_set(tree, cinfo); |
2148 | 0 | col_fill_in(pinfo, false, true); |
2149 | 0 | ti = proto_tree_add_item(tree, proto_cols, tvb, 0, 0, ENC_NA); |
2150 | 0 | proto_item_set_hidden(ti); |
2151 | 0 | col_tree = proto_item_add_subtree(ti, ett_cols); |
2152 | 0 | for (int i = 0; i < cinfo->num_cols; ++i) { |
2153 | 0 | if (cinfo->columns[i].hf_id != -1) { |
2154 | 0 | if (cinfo->columns[i].col_fmt == COL_CUSTOM) { |
2155 | 0 | ti = proto_tree_add_string_format(col_tree, cinfo->columns[i].hf_id, tvb, 0, 0, get_column_text(cinfo, i), "%s: %s", get_column_title(i), get_column_text(cinfo, i)); |
2156 | 0 | } else { |
2157 | 0 | ti = proto_tree_add_string(col_tree, cinfo->columns[i].hf_id, tvb, 0, 0, get_column_text(cinfo, i)); |
2158 | 0 | } |
2159 | 0 | proto_item_set_hidden(ti); |
2160 | 0 | } |
2161 | 0 | } |
2162 | 0 | } |
2163 | 0 | } |
2164 | | |
2165 | | /* |
2166 | | * Editor modelines |
2167 | | * |
2168 | | * Local Variables: |
2169 | | * c-basic-offset: 2 |
2170 | | * tab-width: 8 |
2171 | | * indent-tabs-mode: nil |
2172 | | * End: |
2173 | | * |
2174 | | * ex: set shiftwidth=2 tabstop=8 expandtab: |
2175 | | * :indentSize=2:tabSize=8:noTabs=true: |
2176 | | */ |