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 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include "wmem/wmem.h"
33 #include "to_str-int.h"
35 #include <wsutil/pint.h>
38 * If a user _does_ pass in a too-small buffer, this is probably
39 * going to be too long to fit. However, even a partial string
40 * starting with "[Buf" should provide enough of a clue to be
43 #define BUF_TOO_SMALL_ERR "[Buffer too small]"
46 low_nibble_of_octet_to_hex(guint8 oct)
48 /* At least one version of Apple's C compiler/linker is buggy, causing
49 a complaint from the linker about the "literal C string section"
50 not ending with '\0' if we initialize a 16-element "char" array with
51 a 16-character string, the fact that initializing such an array with
52 such a string is perfectly legitimate ANSI C nonwithstanding, the 17th
53 '\0' byte in the string nonwithstanding. */
54 static const gchar hex_digits[16] =
55 { '0', '1', '2', '3', '4', '5', '6', '7',
56 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
58 return hex_digits[oct & 0xF];
62 byte_to_hex(char *out, guint32 dword)
64 *out++ = low_nibble_of_octet_to_hex(dword >> 4);
65 *out++ = low_nibble_of_octet_to_hex(dword);
70 guint8_to_hex(char *out, guint8 val)
72 return byte_to_hex(out, val);
76 word_to_hex(char *out, guint16 word)
78 out = byte_to_hex(out, word >> 8);
79 out = byte_to_hex(out, word);
84 word_to_hex_punct(char *out, guint16 word, char punct)
86 out = byte_to_hex(out, word >> 8);
88 out = byte_to_hex(out, word);
93 word_to_hex_npad(char *out, guint16 word)
96 *out++ = low_nibble_of_octet_to_hex((guint8)(word >> 12));
98 *out++ = low_nibble_of_octet_to_hex((guint8)(word >> 8));
100 *out++ = low_nibble_of_octet_to_hex((guint8)(word >> 4));
101 *out++ = low_nibble_of_octet_to_hex((guint8)(word >> 0));
106 dword_to_hex(char *out, guint32 dword)
108 out = word_to_hex(out, dword >> 16);
109 out = word_to_hex(out, dword);
114 dword_to_hex_punct(char *out, guint32 dword, char punct)
116 out = word_to_hex_punct(out, dword >> 16, punct);
118 out = word_to_hex_punct(out, dword, punct);
123 qword_to_hex(char *out, guint64 qword)
125 out = dword_to_hex(out, (guint32)(qword >> 32));
126 out = dword_to_hex(out, (guint32)(qword & 0xffffffff));
131 qword_to_hex_punct(char *out, guint64 qword, char punct)
133 out = dword_to_hex_punct(out, (guint32)(qword >> 32), punct);
135 out = dword_to_hex_punct(out, (guint32)(qword & 0xffffffff), punct);
140 * This does *not* null-terminate the string. It returns a pointer
141 * to the position in the string following the last character it
142 * puts there, so that the caller can either put the null terminator
143 * in or can append more stuff to the buffer.
145 * There needs to be at least len * 2 bytes left in the buffer.
148 bytes_to_hexstr(char *out, const guint8 *ad, guint32 len)
153 REPORT_DISSECTOR_BUG("Null pointer passed to bytes_to_hexstr()");
155 for (i = 0; i < len; i++)
156 out = byte_to_hex(out, ad[i]);
161 * This does *not* null-terminate the string. It returns a pointer
162 * to the position in the string following the last character it
163 * puts there, so that the caller can either put the null terminator
164 * in or can append more stuff to the buffer.
166 * There needs to be at least len * 3 - 1 bytes left in the buffer.
169 bytes_to_hexstr_punct(char *out, const guint8 *ad, guint32 len, char punct)
174 REPORT_DISSECTOR_BUG("Null pointer passed to bytes_to_hexstr_punct()");
176 out = byte_to_hex(out, ad[0]);
177 for (i = 1; i < len; i++) {
179 out = byte_to_hex(out, ad[i]);
184 /* Max string length for displaying byte string. */
185 #define MAX_BYTE_STR_LEN 48
187 /* Routine to convert a sequence of bytes to a hex string, one byte/two hex
188 * digits at at a time, with a specified punctuation character between
191 * If punct is '\0', no punctuation is applied (and thus
192 * the resulting string is (len-1) bytes shorter)
195 bytestring_to_str(wmem_allocator_t *scope, const guint8 *ad, const guint32 len, const char punct)
198 guint32 buflen = len;
203 return bytes_to_str(scope, ad, len);
206 REPORT_DISSECTOR_BUG("Null pointer passed to bytestring_to_str()");
209 return wmem_strdup(scope, "");
211 buf=(gchar *)wmem_alloc(scope, MAX_BYTE_STR_LEN+3+1);
212 if (buflen > MAX_BYTE_STR_LEN/3) { /* bd_len > 16 */
214 buflen = MAX_BYTE_STR_LEN/3;
217 buf_ptr = bytes_to_hexstr_punct(buf, ad, buflen, punct); /* max MAX_BYTE_STR_LEN-1 bytes */
220 *buf_ptr++ = punct; /* 1 byte */
221 buf_ptr = g_stpcpy(buf_ptr, "..."); /* 3 bytes */
229 bytes_to_str(wmem_allocator_t *scope, const guint8 *bd, int bd_len)
236 REPORT_DISSECTOR_BUG("Null pointer passed to bytes_to_str()");
238 cur=(gchar *)wmem_alloc(scope, MAX_BYTE_STR_LEN+3+1);
239 if (bd_len <= 0) { cur[0] = '\0'; return cur; }
241 if (bd_len > MAX_BYTE_STR_LEN/2) { /* bd_len > 24 */
243 bd_len = MAX_BYTE_STR_LEN/2;
246 cur_ptr = bytes_to_hexstr(cur, bd, bd_len); /* max MAX_BYTE_STR_LEN bytes */
249 cur_ptr = g_stpcpy(cur_ptr, "..."); /* 3 bytes */
251 *cur_ptr = '\0'; /* 1 byte */
256 guint32_to_str_buf_len(const guint32 u)
258 /* ((2^32)-1) == 2147483647 */
259 if (u >= 1000000000)return 10;
260 if (u >= 100000000) return 9;
261 if (u >= 10000000) return 8;
262 if (u >= 1000000) return 7;
263 if (u >= 100000) return 6;
264 if (u >= 10000) return 5;
265 if (u >= 1000) return 4;
266 if (u >= 100) return 3;
267 if (u >= 10) return 2;
273 guint64_to_str_buf_len(const guint64 u)
275 /* ((2^64)-1) == 18446744073709551615 */
277 if (u >= G_GUINT64_CONSTANT(10000000000000000000)) return 20;
278 if (u >= G_GUINT64_CONSTANT(1000000000000000000)) return 19;
279 if (u >= G_GUINT64_CONSTANT(100000000000000000)) return 18;
280 if (u >= G_GUINT64_CONSTANT(10000000000000000)) return 17;
281 if (u >= G_GUINT64_CONSTANT(1000000000000000)) return 16;
282 if (u >= G_GUINT64_CONSTANT(100000000000000)) return 15;
283 if (u >= G_GUINT64_CONSTANT(10000000000000)) return 14;
284 if (u >= G_GUINT64_CONSTANT(1000000000000)) return 13;
285 if (u >= G_GUINT64_CONSTANT(100000000000)) return 12;
286 if (u >= G_GUINT64_CONSTANT(10000000000)) return 11;
287 if (u >= G_GUINT64_CONSTANT(1000000000)) return 10;
288 if (u >= G_GUINT64_CONSTANT(100000000)) return 9;
289 if (u >= G_GUINT64_CONSTANT(10000000)) return 8;
290 if (u >= G_GUINT64_CONSTANT(1000000)) return 7;
291 if (u >= G_GUINT64_CONSTANT(100000)) return 6;
292 if (u >= G_GUINT64_CONSTANT(10000)) return 5;
293 if (u >= G_GUINT64_CONSTANT(1000)) return 4;
294 if (u >= G_GUINT64_CONSTANT(100)) return 3;
295 if (u >= G_GUINT64_CONSTANT(10)) return 2;
300 static const char fast_strings[][4] = {
301 "0", "1", "2", "3", "4", "5", "6", "7",
302 "8", "9", "10", "11", "12", "13", "14", "15",
303 "16", "17", "18", "19", "20", "21", "22", "23",
304 "24", "25", "26", "27", "28", "29", "30", "31",
305 "32", "33", "34", "35", "36", "37", "38", "39",
306 "40", "41", "42", "43", "44", "45", "46", "47",
307 "48", "49", "50", "51", "52", "53", "54", "55",
308 "56", "57", "58", "59", "60", "61", "62", "63",
309 "64", "65", "66", "67", "68", "69", "70", "71",
310 "72", "73", "74", "75", "76", "77", "78", "79",
311 "80", "81", "82", "83", "84", "85", "86", "87",
312 "88", "89", "90", "91", "92", "93", "94", "95",
313 "96", "97", "98", "99", "100", "101", "102", "103",
314 "104", "105", "106", "107", "108", "109", "110", "111",
315 "112", "113", "114", "115", "116", "117", "118", "119",
316 "120", "121", "122", "123", "124", "125", "126", "127",
317 "128", "129", "130", "131", "132", "133", "134", "135",
318 "136", "137", "138", "139", "140", "141", "142", "143",
319 "144", "145", "146", "147", "148", "149", "150", "151",
320 "152", "153", "154", "155", "156", "157", "158", "159",
321 "160", "161", "162", "163", "164", "165", "166", "167",
322 "168", "169", "170", "171", "172", "173", "174", "175",
323 "176", "177", "178", "179", "180", "181", "182", "183",
324 "184", "185", "186", "187", "188", "189", "190", "191",
325 "192", "193", "194", "195", "196", "197", "198", "199",
326 "200", "201", "202", "203", "204", "205", "206", "207",
327 "208", "209", "210", "211", "212", "213", "214", "215",
328 "216", "217", "218", "219", "220", "221", "222", "223",
329 "224", "225", "226", "227", "228", "229", "230", "231",
330 "232", "233", "234", "235", "236", "237", "238", "239",
331 "240", "241", "242", "243", "244", "245", "246", "247",
332 "248", "249", "250", "251", "252", "253", "254", "255"
336 guint32_to_str_buf(guint32 u, gchar *buf, int buf_len)
338 int str_len = guint32_to_str_buf_len(u)+1;
340 gchar *bp = &buf[str_len];
342 if (buf_len < str_len) {
343 g_strlcpy(buf, BUF_TOO_SMALL_ERR, buf_len); /* Let the unexpected value alert user */
349 uint_to_str_back(bp, u);
353 guint64_to_str_buf(guint64 u, gchar *buf, int buf_len)
355 int str_len = guint64_to_str_buf_len(u)+1;
357 gchar *bp = &buf[str_len];
359 if (buf_len < str_len) {
360 g_strlcpy(buf, BUF_TOO_SMALL_ERR, buf_len); /* Let the unexpected value alert user */
366 uint64_to_str_back(bp, u);
369 static const char mon_names[12][4] = {
385 get_zonename(struct tm *tmp)
388 /* Windows C Runtime: */
389 /* _tzname is encoded using the "system default ansi code page" */
390 /* ("which is not necessarily the same as the C library locale"). */
391 /* So: _tzname must be converted to UTF8 before use. */
392 /* Alternative: use Windows GetTimeZoneInformation() to get the */
393 /* timezone name in UTF16 and convert same to UTF8. */
394 /* XXX: the result is that the timezone name will be based upon the */
395 /* system code page (iow: the charset of the system). */
396 /* Since Wireshark is not internationalized, it would seem more */
397 /* correct to show the timezone name in English, no matter what */
398 /* the system code page, but I don't how to do that (or if it's */
399 /* really even possible). */
400 /* In any case converting to UTF8 presumably at least keeps GTK */
401 /* happy. (A bug was reported wherein Wireshark crashed in GDK */
402 /* on a "Japanese version of Windows XP" when trying to copy */
403 /* the date/time string (containing a copy of _tz_name) to the */
405 static char *ws_tzname[2] = {NULL, NULL};
407 /* The g_malloc'd value returned from g_locale_to_utf8() is */
408 /* cached for all further use so there's no need to ever */
409 /* g_free() that value. */
410 if (ws_tzname[tmp->tm_isdst] == NULL) {
411 ws_tzname[tmp->tm_isdst] = g_locale_to_utf8(_tzname[tmp->tm_isdst], -1, NULL, NULL, NULL);
412 if (ws_tzname[tmp->tm_isdst] == NULL) {
413 ws_tzname[tmp->tm_isdst] = "???";
416 return ws_tzname[tmp->tm_isdst];
421 * If we have tm_zone in struct tm, use that.
422 * Otherwise, if we have tzname[], use it, otherwise just
423 * say "we don't know.
425 # if defined(HAVE_STRUCT_TM_TM_ZONE)
427 # else /* HAVE_STRUCT_TM_TM_ZONE */
428 if ((tmp->tm_isdst != 0) && (tmp->tm_isdst != 1)) {
431 # if defined(HAVE_TZNAME)
432 return tzname[tmp->tm_isdst];
434 return tmp->tm_isdst ? "?DT" : "?ST";
435 # endif /* HAVE_TZNAME */
436 # endif /* HAVE_STRUCT_TM_TM_ZONE */
441 abs_time_to_str(wmem_allocator_t *scope, const nstime_t *abs_time, const absolute_time_display_e fmt,
444 struct tm *tmp = NULL;
445 const char *zonename = "???";
451 case ABSOLUTE_TIME_UTC:
452 case ABSOLUTE_TIME_DOY_UTC:
453 tmp = gmtime(&abs_time->secs);
457 case ABSOLUTE_TIME_LOCAL:
458 tmp = localtime(&abs_time->secs);
460 zonename = get_zonename(tmp);
467 case ABSOLUTE_TIME_DOY_UTC:
469 buf = wmem_strdup_printf(scope,
470 "%04d/%03d:%02d:%02d:%02d.%09ld %s",
476 (long)abs_time->nsecs,
479 buf = wmem_strdup_printf(scope,
480 "%04d/%03d:%02d:%02d:%02d.%09ld",
486 (long)abs_time->nsecs);
490 case ABSOLUTE_TIME_UTC:
491 case ABSOLUTE_TIME_LOCAL:
493 buf = wmem_strdup_printf(scope,
494 "%s %2d, %d %02d:%02d:%02d.%09ld %s",
495 mon_names[tmp->tm_mon],
501 (long)abs_time->nsecs,
504 buf = wmem_strdup_printf(scope,
505 "%s %2d, %d %02d:%02d:%02d.%09ld",
506 mon_names[tmp->tm_mon],
512 (long)abs_time->nsecs);
517 buf = wmem_strdup(scope, "Not representable");
522 abs_time_secs_to_str(wmem_allocator_t *scope, const time_t abs_time, const absolute_time_display_e fmt,
525 struct tm *tmp = NULL;
526 const char *zonename = "???";
531 case ABSOLUTE_TIME_UTC:
532 case ABSOLUTE_TIME_DOY_UTC:
533 tmp = gmtime(&abs_time);
537 case ABSOLUTE_TIME_LOCAL:
538 tmp = localtime(&abs_time);
540 zonename = get_zonename(tmp);
547 case ABSOLUTE_TIME_DOY_UTC:
549 buf = wmem_strdup_printf(scope,
550 "%04d/%03d:%02d:%02d:%02d %s",
558 buf = wmem_strdup_printf(scope,
559 "%04d/%03d:%02d:%02d:%02d",
568 case ABSOLUTE_TIME_UTC:
569 case ABSOLUTE_TIME_LOCAL:
571 buf = wmem_strdup_printf(scope,
572 "%s %2d, %d %02d:%02d:%02d %s",
573 mon_names[tmp->tm_mon],
581 buf = wmem_strdup_printf(scope,
582 "%s %2d, %d %02d:%02d:%02d",
583 mon_names[tmp->tm_mon],
593 buf = wmem_strdup(scope, "Not representable");
598 display_epoch_time(gchar *buf, int buflen, const time_t sec, gint32 frac,
599 const to_str_time_res_t units)
603 elapsed_secs = difftime(sec,(time_t)0);
605 /* This code copied from display_signed_time; keep it in case anyone
606 is looking at captures from before 1970 (???).
607 If the fractional part of the time stamp is negative,
608 print its absolute value and, if the seconds part isn't
609 (the seconds part should be zero in that case), stick
610 a "-" in front of the entire time stamp. */
613 if (elapsed_secs >= 0) {
624 case TO_STR_TIME_RES_T_SECS:
625 g_snprintf(buf, buflen, "%0.0f", elapsed_secs);
628 case TO_STR_TIME_RES_T_DSECS:
629 g_snprintf(buf, buflen, "%0.0f.%01d", elapsed_secs, frac);
632 case TO_STR_TIME_RES_T_CSECS:
633 g_snprintf(buf, buflen, "%0.0f.%02d", elapsed_secs, frac);
636 case TO_STR_TIME_RES_T_MSECS:
637 g_snprintf(buf, buflen, "%0.0f.%03d", elapsed_secs, frac);
640 case TO_STR_TIME_RES_T_USECS:
641 g_snprintf(buf, buflen, "%0.0f.%06d", elapsed_secs, frac);
644 case TO_STR_TIME_RES_T_NSECS:
645 g_snprintf(buf, buflen, "%0.0f.%09d", elapsed_secs, frac);
651 display_signed_time(gchar *buf, int buflen, const gint32 sec, gint32 frac,
652 const to_str_time_res_t units)
654 /* this buffer is not NUL terminated */
655 gint8 num_buf[16]; /* max: '-2147483648', '.1000000000' */
656 gint8 *num_end = &num_buf[16];
663 /* If the fractional part of the time stamp is negative,
664 print its absolute value and, if the seconds part isn't
665 (the seconds part should be zero in that case), stick
666 a "-" in front of the entire time stamp. */
676 num_ptr = int_to_str_back(num_end, sec);
678 num_len = MIN((int) (num_end - num_ptr), buflen);
679 memcpy(buf, num_ptr, num_len);
684 case TO_STR_TIME_RES_T_SECS:
690 case TO_STR_TIME_RES_T_DSECS:
691 num_ptr = uint_to_str_back_len(num_end, frac, 1);
694 case TO_STR_TIME_RES_T_CSECS:
695 num_ptr = uint_to_str_back_len(num_end, frac, 2);
698 case TO_STR_TIME_RES_T_MSECS:
699 num_ptr = uint_to_str_back_len(num_end, frac, 3);
702 case TO_STR_TIME_RES_T_USECS:
703 num_ptr = uint_to_str_back_len(num_end, frac, 6);
706 case TO_STR_TIME_RES_T_NSECS:
707 num_ptr = uint_to_str_back_len(num_end, frac, 9);
715 num_len = MIN((int) (num_end - num_ptr), buflen);
716 memcpy(buf, num_ptr, num_len);
721 /* need to NUL terminate, we know that buffer had at least 1 byte */
727 #define PLURALIZE(n) (((n) > 1) ? "s" : "")
728 #define COMMA(do_it) ((do_it) ? ", " : "")
731 * Maximum length of a string showing days/hours/minutes/seconds.
732 * (Does not include the terminating '\0'.)
733 * Includes space for a '-' sign for any negative components.
734 * -12345 days, 12 hours, 12 minutes, 12.123 seconds
736 #define TIME_SECS_LEN (10+1+4+2+2+5+2+2+7+2+2+7+4)
739 * Convert an unsigned value in seconds and fractions of a second to a string,
740 * giving time in days, hours, minutes, and seconds, and put the result
742 * "is_nsecs" says that "frac" is nanoseconds if true and milliseconds
746 unsigned_time_secs_to_str_buf(guint32 time_val, const guint32 frac,
747 const gboolean is_nsecs, wmem_strbuf_t *buf)
749 int hours, mins, secs;
750 gboolean do_comma = FALSE;
752 secs = time_val % 60;
754 mins = time_val % 60;
756 hours = time_val % 24;
760 wmem_strbuf_append_printf(buf, "%u day%s", time_val, PLURALIZE(time_val));
764 wmem_strbuf_append_printf(buf, "%s%u hour%s", COMMA(do_comma), hours, PLURALIZE(hours));
768 wmem_strbuf_append_printf(buf, "%s%u minute%s", COMMA(do_comma), mins, PLURALIZE(mins));
771 if (secs != 0 || frac != 0) {
774 wmem_strbuf_append_printf(buf, "%s%u.%09u seconds", COMMA(do_comma), secs, frac);
776 wmem_strbuf_append_printf(buf, "%s%u.%03u seconds", COMMA(do_comma), secs, frac);
778 wmem_strbuf_append_printf(buf, "%s%u second%s", COMMA(do_comma), secs, PLURALIZE(secs));
783 unsigned_time_secs_to_str(wmem_allocator_t *scope, const guint32 time_val)
788 return wmem_strdup(scope, "0 seconds");
791 buf = wmem_strbuf_sized_new(scope, TIME_SECS_LEN+1, TIME_SECS_LEN+1);
793 unsigned_time_secs_to_str_buf(time_val, 0, FALSE, buf);
795 return wmem_strbuf_finalize(buf);
799 * Convert a signed value in seconds and fractions of a second to a string,
800 * giving time in days, hours, minutes, and seconds, and put the result
802 * "is_nsecs" says that "frac" is nanoseconds if true and milliseconds
806 signed_time_secs_to_str_buf(gint32 time_val, const guint32 frac,
807 const gboolean is_nsecs, wmem_strbuf_t *buf)
810 wmem_strbuf_append_printf(buf, "-");
811 if(time_val == G_MININT32) {
813 * You can't fit time_val's absolute value into
814 * a 32-bit signed integer. Just directly
815 * pass G_MAXUINT32, which is its absolute
816 * value, directly to unsigned_time_secs_to_str_buf().
818 * (XXX - does ISO C guarantee that -(-2^n),
819 * when calculated and cast to an n-bit unsigned
820 * integer type, will have the value 2^n?)
822 unsigned_time_secs_to_str_buf(G_MAXUINT32, frac,
826 * We now know -secs will fit into a guint32;
827 * negate it and pass that to
828 * unsigned_time_secs_to_str_buf().
830 unsigned_time_secs_to_str_buf(-time_val, frac,
834 unsigned_time_secs_to_str_buf(time_val, frac, is_nsecs, buf);
838 signed_time_secs_to_str(wmem_allocator_t *scope, const gint32 time_val)
843 return wmem_strdup(scope, "0 seconds");
846 buf = wmem_strbuf_sized_new(scope, TIME_SECS_LEN+1, TIME_SECS_LEN+1);
848 signed_time_secs_to_str_buf(time_val, 0, FALSE, buf);
850 return wmem_strbuf_finalize(buf);
854 * Convert a signed value in milliseconds to a string, giving time in days,
855 * hours, minutes, and seconds, and put the result into a buffer.
858 signed_time_msecs_to_str(wmem_allocator_t *scope, gint32 time_val)
864 return wmem_strdup(scope, "0 seconds");
867 buf = wmem_strbuf_sized_new(scope, TIME_SECS_LEN+1+3+1, TIME_SECS_LEN+1+3+1);
870 /* oops we got passed a negative time */
872 msecs = time_val % 1000;
876 msecs = time_val % 1000;
880 signed_time_secs_to_str_buf(time_val, msecs, FALSE, buf);
882 return wmem_strbuf_finalize(buf);
886 * Display a relative time as days/hours/minutes/seconds.
889 rel_time_to_str(wmem_allocator_t *scope, const nstime_t *rel_time)
895 /* If the nanoseconds part of the time stamp is negative,
896 print its absolute value and, if the seconds part isn't
897 (the seconds part should be zero in that case), stick
898 a "-" in front of the entire time stamp. */
899 time_val = (gint) rel_time->secs;
900 nsec = rel_time->nsecs;
901 if (time_val == 0 && nsec == 0) {
902 return wmem_strdup(scope, "0.000000000 seconds");
905 buf = wmem_strbuf_sized_new(scope, 1+TIME_SECS_LEN+1+6+1, 1+TIME_SECS_LEN+1+6+1);
909 wmem_strbuf_append_c(buf, '-');
912 * We assume here that "rel_time->secs" is negative
913 * or zero; if it's not, the time stamp is bogus,
914 * with a positive seconds and negative microseconds.
916 time_val = (gint) -rel_time->secs;
919 signed_time_secs_to_str_buf(time_val, nsec, TRUE, buf);
921 return wmem_strbuf_finalize(buf);
924 #define REL_TIME_SECS_LEN (1+10+1+9+1)
927 * Display a relative time as seconds.
930 rel_time_to_secs_str(wmem_allocator_t *scope, const nstime_t *rel_time)
934 buf=(gchar *)wmem_alloc(scope, REL_TIME_SECS_LEN);
936 display_signed_time(buf, REL_TIME_SECS_LEN, (gint32) rel_time->secs,
937 rel_time->nsecs, TO_STR_TIME_RES_T_NSECS);
942 * Generates a string representing the bits in a bitfield at "bit_offset" from an 8 bit boundary
943 * with the length in bits of no_of_bits based on value.
948 decode_bits_in_field(const guint bit_offset, const gint no_of_bits, const guint64 value)
950 guint64 mask = 0,tmp;
956 mask = mask << (no_of_bits-1);
958 /* Prepare the string, 256 pos for the bits and zero termination, + 64 for the spaces */
959 str=(char *)wmem_alloc0(wmem_packet_scope(), 256+64);
960 for(bit=0;bit<((int)(bit_offset&0x07));bit++){
969 /* read the bits for the int */
970 for(i=0;i<no_of_bits;i++){
1003 This function is very fast and this function is called a lot.
1004 XXX update the address_to_str stuff to use this function.
1007 ip_to_str_buf(const guint8 *ad, gchar *buf, const int buf_len)
1009 register gchar const *p;
1010 register gchar *b=buf;
1012 if (buf_len < WS_INET_ADDRSTRLEN) {
1013 g_strlcpy(buf, BUF_TOO_SMALL_ERR, buf_len); /* Let the unexpected value alert user */
1017 p=fast_strings[*ad++];
1024 p=fast_strings[*ad++];
1031 p=fast_strings[*ad++];
1038 p=fast_strings[*ad];
1047 ip6_to_str_buf_with_pfx(const ws_in6_addr *addr, gchar *buf, int buf_size, const char *prefix)
1049 int bytes; /* the number of bytes which would be produced if the buffer was large enough. */
1050 gchar addr_buf[WS_INET6_ADDRSTRLEN];
1055 bytes = g_snprintf(buf, buf_size, "%s%s", prefix, ws_inet_ntop6(addr, addr_buf, sizeof(addr_buf)));
1058 if (len > buf_size - 1) { /* size minus nul terminator */
1059 len = (int)g_strlcpy(buf, BUF_TOO_SMALL_ERR, buf_size); /* Let the unexpected value alert user */
1065 ip6_to_str_buf(const ws_in6_addr *addr, gchar *buf, int buf_size)
1067 gchar addr_buf[WS_INET6_ADDRSTRLEN];
1070 /* slightly more efficient than ip6_to_str_buf_with_pfx(addr, buf, buf_size, NULL) */
1071 len = (int)g_strlcpy(buf, ws_inet_ntop6(addr, addr_buf, sizeof(addr_buf)), buf_size); /* this returns len = strlen(addr_buf) */
1073 if (len > buf_size - 1) { /* size minus nul terminator */
1074 len = (int)g_strlcpy(buf, BUF_TOO_SMALL_ERR, buf_size); /* Let the unexpected value alert user */
1080 guid_to_str(wmem_allocator_t *scope, const e_guid_t *guid)
1084 buf=(gchar *)wmem_alloc(scope, GUID_STR_LEN);
1085 return guid_to_str_buf(guid, buf, GUID_STR_LEN);
1089 guid_to_str_buf(const e_guid_t *guid, gchar *buf, int buf_len)
1091 char *tempptr = buf;
1093 if (buf_len < GUID_STR_LEN) {
1094 g_strlcpy(buf, BUF_TOO_SMALL_ERR, buf_len);/* Let the unexpected value alert user */
1099 tempptr = dword_to_hex(tempptr, guid->data1); /* 8 bytes */
1100 *tempptr++ = '-'; /* 1 byte */
1101 tempptr = word_to_hex(tempptr, guid->data2); /* 4 bytes */
1102 *tempptr++ = '-'; /* 1 byte */
1103 tempptr = word_to_hex(tempptr, guid->data3); /* 4 bytes */
1104 *tempptr++ = '-'; /* 1 byte */
1105 tempptr = bytes_to_hexstr(tempptr, &guid->data4[0], 2); /* 4 bytes */
1106 *tempptr++ = '-'; /* 1 byte */
1107 tempptr = bytes_to_hexstr(tempptr, &guid->data4[2], 6); /* 12 bytes */
1114 eui64_to_str(wmem_allocator_t *scope, const guint64 ad) {
1118 p_eui64=(guint8 *)wmem_alloc(NULL, 8);
1119 buf=(gchar *)wmem_alloc(scope, EUI64_STR_LEN);
1121 /* Copy and convert the address to network byte order. */
1122 *(guint64 *)(void *)(p_eui64) = pntoh64(&(ad));
1124 tmp = bytes_to_hexstr_punct(buf, p_eui64, 8, ':');
1125 *tmp = '\0'; /* NULL terminate */
1126 wmem_free(NULL, p_eui64);
1131 port_type_to_str (port_type type)
1134 case PT_NONE: return "NONE";
1135 case PT_SCTP: return "SCTP";
1136 case PT_TCP: return "TCP";
1137 case PT_UDP: return "UDP";
1138 case PT_DCCP: return "DCCP";
1139 case PT_IPX: return "IPX";
1140 case PT_DDP: return "DDP";
1141 case PT_IDP: return "IDP";
1142 case PT_USB: return "USB";
1143 case PT_I2C: return "I2C";
1144 case PT_IBQP: return "IBQP";
1145 case PT_BLUETOOTH: return "BLUETOOTH";
1146 default: return "[Unknown]";
1151 oct_to_str_back(char *ptr, guint32 value)
1154 *(--ptr) = '0' + (value & 0x7);
1163 oct64_to_str_back(char *ptr, guint64 value)
1166 *(--ptr) = '0' + (value & 0x7);
1175 hex_to_str_back(char *ptr, int len, guint32 value)
1178 *(--ptr) = low_nibble_of_octet_to_hex(value);
1196 hex64_to_str_back(char *ptr, int len, guint64 value)
1199 *(--ptr) = low_nibble_of_octet_to_hex(value & 0xF);
1217 uint_to_str_back(char *ptr, guint32 value)
1225 while (value >= 10) {
1226 p = fast_strings[100 + (value % 100)];
1235 *(--ptr) = (value) | '0';
1241 uint64_to_str_back(char *ptr, guint64 value)
1249 while (value >= 10) {
1250 p = fast_strings[100 + (value % 100)];
1258 /* value will be 0..9, so using '& 0xF' is safe, and faster than '% 10' */
1260 *(--ptr) = (value & 0xF) | '0';
1266 uint_to_str_back_len(char *ptr, guint32 value, int len)
1270 new_ptr = uint_to_str_back(ptr, value);
1272 /* substract from len number of generated characters */
1273 len -= (int)(ptr - new_ptr);
1275 /* pad remaining with '0' */
1286 uint64_to_str_back_len(char *ptr, guint64 value, int len)
1290 new_ptr = uint64_to_str_back(ptr, value);
1292 /* substract from len number of generated characters */
1293 len -= (int)(ptr - new_ptr);
1295 /* pad remaining with '0' */
1306 int_to_str_back(char *ptr, gint32 value)
1309 ptr = uint_to_str_back(ptr, -value);
1312 ptr = uint_to_str_back(ptr, value);
1318 int64_to_str_back(char *ptr, gint64 value)
1321 ptr = uint64_to_str_back(ptr, -value);
1324 ptr = uint64_to_str_back(ptr, value);
1330 * Editor modelines - http://www.wireshark.org/tools/modelines.html
1335 * indent-tabs-mode: t
1338 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1339 * :indentSize=8:tabSize=8:noTabs=false: