/src/wireshark/epan/to_str.c
Line | Count | Source |
1 | | /* to_str.c |
2 | | * Routines for utilities to convert various other types to strings. |
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 <glib.h> |
17 | | |
18 | | #include <epan/wmem_scopes.h> |
19 | | #include "proto.h" |
20 | | #include "to_str.h" |
21 | | #include "strutil.h" |
22 | | #include <wsutil/pint.h> |
23 | | #include <wsutil/utf8_entities.h> |
24 | | |
25 | | /* |
26 | | * If a user _does_ pass in a too-small buffer, this is probably |
27 | | * going to be too long to fit. However, even a partial string |
28 | | * starting with "[Buf" should provide enough of a clue to be |
29 | | * useful. |
30 | | */ |
31 | 0 | #define BUF_TOO_SMALL_ERR "[Buffer too small]" |
32 | | |
33 | | static const char mon_names[12][4] = { |
34 | | "Jan", |
35 | | "Feb", |
36 | | "Mar", |
37 | | "Apr", |
38 | | "May", |
39 | | "Jun", |
40 | | "Jul", |
41 | | "Aug", |
42 | | "Sep", |
43 | | "Oct", |
44 | | "Nov", |
45 | | "Dec" |
46 | | }; |
47 | | |
48 | | static const char * |
49 | | get_zonename(struct tm *tmp) |
50 | 3.19k | { |
51 | | #if defined(_WIN32) |
52 | | /* |
53 | | * The strings in _tzname[] are encoded using the code page |
54 | | * for the current C-language locale. |
55 | | * |
56 | | * On Windows, all Wireshark programs set that code page |
57 | | * to the UTF-8 code page by calling |
58 | | * |
59 | | * setlocale(LC_ALL, ".UTF-8"); |
60 | | * |
61 | | * so the strings in _tzname[] are UTF-8 strings, and we can |
62 | | * just return them. |
63 | | * |
64 | | * (Note: the above does *not* mean we've set any code pages |
65 | | * *other* than the one used by the Visual Studio C runtime |
66 | | * to UTF-8, so don't assume, for example, that the "ANSI" |
67 | | * versions of Windows APIs will take UTF-8 strings, or that |
68 | | * non-UTF-16 output to the console will be treated as UTF-8. |
69 | | * Setting those other code pages can cause problems, especially |
70 | | * on pre-Windows 10 or older Windows 10 releases.) |
71 | | */ |
72 | | return _tzname[tmp->tm_isdst]; |
73 | | #else |
74 | | /* |
75 | | * UN*X. |
76 | | * |
77 | | * If we have tm_zone in struct tm, use that. |
78 | | * Otherwise, if we have tzname[], use it, otherwise just |
79 | | * say "we don't know. |
80 | | */ |
81 | 3.19k | # if defined(HAVE_STRUCT_TM_TM_ZONE) |
82 | 3.19k | return tmp->tm_zone; |
83 | | # else /* HAVE_STRUCT_TM_TM_ZONE */ |
84 | | if ((tmp->tm_isdst != 0) && (tmp->tm_isdst != 1)) { |
85 | | return "???"; |
86 | | } |
87 | | # if defined(HAVE_TZNAME) |
88 | | return tzname[tmp->tm_isdst]; |
89 | | # else |
90 | | return tmp->tm_isdst ? "?DT" : "?ST"; |
91 | | # endif /* HAVE_TZNAME */ |
92 | | # endif /* HAVE_STRUCT_TM_TM_ZONE */ |
93 | 3.19k | #endif /* _WIN32 */ |
94 | 3.19k | } |
95 | | |
96 | | static struct tm * |
97 | | get_fmt_broken_down_time(field_display_e fmt, const time_t *secs) |
98 | 3.79k | { |
99 | 3.79k | switch (fmt) { |
100 | 578 | case ABSOLUTE_TIME_UTC: |
101 | 578 | case ABSOLUTE_TIME_DOY_UTC: |
102 | 602 | case ABSOLUTE_TIME_NTP_UTC: |
103 | 602 | return gmtime(secs); |
104 | 3.19k | case ABSOLUTE_TIME_LOCAL: |
105 | 3.19k | return localtime(secs); |
106 | 0 | default: |
107 | 0 | break; |
108 | 3.79k | } |
109 | 0 | ws_assert_not_reached(); |
110 | 0 | } |
111 | | |
112 | | static char * |
113 | | snprint_abs_time_secs(wmem_allocator_t *scope, |
114 | | field_display_e fmt, struct tm *tmp, |
115 | | const char *nsecs_str, const char *tzone_sep, |
116 | | const char *tzone_str, bool add_quotes) |
117 | 3.79k | { |
118 | 3.79k | char *buf; |
119 | | |
120 | 3.79k | switch (fmt) { |
121 | 0 | case ABSOLUTE_TIME_DOY_UTC: |
122 | 0 | buf = wmem_strdup_printf(scope, |
123 | 0 | "%s%04d/%03d:%02d:%02d:%02d%s%s%s%s", |
124 | 0 | add_quotes ? "\"" : "", |
125 | 0 | tmp->tm_year + 1900, |
126 | 0 | tmp->tm_yday + 1, |
127 | 0 | tmp->tm_hour, |
128 | 0 | tmp->tm_min, |
129 | 0 | tmp->tm_sec, |
130 | 0 | nsecs_str, |
131 | 0 | tzone_sep, |
132 | 0 | tzone_str, |
133 | 0 | add_quotes ? "\"" : ""); |
134 | 0 | break; |
135 | 24 | case ABSOLUTE_TIME_NTP_UTC: /* FALLTHROUGH */ |
136 | 602 | case ABSOLUTE_TIME_UTC: /* FALLTHROUGH */ |
137 | 3.79k | case ABSOLUTE_TIME_LOCAL: |
138 | 3.79k | buf = wmem_strdup_printf(scope, |
139 | 3.79k | "%s%s %2d, %d %02d:%02d:%02d%s%s%s%s", |
140 | 3.79k | add_quotes ? "\"" : "", |
141 | 3.79k | mon_names[tmp->tm_mon], |
142 | 3.79k | tmp->tm_mday, |
143 | 3.79k | tmp->tm_year + 1900, |
144 | 3.79k | tmp->tm_hour, |
145 | 3.79k | tmp->tm_min, |
146 | 3.79k | tmp->tm_sec, |
147 | 3.79k | nsecs_str, |
148 | 3.79k | tzone_sep, |
149 | 3.79k | tzone_str, |
150 | 3.79k | add_quotes ? "\"" : ""); |
151 | 3.79k | break; |
152 | 0 | default: |
153 | 0 | ws_assert_not_reached(); |
154 | 3.79k | } |
155 | 3.79k | return buf; |
156 | 3.79k | } |
157 | | |
158 | | static char * |
159 | | snprint_abs_time_iso8601(wmem_allocator_t *scope, |
160 | | field_display_e fmt, struct tm *tmp, |
161 | | const char *nsecs_str, int flags) |
162 | 0 | { |
163 | 0 | char *buf; |
164 | 0 | bool add_quotes = flags & ABS_TIME_TO_STR_ADD_DQUOTES; |
165 | 0 | bool add_zone = flags & ABS_TIME_TO_STR_SHOW_ZONE; |
166 | 0 | if (fmt != ABSOLUTE_TIME_LOCAL && flags & ABS_TIME_TO_STR_SHOW_UTC_ONLY) { |
167 | 0 | add_zone = true; |
168 | 0 | } |
169 | |
|
170 | 0 | switch (fmt) { |
171 | 0 | case ABSOLUTE_TIME_DOY_UTC: |
172 | | /* ISO 8601 4.1.3 Ordinal date */ |
173 | 0 | buf = wmem_strdup_printf(scope, |
174 | 0 | "%s%04d-%03dT%02d:%02d:%02d%s%s%s", |
175 | 0 | add_quotes ? "\"" : "", |
176 | 0 | tmp->tm_year + 1900, |
177 | 0 | tmp->tm_yday + 1, |
178 | 0 | tmp->tm_hour, |
179 | 0 | tmp->tm_min, |
180 | 0 | tmp->tm_sec, |
181 | 0 | nsecs_str, |
182 | 0 | add_zone ? "Z" : "", |
183 | 0 | add_quotes ? "\"" : ""); |
184 | 0 | break; |
185 | 0 | case ABSOLUTE_TIME_NTP_UTC: /* FALLTHROUGH */ |
186 | 0 | case ABSOLUTE_TIME_UTC: /* FALLTHROUGH */ |
187 | 0 | buf = wmem_strdup_printf(scope, |
188 | 0 | "%s%d-%02d-%02dT%02d:%02d:%02d%s%s%s", |
189 | 0 | add_quotes ? "\"" : "", |
190 | 0 | tmp->tm_year + 1900, |
191 | 0 | tmp->tm_mon + 1, |
192 | 0 | tmp->tm_mday, |
193 | 0 | tmp->tm_hour, |
194 | 0 | tmp->tm_min, |
195 | 0 | tmp->tm_sec, |
196 | 0 | nsecs_str, |
197 | 0 | add_zone ? "Z" : "", |
198 | 0 | add_quotes ? "\"" : ""); |
199 | 0 | break; |
200 | 0 | case ABSOLUTE_TIME_LOCAL: |
201 | 0 | { |
202 | 0 | char zone_buf[8] = ""; |
203 | 0 | if (add_zone) { |
204 | | /* |
205 | | * C11 requires that strftime supports %z; unfortunately |
206 | | * it doesn't put the ':' in the timezone as strict ISO 8601 |
207 | | * would require (no mixing "basic" and "extended" formats.) |
208 | | * XXX - Should we add in the ":"? |
209 | | * |
210 | | * We could also use _get_timezone on Windows, or on Linux and |
211 | | * *BSD tm_gmtoff (if HAVE_STRUCT_TM_TM_GMTOFF). |
212 | | */ |
213 | 0 | strftime(zone_buf, 8, "%z", tmp); |
214 | 0 | } |
215 | 0 | buf = wmem_strdup_printf(scope, |
216 | 0 | "%s%d-%02d-%02dT%02d:%02d:%02d%s%s%s", |
217 | 0 | add_quotes ? "\"" : "", |
218 | 0 | tmp->tm_year + 1900, |
219 | 0 | tmp->tm_mon + 1, |
220 | 0 | tmp->tm_mday, |
221 | 0 | tmp->tm_hour, |
222 | 0 | tmp->tm_min, |
223 | 0 | tmp->tm_sec, |
224 | 0 | nsecs_str, |
225 | 0 | zone_buf, |
226 | 0 | add_quotes ? "\"" : ""); |
227 | 0 | break; |
228 | 0 | } |
229 | 0 | default: |
230 | 0 | ws_assert_not_reached(); |
231 | 0 | } |
232 | 0 | return buf; |
233 | 0 | } |
234 | | |
235 | | char * |
236 | | abs_time_to_str_ex(wmem_allocator_t *scope, const nstime_t *abs_time, field_display_e fmt, |
237 | | int flags) |
238 | 3.79k | { |
239 | 3.79k | struct tm *tmp; |
240 | 3.79k | char buf_nsecs[32]; |
241 | 3.79k | const char *tzone_sep, *tzone_str; |
242 | | |
243 | 3.79k | if (fmt == BASE_NONE) |
244 | 0 | fmt = ABSOLUTE_TIME_LOCAL; |
245 | | |
246 | 3.79k | ws_assert(FIELD_DISPLAY_IS_ABSOLUTE_TIME(fmt)); |
247 | | |
248 | 3.79k | if (fmt == ABSOLUTE_TIME_UNIX) { |
249 | 0 | return abs_time_to_unix_str(scope, abs_time); |
250 | 0 | } |
251 | | |
252 | 3.79k | if (fmt == ABSOLUTE_TIME_NTP_UTC && abs_time->secs == 0 && |
253 | 2 | (abs_time->nsecs == 0 || abs_time->nsecs == INT_MAX)) { |
254 | 2 | return wmem_strdup(scope, "NULL"); |
255 | 2 | } |
256 | | |
257 | 3.79k | tmp = get_fmt_broken_down_time(fmt, &abs_time->secs); |
258 | 3.79k | if (tmp == NULL) { |
259 | 0 | return wmem_strdup(scope, "Not representable"); |
260 | 0 | } |
261 | | |
262 | 3.79k | *buf_nsecs = '\0'; |
263 | 3.79k | if (abs_time->nsecs != INT_MAX) { |
264 | 698 | snprintf(buf_nsecs, sizeof(buf_nsecs), ".%09d", abs_time->nsecs); |
265 | 698 | } |
266 | | |
267 | 3.79k | if (flags & ABS_TIME_TO_STR_ISO8601) { |
268 | 0 | return snprint_abs_time_iso8601(scope, fmt, tmp, buf_nsecs, flags); |
269 | 0 | } |
270 | | |
271 | 3.79k | tzone_sep = ""; |
272 | 3.79k | tzone_str = ""; |
273 | 3.79k | if (flags & ABS_TIME_TO_STR_SHOW_ZONE || flags & ABS_TIME_TO_STR_SHOW_UTC_ONLY) { |
274 | 3.79k | switch (fmt) { |
275 | | |
276 | 578 | case ABSOLUTE_TIME_UTC: |
277 | 578 | case ABSOLUTE_TIME_DOY_UTC: |
278 | 602 | case ABSOLUTE_TIME_NTP_UTC: |
279 | 602 | tzone_sep = " "; |
280 | 602 | tzone_str = "UTC"; |
281 | 602 | break; |
282 | | |
283 | 3.19k | case ABSOLUTE_TIME_LOCAL: |
284 | 3.19k | if (flags & ABS_TIME_TO_STR_SHOW_ZONE) { |
285 | 3.19k | tzone_sep = " "; |
286 | 3.19k | tzone_str = get_zonename(tmp); |
287 | 3.19k | } |
288 | 3.19k | break; |
289 | 0 | default: |
290 | 0 | ws_assert_not_reached(); |
291 | 3.79k | } |
292 | 3.79k | } |
293 | | |
294 | 3.79k | return snprint_abs_time_secs(scope, fmt, tmp, buf_nsecs, tzone_sep, tzone_str, flags & ABS_TIME_TO_STR_ADD_DQUOTES); |
295 | 3.79k | } |
296 | | |
297 | | char * |
298 | | abs_time_secs_to_str_ex(wmem_allocator_t *scope, const time_t abs_time_secs, field_display_e fmt, |
299 | | int flags) |
300 | 3.09k | { |
301 | 3.09k | nstime_t abs_time; |
302 | | |
303 | 3.09k | nstime_set_unset(&abs_time); |
304 | 3.09k | abs_time.secs = abs_time_secs; |
305 | 3.09k | return abs_time_to_str_ex(scope, &abs_time, fmt, flags); |
306 | 3.09k | } |
307 | | |
308 | 101k | #define PLURALIZE(n) (((n) > 1) ? "s" : "") |
309 | 78.5k | #define COMMA(do_it) ((do_it) ? ", " : "") |
310 | | |
311 | | /* |
312 | | * Maximum length of a string showing days/hours/minutes/seconds. |
313 | | * (Does not include the terminating '\0'.) |
314 | | * Includes space for a '-' sign for any negative components. |
315 | | * -123456789012345 days, 12 hours, 12 minutes, 12.123 seconds |
316 | | */ |
317 | 29.1k | #define TIME_SECS_LEN (16+1+4+2+2+5+2+2+7+2+2+7+4) |
318 | | |
319 | | /* |
320 | | * Convert an unsigned value in seconds and fractions of a second to a string, |
321 | | * giving time in days, hours, minutes, and seconds, and put the result |
322 | | * into a buffer. |
323 | | * "is_nsecs" says that "frac" is nanoseconds if true and milliseconds |
324 | | * if false. |
325 | | */ |
326 | | static void |
327 | | unsigned_time_secs_to_str_buf(uint64_t time_val, const uint32_t frac, |
328 | | const bool is_nsecs, wmem_strbuf_t *buf) |
329 | 29.1k | { |
330 | 29.1k | uint64_t hours, mins, secs; |
331 | 29.1k | bool do_comma = false; |
332 | | |
333 | 29.1k | secs = time_val % 60; |
334 | 29.1k | time_val /= 60; |
335 | 29.1k | mins = time_val % 60; |
336 | 29.1k | time_val /= 60; |
337 | 29.1k | hours = time_val % 24; |
338 | 29.1k | time_val /= 24; |
339 | | |
340 | 29.1k | if (time_val != 0) { |
341 | 23.3k | wmem_strbuf_append_printf(buf, "%" PRIu64 " day%s", time_val, PLURALIZE(time_val)); |
342 | 23.3k | do_comma = true; |
343 | 23.3k | } |
344 | 29.1k | if (hours != 0) { |
345 | 24.0k | wmem_strbuf_append_printf(buf, "%s%" PRIu64 " hour%s", COMMA(do_comma), hours, PLURALIZE(hours)); |
346 | 24.0k | do_comma = true; |
347 | 24.0k | } |
348 | 29.1k | if (mins != 0) { |
349 | 27.3k | wmem_strbuf_append_printf(buf, "%s%" PRIu64 " minute%s", COMMA(do_comma), mins, PLURALIZE(mins)); |
350 | 27.3k | do_comma = true; |
351 | 27.3k | } |
352 | 29.1k | if (secs != 0) { |
353 | 27.0k | if (frac != 0) { |
354 | 432 | if (is_nsecs) |
355 | 8 | wmem_strbuf_append_printf(buf, "%s%" PRIu64 ".%09u seconds", COMMA(do_comma), secs, frac); |
356 | 424 | else |
357 | 424 | wmem_strbuf_append_printf(buf, "%s%" PRIu64 ".%03u seconds", COMMA(do_comma), secs, frac); |
358 | 432 | } else |
359 | 26.6k | wmem_strbuf_append_printf(buf, "%s%" PRIu64 " second%s", COMMA(do_comma), secs, PLURALIZE(secs)); |
360 | 27.0k | } else if (frac != 0) { |
361 | 42 | if (is_nsecs) { |
362 | 0 | if (frac < 1000) { |
363 | 0 | wmem_strbuf_append_printf(buf, "%s%u nanosecond%s", COMMA(do_comma), frac, PLURALIZE(frac)); |
364 | 0 | } else if (frac < 1000000) { |
365 | 0 | wmem_strbuf_append_printf(buf, "%s%u.%03u microseconds", COMMA(do_comma), frac / 1000, frac % 1000); |
366 | 0 | } else { |
367 | 0 | wmem_strbuf_append_printf(buf, "%s%u.%06u milliseconds", COMMA(do_comma), frac / 1000000, frac % 1000000); |
368 | 0 | } |
369 | 42 | } else { |
370 | 42 | wmem_strbuf_append_printf(buf, "%s%u millisecond%s", COMMA(do_comma), frac, PLURALIZE(frac)); |
371 | 42 | } |
372 | 42 | } |
373 | 29.1k | } |
374 | | |
375 | | char * |
376 | | unsigned_time_secs_to_str(wmem_allocator_t *scope, const uint32_t time_val) |
377 | 27.3k | { |
378 | 27.3k | wmem_strbuf_t *buf; |
379 | | |
380 | 27.3k | if (time_val == 0) { |
381 | 1.91k | return wmem_strdup(scope, "0 seconds"); |
382 | 1.91k | } |
383 | | |
384 | 25.4k | buf = wmem_strbuf_new_sized(scope, TIME_SECS_LEN+1); |
385 | | |
386 | 25.4k | unsigned_time_secs_to_str_buf(time_val, 0, false, buf); |
387 | | |
388 | 25.4k | return wmem_strbuf_finalize(buf); |
389 | 27.3k | } |
390 | | |
391 | | /* |
392 | | * Convert a signed value in seconds and fractions of a second to a string, |
393 | | * giving time in days, hours, minutes, and seconds, and put the result |
394 | | * into a buffer. |
395 | | * "is_nsecs" says that "frac" is nanoseconds if true and milliseconds |
396 | | * if false. |
397 | | */ |
398 | | static void |
399 | | signed_time_secs_to_str_buf(int64_t time_val, const uint32_t frac, |
400 | | const bool is_nsecs, wmem_strbuf_t *buf) |
401 | 3.69k | { |
402 | 3.69k | if(time_val < 0){ |
403 | 170 | wmem_strbuf_append_printf(buf, "-"); |
404 | 170 | if(time_val == INT64_MIN) { |
405 | | /* |
406 | | * You can't fit time_val's absolute value into |
407 | | * a 64-bit signed integer. Just directly |
408 | | * pass UINT64_MAX, which is its absolute |
409 | | * value, directly to unsigned_time_secs_to_str_buf(). |
410 | | * |
411 | | * (XXX - does ISO C guarantee that -(-2^n), |
412 | | * when calculated and cast to an n-bit unsigned |
413 | | * integer type, will have the value 2^n?) |
414 | | */ |
415 | 0 | unsigned_time_secs_to_str_buf(UINT64_MAX, frac, |
416 | 0 | is_nsecs, buf); |
417 | 170 | } else { |
418 | | /* |
419 | | * We now know -secs will fit into a uint32_t; |
420 | | * negate it and pass that to |
421 | | * unsigned_time_secs_to_str_buf(). |
422 | | */ |
423 | 170 | unsigned_time_secs_to_str_buf(-time_val, frac, is_nsecs, buf); |
424 | 170 | } |
425 | 170 | } else |
426 | 3.52k | unsigned_time_secs_to_str_buf(time_val, frac, is_nsecs, buf); |
427 | 3.69k | } |
428 | | |
429 | | char * |
430 | | signed_time_secs_to_str(wmem_allocator_t *scope, const int32_t time_val) |
431 | 5.61k | { |
432 | 5.61k | wmem_strbuf_t *buf; |
433 | | |
434 | 5.61k | if (time_val == 0) { |
435 | 2.38k | return wmem_strdup(scope, "0 seconds"); |
436 | 2.38k | } |
437 | | |
438 | 3.22k | buf = wmem_strbuf_new_sized(scope, TIME_SECS_LEN+1); |
439 | | |
440 | 3.22k | signed_time_secs_to_str_buf(time_val, 0, false, buf); |
441 | | |
442 | 3.22k | return wmem_strbuf_finalize(buf); |
443 | 5.61k | } |
444 | | |
445 | | /* |
446 | | * Convert a signed value in milliseconds to a string, giving time in days, |
447 | | * hours, minutes, and seconds, and put the result into a buffer. |
448 | | */ |
449 | | char * |
450 | | signed_time_msecs_to_str(wmem_allocator_t *scope, int32_t time_val) |
451 | 493 | { |
452 | 493 | wmem_strbuf_t *buf; |
453 | 493 | int msecs; |
454 | | |
455 | 493 | if (time_val == 0) { |
456 | 26 | return wmem_strdup(scope, "0 seconds"); |
457 | 26 | } |
458 | | |
459 | 467 | buf = wmem_strbuf_new_sized(scope, TIME_SECS_LEN+1+3+1); |
460 | | |
461 | 467 | if (time_val<0) { |
462 | | /* oops we got passed a negative time */ |
463 | | /* C99 and C++11 guarantee integer division rounds to zero */ |
464 | 5 | msecs = -(time_val % 1000); |
465 | 5 | time_val /= 1000; |
466 | 5 | if (time_val == 0) { |
467 | 1 | wmem_strbuf_append_c(buf, '-'); |
468 | 1 | } |
469 | 462 | } else { |
470 | 462 | msecs = time_val % 1000; |
471 | 462 | time_val /= 1000; |
472 | 462 | } |
473 | | |
474 | 467 | signed_time_secs_to_str_buf(time_val, msecs, false, buf); |
475 | | |
476 | 467 | return wmem_strbuf_finalize(buf); |
477 | 493 | } |
478 | | |
479 | | /* |
480 | | * Display a relative time as days/hours/minutes/seconds. |
481 | | */ |
482 | | char * |
483 | | rel_time_to_str(wmem_allocator_t *scope, const nstime_t *rel_time) |
484 | 8 | { |
485 | 8 | wmem_strbuf_t *buf; |
486 | 8 | int64_t time_val; |
487 | 8 | int32_t nsec; |
488 | | |
489 | | /* If the nanoseconds part of the time stamp is negative, |
490 | | print its absolute value and, if the seconds part isn't |
491 | | (the seconds part should be zero in that case), stick |
492 | | a "-" in front of the entire time stamp. */ |
493 | 8 | time_val = (int64_t) rel_time->secs; |
494 | 8 | nsec = rel_time->nsecs; |
495 | 8 | if (time_val == 0 && nsec == 0) { |
496 | 0 | return wmem_strdup(scope, "0.000000000 seconds"); |
497 | 0 | } |
498 | | |
499 | 8 | buf = wmem_strbuf_new_sized(scope, 1+TIME_SECS_LEN+1+6+1); |
500 | | |
501 | 8 | if (nsec < 0) { |
502 | 0 | nsec = -nsec; |
503 | 0 | wmem_strbuf_append_c(buf, '-'); |
504 | | |
505 | | /* |
506 | | * We assume here that "rel_time->secs" is negative |
507 | | * or zero; if it's not, the time stamp is bogus, |
508 | | * with a positive seconds and negative microseconds. |
509 | | */ |
510 | 0 | time_val = (int64_t) -rel_time->secs; |
511 | 0 | } |
512 | | |
513 | 8 | signed_time_secs_to_str_buf(time_val, nsec, true, buf); |
514 | | |
515 | 8 | return wmem_strbuf_finalize(buf); |
516 | 8 | } |
517 | | |
518 | | /* |
519 | | * Number of characters required by a 64-bit signed number. |
520 | | */ |
521 | 28 | #define CHARS_64_BIT_SIGNED 20 /* sign plus 19 digits */ |
522 | | |
523 | | /* |
524 | | * Number of characters required by a fractional part, in nanoseconds */ |
525 | 28 | #define CHARS_NANOSECONDS 10 /* .000000001 */ |
526 | | |
527 | | /* Includes terminating '\0' */ |
528 | 28 | #define NSTIME_SECS_LEN (CHARS_64_BIT_SIGNED+CHARS_NANOSECONDS+1) |
529 | | |
530 | | /* |
531 | | * Display a relative time as seconds. |
532 | | */ |
533 | | char * |
534 | | rel_time_to_secs_str(wmem_allocator_t *scope, const nstime_t *rel_time) |
535 | 14 | { |
536 | 14 | char *buf; |
537 | | |
538 | 14 | buf = (char *)wmem_alloc(scope, NSTIME_SECS_LEN); |
539 | | |
540 | 14 | display_signed_time(buf, NSTIME_SECS_LEN, rel_time, WS_TSPREC_NSEC); |
541 | 14 | return buf; |
542 | 14 | } |
543 | | |
544 | | char * |
545 | | abs_time_to_unix_str(wmem_allocator_t *scope, const nstime_t *rel_time) |
546 | 0 | { |
547 | 0 | char *buf; |
548 | |
|
549 | 0 | buf = (char *)wmem_alloc(scope, NSTIME_SECS_LEN); |
550 | |
|
551 | 0 | display_epoch_time(buf, NSTIME_SECS_LEN, rel_time, WS_TSPREC_NSEC); |
552 | 0 | return buf; |
553 | 0 | } |
554 | | |
555 | | /* |
556 | | * Generates a string representing the bits in a bitfield at "bit_offset" from an 8 bit boundary |
557 | | * with the length in bits of no_of_bits based on value. |
558 | | * Ex: ..xx x... |
559 | | */ |
560 | | |
561 | | char * |
562 | | decode_bits_in_field(wmem_allocator_t *scope, const unsigned bit_offset, const int no_of_bits, const uint64_t value, const unsigned encoding) |
563 | 2.22M | { |
564 | 2.22M | uint64_t mask; |
565 | 2.22M | char *str; |
566 | 2.22M | int bit, str_p = 0; |
567 | 2.22M | int i; |
568 | 2.22M | int max_bits = MIN(64, no_of_bits); |
569 | 2.22M | int no_leading_dots; |
570 | | |
571 | 2.22M | mask = UINT64_C(1) << (max_bits-1); |
572 | | |
573 | 2.22M | if (encoding & ENC_LITTLE_ENDIAN) { |
574 | | /* Bits within octet are numbered from LSB (0) to MSB (7). |
575 | | * The value in string is from most significant bit to lowest. |
576 | | * Calculate how many dots have to be printed at the beginning of string. |
577 | | */ |
578 | 1.18k | no_leading_dots = (8 - ((bit_offset + no_of_bits) % 8)) % 8; |
579 | 2.22M | } else { |
580 | 2.22M | no_leading_dots = bit_offset % 8; |
581 | 2.22M | } |
582 | | |
583 | | /* Prepare the string, 256 pos for the bits and zero termination, + 64 for the spaces */ |
584 | 2.22M | str = (char *)wmem_alloc0(scope, 256+64); |
585 | 7.86M | for (bit = 0; bit < no_leading_dots; bit++) { |
586 | 5.64M | if (bit && !(bit % 4)) { |
587 | 552k | str[str_p] = ' '; |
588 | 552k | str_p++; |
589 | 552k | } |
590 | 5.64M | str[str_p] = '.'; |
591 | 5.64M | str_p++; |
592 | 5.64M | } |
593 | | |
594 | | /* read the bits for the int */ |
595 | 10.9M | for (i = 0; i < max_bits; i++) { |
596 | 8.74M | if (bit && !(bit % 4)) { |
597 | 1.47M | str[str_p] = ' '; |
598 | 1.47M | str_p++; |
599 | 1.47M | } |
600 | 8.74M | if (bit && !(bit % 8)) { |
601 | 509k | str[str_p] = ' '; |
602 | 509k | str_p++; |
603 | 509k | } |
604 | 8.74M | bit++; |
605 | 8.74M | if ((value & mask) != 0) { |
606 | 3.47M | str[str_p] = '1'; |
607 | 3.47M | str_p++; |
608 | 5.26M | } else { |
609 | 5.26M | str[str_p] = '0'; |
610 | 5.26M | str_p++; |
611 | 5.26M | } |
612 | 8.74M | mask = mask>>1; |
613 | 8.74M | } |
614 | | |
615 | 9.71M | for (; bit % 8; bit++) { |
616 | 7.49M | if (bit && !(bit % 4)) { |
617 | 1.21M | str[str_p] = ' '; |
618 | 1.21M | str_p++; |
619 | 1.21M | } |
620 | 7.49M | str[str_p] = '.'; |
621 | 7.49M | str_p++; |
622 | 7.49M | } |
623 | 2.22M | return str; |
624 | 2.22M | } |
625 | | |
626 | | char * |
627 | | guid_to_str(wmem_allocator_t *scope, const e_guid_t *guid) |
628 | 1.77k | { |
629 | 1.77k | char *buf; |
630 | | |
631 | 1.77k | buf = (char *)wmem_alloc(scope, GUID_STR_LEN); |
632 | 1.77k | return guid_to_str_buf(guid, buf, GUID_STR_LEN); |
633 | 1.77k | } |
634 | | |
635 | | char * |
636 | | guid_to_str_buf(const e_guid_t *guid, char *buf, int buf_len) |
637 | 1.77k | { |
638 | 1.77k | char *tempptr = buf; |
639 | | |
640 | 1.77k | if (buf_len < GUID_STR_LEN) { |
641 | 0 | (void) g_strlcpy(buf, BUF_TOO_SMALL_ERR, buf_len); /* Let the unexpected value alert user */ |
642 | 0 | return buf; |
643 | 0 | } |
644 | | |
645 | | /* 37 bytes */ |
646 | 1.77k | tempptr = dword_to_hex(tempptr, guid->data1); /* 8 bytes */ |
647 | 1.77k | *tempptr++ = '-'; /* 1 byte */ |
648 | 1.77k | tempptr = word_to_hex(tempptr, guid->data2); /* 4 bytes */ |
649 | 1.77k | *tempptr++ = '-'; /* 1 byte */ |
650 | 1.77k | tempptr = word_to_hex(tempptr, guid->data3); /* 4 bytes */ |
651 | 1.77k | *tempptr++ = '-'; /* 1 byte */ |
652 | 1.77k | tempptr = bytes_to_hexstr(tempptr, &guid->data4[0], 2); /* 4 bytes */ |
653 | 1.77k | *tempptr++ = '-'; /* 1 byte */ |
654 | 1.77k | tempptr = bytes_to_hexstr(tempptr, &guid->data4[2], 6); /* 12 bytes */ |
655 | | |
656 | 1.77k | *tempptr = '\0'; |
657 | 1.77k | return buf; |
658 | 1.77k | } |
659 | | |
660 | | const char * |
661 | | port_type_to_str (port_type type) |
662 | 0 | { |
663 | 0 | switch (type) { |
664 | 0 | case PT_NONE: return "NONE"; |
665 | 0 | case PT_SCTP: return "SCTP"; |
666 | 0 | case PT_TCP: return "TCP"; |
667 | 0 | case PT_UDP: return "UDP"; |
668 | 0 | case PT_DCCP: return "DCCP"; |
669 | 0 | case PT_IPX: return "IPX"; |
670 | 0 | case PT_DDP: return "DDP"; |
671 | 0 | case PT_IDP: return "IDP"; |
672 | 0 | case PT_USB: return "USB"; |
673 | 0 | case PT_I2C: return "I2C"; |
674 | 0 | case PT_IBQP: return "IBQP"; |
675 | 0 | case PT_BLUETOOTH: return "BLUETOOTH"; |
676 | 0 | case PT_IWARP_MPA: return "IWARP_MPA"; |
677 | 0 | default: return "[Unknown]"; |
678 | 0 | } |
679 | 0 | } |
680 | | |
681 | | /* |
682 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
683 | | * |
684 | | * Local variables: |
685 | | * c-basic-offset: 4 |
686 | | * tab-width: 8 |
687 | | * indent-tabs-mode: nil |
688 | | * End: |
689 | | * |
690 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
691 | | * :indentSize=4:tabSize=8:noTabs=true: |
692 | | */ |