/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.22k | { |
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.22k | # if defined(HAVE_STRUCT_TM_TM_ZONE) |
82 | 3.22k | 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.22k | #endif /* _WIN32 */ |
94 | 3.22k | } |
95 | | |
96 | | static struct tm * |
97 | | get_fmt_broken_down_time(field_display_e fmt, const time_t *secs) |
98 | 3.97k | { |
99 | 3.97k | switch (fmt) { |
100 | 718 | case ABSOLUTE_TIME_UTC: |
101 | 718 | case ABSOLUTE_TIME_DOY_UTC: |
102 | 743 | case ABSOLUTE_TIME_NTP_UTC: |
103 | 743 | return gmtime(secs); |
104 | 3.22k | case ABSOLUTE_TIME_LOCAL: |
105 | 3.22k | return localtime(secs); |
106 | 0 | default: |
107 | 0 | break; |
108 | 3.97k | } |
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.97k | { |
118 | 3.97k | char *buf; |
119 | | |
120 | 3.97k | 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 | 25 | case ABSOLUTE_TIME_NTP_UTC: /* FALLTHROUGH */ |
136 | 743 | case ABSOLUTE_TIME_UTC: /* FALLTHROUGH */ |
137 | 3.97k | case ABSOLUTE_TIME_LOCAL: |
138 | 3.97k | buf = wmem_strdup_printf(scope, |
139 | 3.97k | "%s%s %2d, %d %02d:%02d:%02d%s%s%s%s", |
140 | 3.97k | add_quotes ? "\"" : "", |
141 | 3.97k | mon_names[tmp->tm_mon], |
142 | 3.97k | tmp->tm_mday, |
143 | 3.97k | tmp->tm_year + 1900, |
144 | 3.97k | tmp->tm_hour, |
145 | 3.97k | tmp->tm_min, |
146 | 3.97k | tmp->tm_sec, |
147 | 3.97k | nsecs_str, |
148 | 3.97k | tzone_sep, |
149 | 3.97k | tzone_str, |
150 | 3.97k | add_quotes ? "\"" : ""); |
151 | 3.97k | break; |
152 | 0 | default: |
153 | 0 | ws_assert_not_reached(); |
154 | 3.97k | } |
155 | 3.97k | return buf; |
156 | 3.97k | } |
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.97k | { |
239 | 3.97k | struct tm *tmp; |
240 | 3.97k | char buf_nsecs[32]; |
241 | 3.97k | const char *tzone_sep, *tzone_str; |
242 | | |
243 | 3.97k | if (fmt == BASE_NONE) |
244 | 0 | fmt = ABSOLUTE_TIME_LOCAL; |
245 | | |
246 | 3.97k | ws_assert(FIELD_DISPLAY_IS_ABSOLUTE_TIME(fmt)); |
247 | | |
248 | 3.97k | if (fmt == ABSOLUTE_TIME_UNIX) { |
249 | 0 | return abs_time_to_unix_str(scope, abs_time); |
250 | 0 | } |
251 | | |
252 | 3.97k | 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.97k | tmp = get_fmt_broken_down_time(fmt, &abs_time->secs); |
258 | 3.97k | if (tmp == NULL) { |
259 | 0 | return wmem_strdup(scope, "Not representable"); |
260 | 0 | } |
261 | | |
262 | 3.97k | *buf_nsecs = '\0'; |
263 | 3.97k | if (abs_time->nsecs != INT_MAX) { |
264 | 845 | snprintf(buf_nsecs, sizeof(buf_nsecs), ".%09d", abs_time->nsecs); |
265 | 845 | } |
266 | | |
267 | 3.97k | 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.97k | tzone_sep = ""; |
272 | 3.97k | tzone_str = ""; |
273 | 3.97k | if (flags & ABS_TIME_TO_STR_SHOW_ZONE || flags & ABS_TIME_TO_STR_SHOW_UTC_ONLY) { |
274 | 3.97k | switch (fmt) { |
275 | | |
276 | 718 | case ABSOLUTE_TIME_UTC: |
277 | 718 | case ABSOLUTE_TIME_DOY_UTC: |
278 | 743 | case ABSOLUTE_TIME_NTP_UTC: |
279 | 743 | tzone_sep = " "; |
280 | 743 | tzone_str = "UTC"; |
281 | 743 | break; |
282 | | |
283 | 3.22k | case ABSOLUTE_TIME_LOCAL: |
284 | 3.22k | if (flags & ABS_TIME_TO_STR_SHOW_ZONE) { |
285 | 3.22k | tzone_sep = " "; |
286 | 3.22k | tzone_str = get_zonename(tmp); |
287 | 3.22k | } |
288 | 3.22k | break; |
289 | 0 | default: |
290 | 0 | ws_assert_not_reached(); |
291 | 3.97k | } |
292 | 3.97k | } |
293 | | |
294 | 3.97k | return snprint_abs_time_secs(scope, fmt, tmp, buf_nsecs, tzone_sep, tzone_str, flags & ABS_TIME_TO_STR_ADD_DQUOTES); |
295 | 3.97k | } |
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.12k | { |
301 | 3.12k | nstime_t abs_time; |
302 | | |
303 | 3.12k | nstime_set_unset(&abs_time); |
304 | 3.12k | abs_time.secs = abs_time_secs; |
305 | 3.12k | return abs_time_to_str_ex(scope, &abs_time, fmt, flags); |
306 | 3.12k | } |
307 | | |
308 | 110k | #define PLURALIZE(n) (((n) > 1) ? "s" : "") |
309 | 85.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 | 31.8k | #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 | 31.8k | { |
330 | 31.8k | uint64_t hours, mins, secs; |
331 | 31.8k | bool do_comma = false; |
332 | | |
333 | 31.8k | secs = time_val % 60; |
334 | 31.8k | time_val /= 60; |
335 | 31.8k | mins = time_val % 60; |
336 | 31.8k | time_val /= 60; |
337 | 31.8k | hours = time_val % 24; |
338 | 31.8k | time_val /= 24; |
339 | | |
340 | 31.8k | if (time_val != 0) { |
341 | 25.3k | wmem_strbuf_append_printf(buf, "%" PRIu64 " day%s", time_val, PLURALIZE(time_val)); |
342 | 25.3k | do_comma = true; |
343 | 25.3k | } |
344 | 31.8k | if (hours != 0) { |
345 | 26.4k | wmem_strbuf_append_printf(buf, "%s%" PRIu64 " hour%s", COMMA(do_comma), hours, PLURALIZE(hours)); |
346 | 26.4k | do_comma = true; |
347 | 26.4k | } |
348 | 31.8k | if (mins != 0) { |
349 | 29.5k | wmem_strbuf_append_printf(buf, "%s%" PRIu64 " minute%s", COMMA(do_comma), mins, PLURALIZE(mins)); |
350 | 29.5k | do_comma = true; |
351 | 29.5k | } |
352 | 31.8k | if (secs != 0) { |
353 | 29.4k | if (frac != 0) { |
354 | 468 | if (is_nsecs) |
355 | 4 | wmem_strbuf_append_printf(buf, "%s%" PRIu64 ".%09u seconds", COMMA(do_comma), secs, frac); |
356 | 464 | else |
357 | 464 | wmem_strbuf_append_printf(buf, "%s%" PRIu64 ".%03u seconds", COMMA(do_comma), secs, frac); |
358 | 468 | } else |
359 | 29.0k | wmem_strbuf_append_printf(buf, "%s%" PRIu64 " second%s", COMMA(do_comma), secs, PLURALIZE(secs)); |
360 | 29.4k | } else if (frac != 0) { |
361 | 52 | if (is_nsecs) { |
362 | 2 | if (frac < 1000) { |
363 | 0 | wmem_strbuf_append_printf(buf, "%s%u nanosecond%s", COMMA(do_comma), frac, PLURALIZE(frac)); |
364 | 2 | } else if (frac < 1000000) { |
365 | 0 | wmem_strbuf_append_printf(buf, "%s%u.%03u microseconds", COMMA(do_comma), frac / 1000, frac % 1000); |
366 | 2 | } else { |
367 | 2 | wmem_strbuf_append_printf(buf, "%s%u.%06u milliseconds", COMMA(do_comma), frac / 1000000, frac % 1000000); |
368 | 2 | } |
369 | 50 | } else { |
370 | 50 | wmem_strbuf_append_printf(buf, "%s%u millisecond%s", COMMA(do_comma), frac, PLURALIZE(frac)); |
371 | 50 | } |
372 | 52 | } |
373 | 31.8k | } |
374 | | |
375 | | char * |
376 | | unsigned_time_secs_to_str(wmem_allocator_t *scope, const uint64_t time_val) |
377 | 29.9k | { |
378 | 29.9k | wmem_strbuf_t *buf; |
379 | | |
380 | 29.9k | if (time_val == 0) { |
381 | 1.96k | return wmem_strdup(scope, "0 seconds"); |
382 | 1.96k | } |
383 | | |
384 | 27.9k | buf = wmem_strbuf_new_sized(scope, TIME_SECS_LEN+1); |
385 | | |
386 | 27.9k | unsigned_time_secs_to_str_buf(time_val, 0, false, buf); |
387 | | |
388 | 27.9k | return wmem_strbuf_finalize(buf); |
389 | 29.9k | } |
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.83k | { |
402 | 3.83k | if(time_val < 0){ |
403 | 0 | wmem_strbuf_append_printf(buf, "-"); |
404 | 0 | 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 | 0 | unsigned_time_secs_to_str_buf(UINT64_MAX, frac, |
412 | 0 | is_nsecs, buf); |
413 | 0 | } else { |
414 | | /* |
415 | | * We now know -secs will fit into a uint32_t; |
416 | | * negate it and pass that to |
417 | | * unsigned_time_secs_to_str_buf(). |
418 | | */ |
419 | 0 | unsigned_time_secs_to_str_buf(-time_val, frac, is_nsecs, buf); |
420 | 0 | } |
421 | 0 | } else |
422 | 3.83k | unsigned_time_secs_to_str_buf(time_val, frac, is_nsecs, buf); |
423 | 3.83k | } |
424 | | |
425 | | char * |
426 | | signed_time_secs_to_str(wmem_allocator_t *scope, const int64_t time_val) |
427 | 5.41k | { |
428 | 5.41k | wmem_strbuf_t *buf; |
429 | | |
430 | 5.41k | if (time_val == 0) { |
431 | 2.10k | return wmem_strdup(scope, "0 seconds"); |
432 | 2.10k | } |
433 | | |
434 | 3.31k | buf = wmem_strbuf_new_sized(scope, TIME_SECS_LEN+1); |
435 | | |
436 | 3.31k | signed_time_secs_to_str_buf(time_val, 0, false, buf); |
437 | | |
438 | 3.31k | return wmem_strbuf_finalize(buf); |
439 | 5.41k | } |
440 | | |
441 | | /* |
442 | | * Convert a signed value in milliseconds to a string, giving time in days, |
443 | | * hours, minutes, and seconds, and put the result into a buffer. |
444 | | */ |
445 | | char * |
446 | | signed_time_msecs_to_str(wmem_allocator_t *scope, int64_t time_val) |
447 | 548 | { |
448 | 548 | wmem_strbuf_t *buf; |
449 | 548 | int msecs; |
450 | | |
451 | 548 | if (time_val == 0) { |
452 | 34 | return wmem_strdup(scope, "0 seconds"); |
453 | 34 | } |
454 | | |
455 | 514 | buf = wmem_strbuf_new_sized(scope, TIME_SECS_LEN+1+3+1); |
456 | | |
457 | 514 | if (time_val<0) { |
458 | | /* oops we got passed a negative time */ |
459 | | /* C99 and C++11 guarantee integer division rounds to zero */ |
460 | 0 | msecs = -(time_val % 1000); |
461 | 0 | time_val /= 1000; |
462 | 0 | if (time_val == 0) { |
463 | 0 | wmem_strbuf_append_c(buf, '-'); |
464 | 0 | } |
465 | 514 | } else { |
466 | 514 | msecs = time_val % 1000; |
467 | 514 | time_val /= 1000; |
468 | 514 | } |
469 | | |
470 | 514 | signed_time_secs_to_str_buf(time_val, msecs, false, buf); |
471 | | |
472 | 514 | return wmem_strbuf_finalize(buf); |
473 | 548 | } |
474 | | |
475 | | /* |
476 | | * Display a relative time as days/hours/minutes/seconds. |
477 | | */ |
478 | | char * |
479 | | rel_time_to_str(wmem_allocator_t *scope, const nstime_t *rel_time) |
480 | 7 | { |
481 | 7 | wmem_strbuf_t *buf; |
482 | 7 | int64_t time_val; |
483 | 7 | int32_t nsec; |
484 | | |
485 | | /* If the nanoseconds part of the time stamp is negative, |
486 | | print its absolute value and, if the seconds part isn't |
487 | | (the seconds part should be zero in that case), stick |
488 | | a "-" in front of the entire time stamp. */ |
489 | 7 | time_val = (int64_t) rel_time->secs; |
490 | 7 | nsec = rel_time->nsecs; |
491 | 7 | if (time_val == 0 && nsec == 0) { |
492 | 1 | return wmem_strdup(scope, "0.000000000 seconds"); |
493 | 1 | } |
494 | | |
495 | 6 | buf = wmem_strbuf_new_sized(scope, 1+TIME_SECS_LEN+1+6+1); |
496 | | |
497 | 6 | if (nsec < 0) { |
498 | 0 | nsec = -nsec; |
499 | 0 | wmem_strbuf_append_c(buf, '-'); |
500 | | |
501 | | /* |
502 | | * We assume here that "rel_time->secs" is negative |
503 | | * or zero; if it's not, the time stamp is bogus, |
504 | | * with a positive seconds and negative microseconds. |
505 | | */ |
506 | 0 | time_val = (int64_t) -rel_time->secs; |
507 | 0 | } |
508 | | |
509 | 6 | signed_time_secs_to_str_buf(time_val, nsec, true, buf); |
510 | | |
511 | 6 | return wmem_strbuf_finalize(buf); |
512 | 7 | } |
513 | | |
514 | | /* |
515 | | * Number of characters required by a 64-bit signed number. |
516 | | */ |
517 | 28 | #define CHARS_64_BIT_SIGNED 20 /* sign plus 19 digits */ |
518 | | |
519 | | /* |
520 | | * Number of characters required by a fractional part, in nanoseconds */ |
521 | 28 | #define CHARS_NANOSECONDS 10 /* .000000001 */ |
522 | | |
523 | | /* Includes terminating '\0' */ |
524 | 28 | #define NSTIME_SECS_LEN (CHARS_64_BIT_SIGNED+CHARS_NANOSECONDS+1) |
525 | | |
526 | | /* |
527 | | * Display a relative time as seconds. |
528 | | */ |
529 | | char * |
530 | | rel_time_to_secs_str(wmem_allocator_t *scope, const nstime_t *rel_time) |
531 | 14 | { |
532 | 14 | char *buf; |
533 | | |
534 | 14 | buf = (char *)wmem_alloc(scope, NSTIME_SECS_LEN); |
535 | | |
536 | 14 | display_signed_time(buf, NSTIME_SECS_LEN, rel_time, WS_TSPREC_NSEC); |
537 | 14 | return buf; |
538 | 14 | } |
539 | | |
540 | | char * |
541 | | abs_time_to_unix_str(wmem_allocator_t *scope, const nstime_t *rel_time) |
542 | 0 | { |
543 | 0 | char *buf; |
544 | |
|
545 | 0 | buf = (char *)wmem_alloc(scope, NSTIME_SECS_LEN); |
546 | |
|
547 | 0 | display_epoch_time(buf, NSTIME_SECS_LEN, rel_time, WS_TSPREC_NSEC); |
548 | 0 | return buf; |
549 | 0 | } |
550 | | |
551 | | /* |
552 | | * Generates a string representing the bits in a bitfield at "bit_offset" from an 8 bit boundary |
553 | | * with the length in bits of no_of_bits based on value. |
554 | | * Ex: ..xx x... |
555 | | */ |
556 | | |
557 | | char * |
558 | | decode_bits_in_field(wmem_allocator_t *scope, const unsigned bit_offset, const int no_of_bits, const uint64_t value, const unsigned encoding) |
559 | 2.53M | { |
560 | 2.53M | uint64_t mask; |
561 | 2.53M | char *str; |
562 | 2.53M | int bit, str_p = 0; |
563 | 2.53M | int i; |
564 | 2.53M | int max_bits = MIN(64, no_of_bits); |
565 | 2.53M | int no_leading_dots; |
566 | | |
567 | 2.53M | mask = UINT64_C(1) << (max_bits-1); |
568 | | |
569 | 2.53M | if (encoding & ENC_LITTLE_ENDIAN) { |
570 | | /* Bits within octet are numbered from LSB (0) to MSB (7). |
571 | | * The value in string is from most significant bit to lowest. |
572 | | * Calculate how many dots have to be printed at the beginning of string. |
573 | | */ |
574 | 1.23k | no_leading_dots = (8 - ((bit_offset + no_of_bits) % 8)) % 8; |
575 | 2.53M | } else { |
576 | 2.53M | no_leading_dots = bit_offset % 8; |
577 | 2.53M | } |
578 | | |
579 | | /* Prepare the string, 256 pos for the bits and zero termination, + 64 for the spaces */ |
580 | 2.53M | str = (char *)wmem_alloc0(scope, 256+64); |
581 | 8.97M | for (bit = 0; bit < no_leading_dots; bit++) { |
582 | 6.43M | if (bit && !(bit % 4)) { |
583 | 630k | str[str_p] = ' '; |
584 | 630k | str_p++; |
585 | 630k | } |
586 | 6.43M | str[str_p] = '.'; |
587 | 6.43M | str_p++; |
588 | 6.43M | } |
589 | | |
590 | | /* read the bits for the int */ |
591 | 12.4M | for (i = 0; i < max_bits; i++) { |
592 | 9.92M | if (bit && !(bit % 4)) { |
593 | 1.67M | str[str_p] = ' '; |
594 | 1.67M | str_p++; |
595 | 1.67M | } |
596 | 9.92M | if (bit && !(bit % 8)) { |
597 | 577k | str[str_p] = ' '; |
598 | 577k | str_p++; |
599 | 577k | } |
600 | 9.92M | bit++; |
601 | 9.92M | if ((value & mask) != 0) { |
602 | 3.92M | str[str_p] = '1'; |
603 | 3.92M | str_p++; |
604 | 6.00M | } else { |
605 | 6.00M | str[str_p] = '0'; |
606 | 6.00M | str_p++; |
607 | 6.00M | } |
608 | 9.92M | mask = mask>>1; |
609 | 9.92M | } |
610 | | |
611 | 11.0M | for (; bit % 8; bit++) { |
612 | 8.56M | if (bit && !(bit % 4)) { |
613 | 1.38M | str[str_p] = ' '; |
614 | 1.38M | str_p++; |
615 | 1.38M | } |
616 | 8.56M | str[str_p] = '.'; |
617 | 8.56M | str_p++; |
618 | 8.56M | } |
619 | 2.53M | return str; |
620 | 2.53M | } |
621 | | |
622 | | char * |
623 | | guid_to_str(wmem_allocator_t *scope, const e_guid_t *guid) |
624 | 1.84k | { |
625 | 1.84k | char *buf; |
626 | | |
627 | 1.84k | buf = (char *)wmem_alloc(scope, GUID_STR_LEN); |
628 | 1.84k | return guid_to_str_buf(guid, buf, GUID_STR_LEN); |
629 | 1.84k | } |
630 | | |
631 | | char * |
632 | | guid_to_str_buf(const e_guid_t *guid, char *buf, int buf_len) |
633 | 1.84k | { |
634 | 1.84k | char *tempptr = buf; |
635 | | |
636 | 1.84k | if (buf_len < GUID_STR_LEN) { |
637 | 0 | (void) g_strlcpy(buf, BUF_TOO_SMALL_ERR, buf_len); /* Let the unexpected value alert user */ |
638 | 0 | return buf; |
639 | 0 | } |
640 | | |
641 | | /* 37 bytes */ |
642 | 1.84k | tempptr = dword_to_hex(tempptr, guid->data1); /* 8 bytes */ |
643 | 1.84k | *tempptr++ = '-'; /* 1 byte */ |
644 | 1.84k | tempptr = word_to_hex(tempptr, guid->data2); /* 4 bytes */ |
645 | 1.84k | *tempptr++ = '-'; /* 1 byte */ |
646 | 1.84k | tempptr = word_to_hex(tempptr, guid->data3); /* 4 bytes */ |
647 | 1.84k | *tempptr++ = '-'; /* 1 byte */ |
648 | 1.84k | tempptr = bytes_to_hexstr(tempptr, &guid->data4[0], 2); /* 4 bytes */ |
649 | 1.84k | *tempptr++ = '-'; /* 1 byte */ |
650 | 1.84k | tempptr = bytes_to_hexstr(tempptr, &guid->data4[2], 6); /* 12 bytes */ |
651 | | |
652 | 1.84k | *tempptr = '\0'; |
653 | 1.84k | return buf; |
654 | 1.84k | } |
655 | | |
656 | | const char * |
657 | | port_type_to_str (port_type type) |
658 | 0 | { |
659 | 0 | switch (type) { |
660 | 0 | case PT_NONE: return "NONE"; |
661 | 0 | case PT_SCTP: return "SCTP"; |
662 | 0 | case PT_TCP: return "TCP"; |
663 | 0 | case PT_UDP: return "UDP"; |
664 | 0 | case PT_DCCP: return "DCCP"; |
665 | 0 | case PT_IPX: return "IPX"; |
666 | 0 | case PT_DDP: return "DDP"; |
667 | 0 | case PT_IDP: return "IDP"; |
668 | 0 | case PT_USB: return "USB"; |
669 | 0 | case PT_I2C: return "I2C"; |
670 | 0 | case PT_IBQP: return "IBQP"; |
671 | 0 | case PT_BLUETOOTH: return "BLUETOOTH"; |
672 | 0 | case PT_IWARP_MPA: return "IWARP_MPA"; |
673 | 0 | default: return "[Unknown]"; |
674 | 0 | } |
675 | 0 | } |
676 | | |
677 | | /* |
678 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
679 | | * |
680 | | * Local variables: |
681 | | * c-basic-offset: 4 |
682 | | * tab-width: 8 |
683 | | * indent-tabs-mode: nil |
684 | | * End: |
685 | | * |
686 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
687 | | * :indentSize=4:tabSize=8:noTabs=true: |
688 | | */ |