2 * Routines for utilities to convert various other types to strings.
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0-or-later
18 #include "wmem/wmem.h"
21 #include "to_str-int.h"
23 #include <wsutil/pint.h>
24 #include <wsutil/utf8_entities.h>
27 * If a user _does_ pass in a too-small buffer, this is probably
28 * going to be too long to fit. However, even a partial string
29 * starting with "[Buf" should provide enough of a clue to be
32 #define BUF_TOO_SMALL_ERR "[Buffer too small]"
35 low_nibble_of_octet_to_hex(guint8 oct)
37 /* At least one version of Apple's C compiler/linker is buggy, causing
38 a complaint from the linker about the "literal C string section"
39 not ending with '\0' if we initialize a 16-element "char" array with
40 a 16-character string, the fact that initializing such an array with
41 such a string is perfectly legitimate ANSI C nonwithstanding, the 17th
42 '\0' byte in the string nonwithstanding. */
43 static const gchar hex_digits[16] =
44 { '0', '1', '2', '3', '4', '5', '6', '7',
45 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
47 return hex_digits[oct & 0xF];
51 byte_to_hex(char *out, guint32 dword)
53 *out++ = low_nibble_of_octet_to_hex(dword >> 4);
54 *out++ = low_nibble_of_octet_to_hex(dword);
59 guint8_to_hex(char *out, guint8 val)
61 return byte_to_hex(out, val);
65 word_to_hex(char *out, guint16 word)
67 out = byte_to_hex(out, word >> 8);
68 out = byte_to_hex(out, word);
73 word_to_hex_punct(char *out, guint16 word, char punct)
75 out = byte_to_hex(out, word >> 8);
77 out = byte_to_hex(out, word);
82 word_to_hex_npad(char *out, guint16 word)
85 *out++ = low_nibble_of_octet_to_hex((guint8)(word >> 12));
87 *out++ = low_nibble_of_octet_to_hex((guint8)(word >> 8));
89 *out++ = low_nibble_of_octet_to_hex((guint8)(word >> 4));
90 *out++ = low_nibble_of_octet_to_hex((guint8)(word >> 0));
95 dword_to_hex(char *out, guint32 dword)
97 out = word_to_hex(out, dword >> 16);
98 out = word_to_hex(out, dword);
103 dword_to_hex_punct(char *out, guint32 dword, char punct)
105 out = word_to_hex_punct(out, dword >> 16, punct);
107 out = word_to_hex_punct(out, dword, punct);
112 qword_to_hex(char *out, guint64 qword)
114 out = dword_to_hex(out, (guint32)(qword >> 32));
115 out = dword_to_hex(out, (guint32)(qword & 0xffffffff));
120 qword_to_hex_punct(char *out, guint64 qword, char punct)
122 out = dword_to_hex_punct(out, (guint32)(qword >> 32), punct);
124 out = dword_to_hex_punct(out, (guint32)(qword & 0xffffffff), punct);
129 * This does *not* null-terminate the string. It returns a pointer
130 * to the position in the string following the last character it
131 * puts there, so that the caller can either put the null terminator
132 * in or can append more stuff to the buffer.
134 * There needs to be at least len * 2 bytes left in the buffer.
137 bytes_to_hexstr(char *out, const guint8 *ad, guint32 len)
142 REPORT_DISSECTOR_BUG("Null pointer passed to bytes_to_hexstr()");
144 for (i = 0; i < len; i++)
145 out = byte_to_hex(out, ad[i]);
150 * This does *not* null-terminate the string. It returns a pointer
151 * to the position in the string following the last character it
152 * puts there, so that the caller can either put the null terminator
153 * in or can append more stuff to the buffer.
155 * There needs to be at least len * 3 - 1 bytes left in the buffer.
158 bytes_to_hexstr_punct(char *out, const guint8 *ad, guint32 len, char punct)
163 REPORT_DISSECTOR_BUG("Null pointer passed to bytes_to_hexstr_punct()");
165 out = byte_to_hex(out, ad[0]);
166 for (i = 1; i < len; i++) {
168 out = byte_to_hex(out, ad[i]);
173 /* Max string length for displaying byte string. */
174 #define MAX_BYTE_STR_LEN 48
176 /* Routine to convert a sequence of bytes to a hex string, one byte/two hex
177 * digits at at a time, with a specified punctuation character between
180 * If punct is '\0', no punctuation is applied (and thus
181 * the resulting string is (len-1) bytes shorter)
184 bytestring_to_str(wmem_allocator_t *scope, const guint8 *ad, const guint32 len, const char punct)
187 guint32 buflen = len;
192 return bytes_to_str(scope, ad, len);
195 REPORT_DISSECTOR_BUG("Null pointer passed to bytestring_to_str()");
198 return wmem_strdup(scope, "");
200 buf=(gchar *)wmem_alloc(scope, MAX_BYTE_STR_LEN+3+1);
201 if (buflen > MAX_BYTE_STR_LEN/3) { /* bd_len > 16 */
203 buflen = MAX_BYTE_STR_LEN/3;
206 buf_ptr = bytes_to_hexstr_punct(buf, ad, buflen, punct); /* max MAX_BYTE_STR_LEN-1 bytes */
209 *buf_ptr++ = punct; /* 1 byte */
210 buf_ptr = g_stpcpy(buf_ptr, UTF8_HORIZONTAL_ELLIPSIS); /* 3 bytes */
218 bytes_to_str(wmem_allocator_t *scope, const guint8 *bd, int bd_len)
225 REPORT_DISSECTOR_BUG("Null pointer passed to bytes_to_str()");
227 cur=(gchar *)wmem_alloc(scope, MAX_BYTE_STR_LEN+3+1);
228 if (bd_len <= 0) { cur[0] = '\0'; return cur; }
230 if (bd_len > MAX_BYTE_STR_LEN/2) { /* bd_len > 24 */
232 bd_len = MAX_BYTE_STR_LEN/2;
235 cur_ptr = bytes_to_hexstr(cur, bd, bd_len); /* max MAX_BYTE_STR_LEN bytes */
238 cur_ptr = g_stpcpy(cur_ptr, UTF8_HORIZONTAL_ELLIPSIS); /* 3 bytes */
240 *cur_ptr = '\0'; /* 1 byte */
245 guint32_to_str_buf_len(const guint32 u)
247 /* ((2^32)-1) == 2147483647 */
248 if (u >= 1000000000)return 10;
249 if (u >= 100000000) return 9;
250 if (u >= 10000000) return 8;
251 if (u >= 1000000) return 7;
252 if (u >= 100000) return 6;
253 if (u >= 10000) return 5;
254 if (u >= 1000) return 4;
255 if (u >= 100) return 3;
256 if (u >= 10) return 2;
262 guint64_to_str_buf_len(const guint64 u)
264 /* ((2^64)-1) == 18446744073709551615 */
266 if (u >= G_GUINT64_CONSTANT(10000000000000000000)) return 20;
267 if (u >= G_GUINT64_CONSTANT(1000000000000000000)) return 19;
268 if (u >= G_GUINT64_CONSTANT(100000000000000000)) return 18;
269 if (u >= G_GUINT64_CONSTANT(10000000000000000)) return 17;
270 if (u >= G_GUINT64_CONSTANT(1000000000000000)) return 16;
271 if (u >= G_GUINT64_CONSTANT(100000000000000)) return 15;
272 if (u >= G_GUINT64_CONSTANT(10000000000000)) return 14;
273 if (u >= G_GUINT64_CONSTANT(1000000000000)) return 13;
274 if (u >= G_GUINT64_CONSTANT(100000000000)) return 12;
275 if (u >= G_GUINT64_CONSTANT(10000000000)) return 11;
276 if (u >= G_GUINT64_CONSTANT(1000000000)) return 10;
277 if (u >= G_GUINT64_CONSTANT(100000000)) return 9;
278 if (u >= G_GUINT64_CONSTANT(10000000)) return 8;
279 if (u >= G_GUINT64_CONSTANT(1000000)) return 7;
280 if (u >= G_GUINT64_CONSTANT(100000)) return 6;
281 if (u >= G_GUINT64_CONSTANT(10000)) return 5;
282 if (u >= G_GUINT64_CONSTANT(1000)) return 4;
283 if (u >= G_GUINT64_CONSTANT(100)) return 3;
284 if (u >= G_GUINT64_CONSTANT(10)) return 2;
289 static const char fast_strings[][4] = {
290 "0", "1", "2", "3", "4", "5", "6", "7",
291 "8", "9", "10", "11", "12", "13", "14", "15",
292 "16", "17", "18", "19", "20", "21", "22", "23",
293 "24", "25", "26", "27", "28", "29", "30", "31",
294 "32", "33", "34", "35", "36", "37", "38", "39",
295 "40", "41", "42", "43", "44", "45", "46", "47",
296 "48", "49", "50", "51", "52", "53", "54", "55",
297 "56", "57", "58", "59", "60", "61", "62", "63",
298 "64", "65", "66", "67", "68", "69", "70", "71",
299 "72", "73", "74", "75", "76", "77", "78", "79",
300 "80", "81", "82", "83", "84", "85", "86", "87",
301 "88", "89", "90", "91", "92", "93", "94", "95",
302 "96", "97", "98", "99", "100", "101", "102", "103",
303 "104", "105", "106", "107", "108", "109", "110", "111",
304 "112", "113", "114", "115", "116", "117", "118", "119",
305 "120", "121", "122", "123", "124", "125", "126", "127",
306 "128", "129", "130", "131", "132", "133", "134", "135",
307 "136", "137", "138", "139", "140", "141", "142", "143",
308 "144", "145", "146", "147", "148", "149", "150", "151",
309 "152", "153", "154", "155", "156", "157", "158", "159",
310 "160", "161", "162", "163", "164", "165", "166", "167",
311 "168", "169", "170", "171", "172", "173", "174", "175",
312 "176", "177", "178", "179", "180", "181", "182", "183",
313 "184", "185", "186", "187", "188", "189", "190", "191",
314 "192", "193", "194", "195", "196", "197", "198", "199",
315 "200", "201", "202", "203", "204", "205", "206", "207",
316 "208", "209", "210", "211", "212", "213", "214", "215",
317 "216", "217", "218", "219", "220", "221", "222", "223",
318 "224", "225", "226", "227", "228", "229", "230", "231",
319 "232", "233", "234", "235", "236", "237", "238", "239",
320 "240", "241", "242", "243", "244", "245", "246", "247",
321 "248", "249", "250", "251", "252", "253", "254", "255"
325 guint32_to_str_buf(guint32 u, gchar *buf, int buf_len)
327 int str_len = guint32_to_str_buf_len(u)+1;
329 gchar *bp = &buf[str_len];
331 if (buf_len < str_len) {
332 g_strlcpy(buf, BUF_TOO_SMALL_ERR, buf_len); /* Let the unexpected value alert user */
338 uint_to_str_back(bp, u);
342 guint64_to_str_buf(guint64 u, gchar *buf, int buf_len)
344 int str_len = guint64_to_str_buf_len(u)+1;
346 gchar *bp = &buf[str_len];
348 if (buf_len < str_len) {
349 g_strlcpy(buf, BUF_TOO_SMALL_ERR, buf_len); /* Let the unexpected value alert user */
355 uint64_to_str_back(bp, u);
358 static const char mon_names[12][4] = {
374 get_zonename(struct tm *tmp)
377 /* Windows C Runtime: */
378 /* _tzname is encoded using the "system default ansi code page" */
379 /* ("which is not necessarily the same as the C library locale"). */
380 /* So: _tzname must be converted to UTF8 before use. */
381 /* Alternative: use Windows GetTimeZoneInformation() to get the */
382 /* timezone name in UTF16 and convert same to UTF8. */
383 /* XXX: the result is that the timezone name will be based upon the */
384 /* system code page (iow: the charset of the system). */
385 /* Since Wireshark is not internationalized, it would seem more */
386 /* correct to show the timezone name in English, no matter what */
387 /* the system code page, but I don't how to do that (or if it's */
388 /* really even possible). */
389 /* In any case converting to UTF8 presumably at least keeps GTK */
390 /* happy. (A bug was reported wherein Wireshark crashed in GDK */
391 /* on a "Japanese version of Windows XP" when trying to copy */
392 /* the date/time string (containing a copy of _tz_name) to the */
394 static char *ws_tzname[2] = {NULL, NULL};
396 /* The g_malloc'd value returned from g_locale_to_utf8() is */
397 /* cached for all further use so there's no need to ever */
398 /* g_free() that value. */
399 if (ws_tzname[tmp->tm_isdst] == NULL) {
400 ws_tzname[tmp->tm_isdst] = g_locale_to_utf8(_tzname[tmp->tm_isdst], -1, NULL, NULL, NULL);
401 if (ws_tzname[tmp->tm_isdst] == NULL) {
402 ws_tzname[tmp->tm_isdst] = "???";
405 return ws_tzname[tmp->tm_isdst];
410 * If we have tm_zone in struct tm, use that.
411 * Otherwise, if we have tzname[], use it, otherwise just
412 * say "we don't know.
414 # if defined(HAVE_STRUCT_TM_TM_ZONE)
416 # else /* HAVE_STRUCT_TM_TM_ZONE */
417 if ((tmp->tm_isdst != 0) && (tmp->tm_isdst != 1)) {
420 # if defined(HAVE_TZNAME)
421 return tzname[tmp->tm_isdst];
423 return tmp->tm_isdst ? "?DT" : "?ST";
424 # endif /* HAVE_TZNAME */
425 # endif /* HAVE_STRUCT_TM_TM_ZONE */
430 abs_time_to_str(wmem_allocator_t *scope, const nstime_t *abs_time, const absolute_time_display_e fmt,
433 struct tm *tmp = NULL;
434 const char *zonename = "???";
440 case ABSOLUTE_TIME_UTC:
441 case ABSOLUTE_TIME_DOY_UTC:
442 tmp = gmtime(&abs_time->secs);
446 case ABSOLUTE_TIME_LOCAL:
447 tmp = localtime(&abs_time->secs);
449 zonename = get_zonename(tmp);
456 case ABSOLUTE_TIME_DOY_UTC:
458 buf = wmem_strdup_printf(scope,
459 "%04d/%03d:%02d:%02d:%02d.%09ld %s",
465 (long)abs_time->nsecs,
468 buf = wmem_strdup_printf(scope,
469 "%04d/%03d:%02d:%02d:%02d.%09ld",
475 (long)abs_time->nsecs);
479 case ABSOLUTE_TIME_UTC:
480 case ABSOLUTE_TIME_LOCAL:
482 buf = wmem_strdup_printf(scope,
483 "%s %2d, %d %02d:%02d:%02d.%09ld %s",
484 mon_names[tmp->tm_mon],
490 (long)abs_time->nsecs,
493 buf = wmem_strdup_printf(scope,
494 "%s %2d, %d %02d:%02d:%02d.%09ld",
495 mon_names[tmp->tm_mon],
501 (long)abs_time->nsecs);
506 buf = wmem_strdup(scope, "Not representable");
511 abs_time_secs_to_str(wmem_allocator_t *scope, const time_t abs_time, const absolute_time_display_e fmt,
514 struct tm *tmp = NULL;
515 const char *zonename = "???";
520 case ABSOLUTE_TIME_UTC:
521 case ABSOLUTE_TIME_DOY_UTC:
522 tmp = gmtime(&abs_time);
526 case ABSOLUTE_TIME_LOCAL:
527 tmp = localtime(&abs_time);
529 zonename = get_zonename(tmp);
536 case ABSOLUTE_TIME_DOY_UTC:
538 buf = wmem_strdup_printf(scope,
539 "%04d/%03d:%02d:%02d:%02d %s",
547 buf = wmem_strdup_printf(scope,
548 "%04d/%03d:%02d:%02d:%02d",
557 case ABSOLUTE_TIME_UTC:
558 case ABSOLUTE_TIME_LOCAL:
560 buf = wmem_strdup_printf(scope,
561 "%s %2d, %d %02d:%02d:%02d %s",
562 mon_names[tmp->tm_mon],
570 buf = wmem_strdup_printf(scope,
571 "%s %2d, %d %02d:%02d:%02d",
572 mon_names[tmp->tm_mon],
582 buf = wmem_strdup(scope, "Not representable");
587 display_epoch_time(gchar *buf, int buflen, const time_t sec, gint32 frac,
588 const to_str_time_res_t units)
592 elapsed_secs = difftime(sec,(time_t)0);
594 /* This code copied from display_signed_time; keep it in case anyone
595 is looking at captures from before 1970 (???).
596 If the fractional part of the time stamp is negative,
597 print its absolute value and, if the seconds part isn't
598 (the seconds part should be zero in that case), stick
599 a "-" in front of the entire time stamp. */
602 if (elapsed_secs >= 0) {
613 case TO_STR_TIME_RES_T_SECS:
614 g_snprintf(buf, buflen, "%0.0f", elapsed_secs);
617 case TO_STR_TIME_RES_T_DSECS:
618 g_snprintf(buf, buflen, "%0.0f.%01d", elapsed_secs, frac);
621 case TO_STR_TIME_RES_T_CSECS:
622 g_snprintf(buf, buflen, "%0.0f.%02d", elapsed_secs, frac);
625 case TO_STR_TIME_RES_T_MSECS:
626 g_snprintf(buf, buflen, "%0.0f.%03d", elapsed_secs, frac);
629 case TO_STR_TIME_RES_T_USECS:
630 g_snprintf(buf, buflen, "%0.0f.%06d", elapsed_secs, frac);
633 case TO_STR_TIME_RES_T_NSECS:
634 g_snprintf(buf, buflen, "%0.0f.%09d", elapsed_secs, frac);
640 display_signed_time(gchar *buf, int buflen, const gint32 sec, gint32 frac,
641 const to_str_time_res_t units)
643 /* this buffer is not NUL terminated */
644 gint8 num_buf[16]; /* max: '-2147483648', '.1000000000' */
645 gint8 *num_end = &num_buf[16];
652 /* If the fractional part of the time stamp is negative,
653 print its absolute value and, if the seconds part isn't
654 (the seconds part should be zero in that case), stick
655 a "-" in front of the entire time stamp. */
665 num_ptr = int_to_str_back(num_end, sec);
667 num_len = MIN((int) (num_end - num_ptr), buflen);
668 memcpy(buf, num_ptr, num_len);
673 case TO_STR_TIME_RES_T_SECS:
679 case TO_STR_TIME_RES_T_DSECS:
680 num_ptr = uint_to_str_back_len(num_end, frac, 1);
683 case TO_STR_TIME_RES_T_CSECS:
684 num_ptr = uint_to_str_back_len(num_end, frac, 2);
687 case TO_STR_TIME_RES_T_MSECS:
688 num_ptr = uint_to_str_back_len(num_end, frac, 3);
691 case TO_STR_TIME_RES_T_USECS:
692 num_ptr = uint_to_str_back_len(num_end, frac, 6);
695 case TO_STR_TIME_RES_T_NSECS:
696 num_ptr = uint_to_str_back_len(num_end, frac, 9);
704 num_len = MIN((int) (num_end - num_ptr), buflen);
705 memcpy(buf, num_ptr, num_len);
710 /* need to NUL terminate, we know that buffer had at least 1 byte */
716 #define PLURALIZE(n) (((n) > 1) ? "s" : "")
717 #define COMMA(do_it) ((do_it) ? ", " : "")
720 * Maximum length of a string showing days/hours/minutes/seconds.
721 * (Does not include the terminating '\0'.)
722 * Includes space for a '-' sign for any negative components.
723 * -12345 days, 12 hours, 12 minutes, 12.123 seconds
725 #define TIME_SECS_LEN (10+1+4+2+2+5+2+2+7+2+2+7+4)
728 * Convert an unsigned value in seconds and fractions of a second to a string,
729 * giving time in days, hours, minutes, and seconds, and put the result
731 * "is_nsecs" says that "frac" is nanoseconds if true and milliseconds
735 unsigned_time_secs_to_str_buf(guint32 time_val, const guint32 frac,
736 const gboolean is_nsecs, wmem_strbuf_t *buf)
738 int hours, mins, secs;
739 gboolean do_comma = FALSE;
741 secs = time_val % 60;
743 mins = time_val % 60;
745 hours = time_val % 24;
749 wmem_strbuf_append_printf(buf, "%u day%s", time_val, PLURALIZE(time_val));
753 wmem_strbuf_append_printf(buf, "%s%u hour%s", COMMA(do_comma), hours, PLURALIZE(hours));
757 wmem_strbuf_append_printf(buf, "%s%u minute%s", COMMA(do_comma), mins, PLURALIZE(mins));
760 if (secs != 0 || frac != 0) {
763 wmem_strbuf_append_printf(buf, "%s%u.%09u seconds", COMMA(do_comma), secs, frac);
765 wmem_strbuf_append_printf(buf, "%s%u.%03u seconds", COMMA(do_comma), secs, frac);
767 wmem_strbuf_append_printf(buf, "%s%u second%s", COMMA(do_comma), secs, PLURALIZE(secs));
772 unsigned_time_secs_to_str(wmem_allocator_t *scope, const guint32 time_val)
777 return wmem_strdup(scope, "0 seconds");
780 buf = wmem_strbuf_sized_new(scope, TIME_SECS_LEN+1, TIME_SECS_LEN+1);
782 unsigned_time_secs_to_str_buf(time_val, 0, FALSE, buf);
784 return wmem_strbuf_finalize(buf);
788 * Convert a signed value in seconds and fractions of a second to a string,
789 * giving time in days, hours, minutes, and seconds, and put the result
791 * "is_nsecs" says that "frac" is nanoseconds if true and milliseconds
795 signed_time_secs_to_str_buf(gint32 time_val, const guint32 frac,
796 const gboolean is_nsecs, wmem_strbuf_t *buf)
799 wmem_strbuf_append_printf(buf, "-");
800 if(time_val == G_MININT32) {
802 * You can't fit time_val's absolute value into
803 * a 32-bit signed integer. Just directly
804 * pass G_MAXUINT32, which is its absolute
805 * value, directly to unsigned_time_secs_to_str_buf().
807 * (XXX - does ISO C guarantee that -(-2^n),
808 * when calculated and cast to an n-bit unsigned
809 * integer type, will have the value 2^n?)
811 unsigned_time_secs_to_str_buf(G_MAXUINT32, frac,
815 * We now know -secs will fit into a guint32;
816 * negate it and pass that to
817 * unsigned_time_secs_to_str_buf().
819 unsigned_time_secs_to_str_buf(-time_val, frac,
823 unsigned_time_secs_to_str_buf(time_val, frac, is_nsecs, buf);
827 signed_time_secs_to_str(wmem_allocator_t *scope, const gint32 time_val)
832 return wmem_strdup(scope, "0 seconds");
835 buf = wmem_strbuf_sized_new(scope, TIME_SECS_LEN+1, TIME_SECS_LEN+1);
837 signed_time_secs_to_str_buf(time_val, 0, FALSE, buf);
839 return wmem_strbuf_finalize(buf);
843 * Convert a signed value in milliseconds to a string, giving time in days,
844 * hours, minutes, and seconds, and put the result into a buffer.
847 signed_time_msecs_to_str(wmem_allocator_t *scope, gint32 time_val)
853 return wmem_strdup(scope, "0 seconds");
856 buf = wmem_strbuf_sized_new(scope, TIME_SECS_LEN+1+3+1, TIME_SECS_LEN+1+3+1);
859 /* oops we got passed a negative time */
861 msecs = time_val % 1000;
865 msecs = time_val % 1000;
869 signed_time_secs_to_str_buf(time_val, msecs, FALSE, buf);
871 return wmem_strbuf_finalize(buf);
875 * Display a relative time as days/hours/minutes/seconds.
878 rel_time_to_str(wmem_allocator_t *scope, const nstime_t *rel_time)
884 /* If the nanoseconds part of the time stamp is negative,
885 print its absolute value and, if the seconds part isn't
886 (the seconds part should be zero in that case), stick
887 a "-" in front of the entire time stamp. */
888 time_val = (gint) rel_time->secs;
889 nsec = rel_time->nsecs;
890 if (time_val == 0 && nsec == 0) {
891 return wmem_strdup(scope, "0.000000000 seconds");
894 buf = wmem_strbuf_sized_new(scope, 1+TIME_SECS_LEN+1+6+1, 1+TIME_SECS_LEN+1+6+1);
898 wmem_strbuf_append_c(buf, '-');
901 * We assume here that "rel_time->secs" is negative
902 * or zero; if it's not, the time stamp is bogus,
903 * with a positive seconds and negative microseconds.
905 time_val = (gint) -rel_time->secs;
908 signed_time_secs_to_str_buf(time_val, nsec, TRUE, buf);
910 return wmem_strbuf_finalize(buf);
913 #define REL_TIME_SECS_LEN (1+10+1+9+1)
916 * Display a relative time as seconds.
919 rel_time_to_secs_str(wmem_allocator_t *scope, const nstime_t *rel_time)
923 buf=(gchar *)wmem_alloc(scope, REL_TIME_SECS_LEN);
925 display_signed_time(buf, REL_TIME_SECS_LEN, (gint32) rel_time->secs,
926 rel_time->nsecs, TO_STR_TIME_RES_T_NSECS);
931 * Generates a string representing the bits in a bitfield at "bit_offset" from an 8 bit boundary
932 * with the length in bits of no_of_bits based on value.
937 decode_bits_in_field(const guint bit_offset, const gint no_of_bits, const guint64 value)
939 guint64 mask = 0,tmp;
945 mask = mask << (no_of_bits-1);
947 /* Prepare the string, 256 pos for the bits and zero termination, + 64 for the spaces */
948 str=(char *)wmem_alloc0(wmem_packet_scope(), 256+64);
949 for(bit=0;bit<((int)(bit_offset&0x07));bit++){
958 /* read the bits for the int */
959 for(i=0;i<no_of_bits;i++){
992 This function is very fast and this function is called a lot.
993 XXX update the address_to_str stuff to use this function.
996 ip_to_str_buf(const guint8 *ad, gchar *buf, const int buf_len)
998 register gchar const *p;
999 register gchar *b=buf;
1001 if (buf_len < WS_INET_ADDRSTRLEN) {
1002 g_strlcpy(buf, BUF_TOO_SMALL_ERR, buf_len); /* Let the unexpected value alert user */
1006 p=fast_strings[*ad++];
1013 p=fast_strings[*ad++];
1020 p=fast_strings[*ad++];
1027 p=fast_strings[*ad];
1036 ip6_to_str_buf_with_pfx(const ws_in6_addr *addr, gchar *buf, int buf_size, const char *prefix)
1038 int bytes; /* the number of bytes which would be produced if the buffer was large enough. */
1039 gchar addr_buf[WS_INET6_ADDRSTRLEN];
1044 bytes = g_snprintf(buf, buf_size, "%s%s", prefix, ws_inet_ntop6(addr, addr_buf, sizeof(addr_buf)));
1047 if (len > buf_size - 1) { /* size minus nul terminator */
1048 len = (int)g_strlcpy(buf, BUF_TOO_SMALL_ERR, buf_size); /* Let the unexpected value alert user */
1054 ip6_to_str_buf(const ws_in6_addr *addr, gchar *buf, int buf_size)
1056 gchar addr_buf[WS_INET6_ADDRSTRLEN];
1059 /* slightly more efficient than ip6_to_str_buf_with_pfx(addr, buf, buf_size, NULL) */
1060 len = (int)g_strlcpy(buf, ws_inet_ntop6(addr, addr_buf, sizeof(addr_buf)), buf_size); /* this returns len = strlen(addr_buf) */
1062 if (len > buf_size - 1) { /* size minus nul terminator */
1063 len = (int)g_strlcpy(buf, BUF_TOO_SMALL_ERR, buf_size); /* Let the unexpected value alert user */
1069 guid_to_str(wmem_allocator_t *scope, const e_guid_t *guid)
1073 buf=(gchar *)wmem_alloc(scope, GUID_STR_LEN);
1074 return guid_to_str_buf(guid, buf, GUID_STR_LEN);
1078 guid_to_str_buf(const e_guid_t *guid, gchar *buf, int buf_len)
1080 char *tempptr = buf;
1082 if (buf_len < GUID_STR_LEN) {
1083 g_strlcpy(buf, BUF_TOO_SMALL_ERR, buf_len);/* Let the unexpected value alert user */
1088 tempptr = dword_to_hex(tempptr, guid->data1); /* 8 bytes */
1089 *tempptr++ = '-'; /* 1 byte */
1090 tempptr = word_to_hex(tempptr, guid->data2); /* 4 bytes */
1091 *tempptr++ = '-'; /* 1 byte */
1092 tempptr = word_to_hex(tempptr, guid->data3); /* 4 bytes */
1093 *tempptr++ = '-'; /* 1 byte */
1094 tempptr = bytes_to_hexstr(tempptr, &guid->data4[0], 2); /* 4 bytes */
1095 *tempptr++ = '-'; /* 1 byte */
1096 tempptr = bytes_to_hexstr(tempptr, &guid->data4[2], 6); /* 12 bytes */
1103 eui64_to_str(wmem_allocator_t *scope, const guint64 ad) {
1107 p_eui64=(guint8 *)wmem_alloc(NULL, 8);
1108 buf=(gchar *)wmem_alloc(scope, EUI64_STR_LEN);
1110 /* Copy and convert the address to network byte order. */
1111 *(guint64 *)(void *)(p_eui64) = pntoh64(&(ad));
1113 tmp = bytes_to_hexstr_punct(buf, p_eui64, 8, ':');
1114 *tmp = '\0'; /* NULL terminate */
1115 wmem_free(NULL, p_eui64);
1120 port_type_to_str (port_type type)
1123 case PT_NONE: return "NONE";
1124 case PT_SCTP: return "SCTP";
1125 case PT_TCP: return "TCP";
1126 case PT_UDP: return "UDP";
1127 case PT_DCCP: return "DCCP";
1128 case PT_IPX: return "IPX";
1129 case PT_DDP: return "DDP";
1130 case PT_IDP: return "IDP";
1131 case PT_USB: return "USB";
1132 case PT_I2C: return "I2C";
1133 case PT_IBQP: return "IBQP";
1134 case PT_BLUETOOTH: return "BLUETOOTH";
1135 default: return "[Unknown]";
1140 oct_to_str_back(char *ptr, guint32 value)
1143 *(--ptr) = '0' + (value & 0x7);
1152 oct64_to_str_back(char *ptr, guint64 value)
1155 *(--ptr) = '0' + (value & 0x7);
1164 hex_to_str_back(char *ptr, int len, guint32 value)
1167 *(--ptr) = low_nibble_of_octet_to_hex(value);
1185 hex64_to_str_back(char *ptr, int len, guint64 value)
1188 *(--ptr) = low_nibble_of_octet_to_hex(value & 0xF);
1206 uint_to_str_back(char *ptr, guint32 value)
1214 while (value >= 10) {
1215 p = fast_strings[100 + (value % 100)];
1224 *(--ptr) = (value) | '0';
1230 uint64_to_str_back(char *ptr, guint64 value)
1238 while (value >= 10) {
1239 p = fast_strings[100 + (value % 100)];
1247 /* value will be 0..9, so using '& 0xF' is safe, and faster than '% 10' */
1249 *(--ptr) = (value & 0xF) | '0';
1255 uint_to_str_back_len(char *ptr, guint32 value, int len)
1259 new_ptr = uint_to_str_back(ptr, value);
1261 /* substract from len number of generated characters */
1262 len -= (int)(ptr - new_ptr);
1264 /* pad remaining with '0' */
1275 uint64_to_str_back_len(char *ptr, guint64 value, int len)
1279 new_ptr = uint64_to_str_back(ptr, value);
1281 /* substract from len number of generated characters */
1282 len -= (int)(ptr - new_ptr);
1284 /* pad remaining with '0' */
1295 int_to_str_back(char *ptr, gint32 value)
1298 ptr = uint_to_str_back(ptr, -value);
1301 ptr = uint_to_str_back(ptr, value);
1307 int64_to_str_back(char *ptr, gint64 value)
1310 ptr = uint64_to_str_back(ptr, -value);
1313 ptr = uint64_to_str_back(ptr, value);
1319 * Editor modelines - http://www.wireshark.org/tools/modelines.html
1324 * indent-tabs-mode: t
1327 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1328 * :indentSize=8:tabSize=8:noTabs=false: