TODO SMB2 NegotiateContext....
[metze/wireshark/wip.git] / epan / to_str.c
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 "wmem/wmem.h"
19 #include "proto.h"
20 #include "to_str.h"
21 #include "to_str-int.h"
22 #include "strutil.h"
23 #include <wsutil/pint.h>
24 #include <wsutil/utf8_entities.h>
25
26 /*
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
30  * useful.
31  */
32 #define BUF_TOO_SMALL_ERR "[Buffer too small]"
33
34 static inline char
35 low_nibble_of_octet_to_hex(guint8 oct)
36 {
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' };
46
47         return hex_digits[oct & 0xF];
48 }
49
50 static inline char *
51 byte_to_hex(char *out, guint32 dword)
52 {
53         *out++ = low_nibble_of_octet_to_hex(dword >> 4);
54         *out++ = low_nibble_of_octet_to_hex(dword);
55         return out;
56 }
57
58 char *
59 guint8_to_hex(char *out, guint8 val)
60 {
61         return byte_to_hex(out, val);
62 }
63
64 char *
65 word_to_hex(char *out, guint16 word)
66 {
67         out = byte_to_hex(out, word >> 8);
68         out = byte_to_hex(out, word);
69         return out;
70 }
71
72 char *
73 word_to_hex_punct(char *out, guint16 word, char punct)
74 {
75         out = byte_to_hex(out, word >> 8);
76         *out++ = punct;
77         out = byte_to_hex(out, word);
78         return out;
79 }
80
81 char *
82 word_to_hex_npad(char *out, guint16 word)
83 {
84         if (word >= 0x1000)
85                 *out++ = low_nibble_of_octet_to_hex((guint8)(word >> 12));
86         if (word >= 0x0100)
87                 *out++ = low_nibble_of_octet_to_hex((guint8)(word >> 8));
88         if (word >= 0x0010)
89                 *out++ = low_nibble_of_octet_to_hex((guint8)(word >> 4));
90         *out++ = low_nibble_of_octet_to_hex((guint8)(word >> 0));
91         return out;
92 }
93
94 char *
95 dword_to_hex(char *out, guint32 dword)
96 {
97         out = word_to_hex(out, dword >> 16);
98         out = word_to_hex(out, dword);
99         return out;
100 }
101
102 char *
103 dword_to_hex_punct(char *out, guint32 dword, char punct)
104 {
105         out = word_to_hex_punct(out, dword >> 16, punct);
106         *out++ = punct;
107         out = word_to_hex_punct(out, dword, punct);
108         return out;
109 }
110
111 char *
112 qword_to_hex(char *out, guint64 qword)
113 {
114         out = dword_to_hex(out, (guint32)(qword >> 32));
115         out = dword_to_hex(out, (guint32)(qword & 0xffffffff));
116         return out;
117 }
118
119 char *
120 qword_to_hex_punct(char *out, guint64 qword, char punct)
121 {
122         out = dword_to_hex_punct(out, (guint32)(qword >> 32), punct);
123         *out++ = punct;
124         out = dword_to_hex_punct(out, (guint32)(qword & 0xffffffff), punct);
125         return out;
126 }
127
128 /*
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.
133  *
134  * There needs to be at least len * 2 bytes left in the buffer.
135  */
136 char *
137 bytes_to_hexstr(char *out, const guint8 *ad, guint32 len)
138 {
139         guint32 i;
140
141         if (!ad)
142                 REPORT_DISSECTOR_BUG("Null pointer passed to bytes_to_hexstr()");
143
144         for (i = 0; i < len; i++)
145                 out = byte_to_hex(out, ad[i]);
146         return out;
147 }
148
149 /*
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.
154  *
155  * There needs to be at least len * 3 - 1 bytes left in the buffer.
156  */
157 char *
158 bytes_to_hexstr_punct(char *out, const guint8 *ad, guint32 len, char punct)
159 {
160         guint32 i;
161
162         if (!ad)
163                 REPORT_DISSECTOR_BUG("Null pointer passed to bytes_to_hexstr_punct()");
164
165         out = byte_to_hex(out, ad[0]);
166         for (i = 1; i < len; i++) {
167                 *out++ = punct;
168                 out = byte_to_hex(out, ad[i]);
169         }
170         return out;
171 }
172
173 /* Max string length for displaying byte string.  */
174 #define MAX_BYTE_STR_LEN        48
175
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
178  * the bytes.
179  *
180  * If punct is '\0', no punctuation is applied (and thus
181  * the resulting string is (len-1) bytes shorter)
182  */
183 gchar *
184 bytestring_to_str(wmem_allocator_t *scope, const guint8 *ad, const guint32 len, const char punct)
185 {
186         gchar *buf;
187         guint32 buflen = len;
188         gchar *buf_ptr;
189         int truncated = 0;
190
191         if (!punct)
192                 return bytes_to_str(scope, ad, len);
193
194         if (!ad)
195                 REPORT_DISSECTOR_BUG("Null pointer passed to bytestring_to_str()");
196
197         if (len == 0)
198                 return wmem_strdup(scope, "");
199
200         buf=(gchar *)wmem_alloc(scope, MAX_BYTE_STR_LEN+3+1);
201         if (buflen > MAX_BYTE_STR_LEN/3) {      /* bd_len > 16 */
202                 truncated = 1;
203                 buflen = MAX_BYTE_STR_LEN/3;
204         }
205
206         buf_ptr = bytes_to_hexstr_punct(buf, ad, buflen, punct); /* max MAX_BYTE_STR_LEN-1 bytes */
207
208         if (truncated) {
209                 *buf_ptr++ = punct;                     /* 1 byte */
210                 buf_ptr    = g_stpcpy(buf_ptr, UTF8_HORIZONTAL_ELLIPSIS);       /* 3 bytes */
211         }
212
213         *buf_ptr = '\0';
214         return buf;
215 }
216
217 char *
218 bytes_to_str(wmem_allocator_t *scope, const guint8 *bd, int bd_len)
219 {
220         gchar *cur;
221         gchar *cur_ptr;
222         int truncated = 0;
223
224         if (!bd)
225                 REPORT_DISSECTOR_BUG("Null pointer passed to bytes_to_str()");
226
227         cur=(gchar *)wmem_alloc(scope, MAX_BYTE_STR_LEN+3+1);
228         if (bd_len <= 0) { cur[0] = '\0'; return cur; }
229
230         if (bd_len > MAX_BYTE_STR_LEN/2) {      /* bd_len > 24 */
231                 truncated = 1;
232                 bd_len = MAX_BYTE_STR_LEN/2;
233         }
234
235         cur_ptr = bytes_to_hexstr(cur, bd, bd_len);     /* max MAX_BYTE_STR_LEN bytes */
236
237         if (truncated)
238                 cur_ptr = g_stpcpy(cur_ptr, UTF8_HORIZONTAL_ELLIPSIS);  /* 3 bytes */
239
240         *cur_ptr = '\0';                                /* 1 byte */
241         return cur;
242 }
243
244 static int
245 guint32_to_str_buf_len(const guint32 u)
246 {
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;
257
258         return 1;
259 }
260
261 static int
262 guint64_to_str_buf_len(const guint64 u)
263 {
264         /* ((2^64)-1) == 18446744073709551615 */
265
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;
285
286         return 1;
287 }
288
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"
322 };
323
324 void
325 guint32_to_str_buf(guint32 u, gchar *buf, int buf_len)
326 {
327         int str_len = guint32_to_str_buf_len(u)+1;
328
329         gchar *bp = &buf[str_len];
330
331         if (buf_len < str_len) {
332                 g_strlcpy(buf, BUF_TOO_SMALL_ERR, buf_len);     /* Let the unexpected value alert user */
333                 return;
334         }
335
336         *--bp = '\0';
337
338         uint_to_str_back(bp, u);
339 }
340
341 void
342 guint64_to_str_buf(guint64 u, gchar *buf, int buf_len)
343 {
344         int str_len = guint64_to_str_buf_len(u)+1;
345
346         gchar *bp = &buf[str_len];
347
348         if (buf_len < str_len) {
349                 g_strlcpy(buf, BUF_TOO_SMALL_ERR, buf_len);     /* Let the unexpected value alert user */
350                 return;
351         }
352
353         *--bp = '\0';
354
355         uint64_to_str_back(bp, u);
356 }
357
358 static const char mon_names[12][4] = {
359         "Jan",
360         "Feb",
361         "Mar",
362         "Apr",
363         "May",
364         "Jun",
365         "Jul",
366         "Aug",
367         "Sep",
368         "Oct",
369         "Nov",
370         "Dec"
371 };
372
373 static const gchar *
374 get_zonename(struct tm *tmp)
375 {
376 #if defined(_WIN32)
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     */
393         /*    clipboard).                                                     */
394         static char *ws_tzname[2] = {NULL, NULL};
395
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] = "???";
403                 }
404         }
405         return ws_tzname[tmp->tm_isdst];
406 #else
407         /*
408          * UN*X.
409          *
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.
413          */
414 # if defined(HAVE_STRUCT_TM_TM_ZONE)
415         return tmp->tm_zone;
416 # else /* HAVE_STRUCT_TM_TM_ZONE */
417         if ((tmp->tm_isdst != 0) && (tmp->tm_isdst != 1)) {
418                 return "???";
419         }
420 #  if defined(HAVE_TZNAME)
421         return tzname[tmp->tm_isdst];
422 #  else
423         return tmp->tm_isdst ? "?DT" : "?ST";
424 #  endif /* HAVE_TZNAME */
425 # endif /* HAVE_STRUCT_TM_TM_ZONE */
426 #endif /* _WIN32 */
427 }
428
429 gchar *
430 abs_time_to_str(wmem_allocator_t *scope, const nstime_t *abs_time, const absolute_time_display_e fmt,
431                 gboolean show_zone)
432 {
433         struct tm *tmp = NULL;
434         const char *zonename = "???";
435         gchar *buf = NULL;
436
437
438         switch (fmt) {
439
440                 case ABSOLUTE_TIME_UTC:
441                 case ABSOLUTE_TIME_DOY_UTC:
442                         tmp = gmtime(&abs_time->secs);
443                         zonename = "UTC";
444                         break;
445
446                 case ABSOLUTE_TIME_LOCAL:
447                         tmp = localtime(&abs_time->secs);
448                         if (tmp) {
449                                 zonename = get_zonename(tmp);
450                         }
451                         break;
452         }
453         if (tmp) {
454                 switch (fmt) {
455
456                         case ABSOLUTE_TIME_DOY_UTC:
457                                 if (show_zone) {
458                                         buf = wmem_strdup_printf(scope,
459                                                         "%04d/%03d:%02d:%02d:%02d.%09ld %s",
460                                                         tmp->tm_year + 1900,
461                                                         tmp->tm_yday + 1,
462                                                         tmp->tm_hour,
463                                                         tmp->tm_min,
464                                                         tmp->tm_sec,
465                                                         (long)abs_time->nsecs,
466                                                         zonename);
467                                 } else {
468                                         buf = wmem_strdup_printf(scope,
469                                                         "%04d/%03d:%02d:%02d:%02d.%09ld",
470                                                         tmp->tm_year + 1900,
471                                                         tmp->tm_yday + 1,
472                                                         tmp->tm_hour,
473                                                         tmp->tm_min,
474                                                         tmp->tm_sec,
475                                                         (long)abs_time->nsecs);
476                                 }
477                                 break;
478
479                         case ABSOLUTE_TIME_UTC:
480                         case ABSOLUTE_TIME_LOCAL:
481                                 if (show_zone) {
482                                         buf = wmem_strdup_printf(scope,
483                                                         "%s %2d, %d %02d:%02d:%02d.%09ld %s",
484                                                         mon_names[tmp->tm_mon],
485                                                         tmp->tm_mday,
486                                                         tmp->tm_year + 1900,
487                                                         tmp->tm_hour,
488                                                         tmp->tm_min,
489                                                         tmp->tm_sec,
490                                                         (long)abs_time->nsecs,
491                                                         zonename);
492                                 } else {
493                                         buf = wmem_strdup_printf(scope,
494                                                         "%s %2d, %d %02d:%02d:%02d.%09ld",
495                                                         mon_names[tmp->tm_mon],
496                                                         tmp->tm_mday,
497                                                         tmp->tm_year + 1900,
498                                                         tmp->tm_hour,
499                                                         tmp->tm_min,
500                                                         tmp->tm_sec,
501                                                         (long)abs_time->nsecs);
502                                 }
503                                 break;
504                 }
505         } else
506                 buf = wmem_strdup(scope, "Not representable");
507         return buf;
508 }
509
510 gchar *
511 abs_time_secs_to_str(wmem_allocator_t *scope, const time_t abs_time, const absolute_time_display_e fmt,
512                 gboolean show_zone)
513 {
514         struct tm *tmp = NULL;
515         const char *zonename = "???";
516         gchar *buf = NULL;
517
518         switch (fmt) {
519
520                 case ABSOLUTE_TIME_UTC:
521                 case ABSOLUTE_TIME_DOY_UTC:
522                         tmp = gmtime(&abs_time);
523                         zonename = "UTC";
524                         break;
525
526                 case ABSOLUTE_TIME_LOCAL:
527                         tmp = localtime(&abs_time);
528                         if (tmp) {
529                                 zonename = get_zonename(tmp);
530                         }
531                         break;
532         }
533         if (tmp) {
534                 switch (fmt) {
535
536                         case ABSOLUTE_TIME_DOY_UTC:
537                                 if (show_zone) {
538                                         buf = wmem_strdup_printf(scope,
539                                                         "%04d/%03d:%02d:%02d:%02d %s",
540                                                         tmp->tm_year + 1900,
541                                                         tmp->tm_yday + 1,
542                                                         tmp->tm_hour,
543                                                         tmp->tm_min,
544                                                         tmp->tm_sec,
545                                                         zonename);
546                                 } else {
547                                         buf = wmem_strdup_printf(scope,
548                                                         "%04d/%03d:%02d:%02d:%02d",
549                                                         tmp->tm_year + 1900,
550                                                         tmp->tm_yday + 1,
551                                                         tmp->tm_hour,
552                                                         tmp->tm_min,
553                                                         tmp->tm_sec);
554                                 }
555                                 break;
556
557                         case ABSOLUTE_TIME_UTC:
558                         case ABSOLUTE_TIME_LOCAL:
559                                 if (show_zone) {
560                                         buf = wmem_strdup_printf(scope,
561                                                         "%s %2d, %d %02d:%02d:%02d %s",
562                                                         mon_names[tmp->tm_mon],
563                                                         tmp->tm_mday,
564                                                         tmp->tm_year + 1900,
565                                                         tmp->tm_hour,
566                                                         tmp->tm_min,
567                                                         tmp->tm_sec,
568                                                         zonename);
569                                 } else {
570                                         buf = wmem_strdup_printf(scope,
571                                                         "%s %2d, %d %02d:%02d:%02d",
572                                                         mon_names[tmp->tm_mon],
573                                                         tmp->tm_mday,
574                                                         tmp->tm_year + 1900,
575                                                         tmp->tm_hour,
576                                                         tmp->tm_min,
577                                                         tmp->tm_sec);
578                                 }
579                                 break;
580                 }
581         } else
582                 buf = wmem_strdup(scope, "Not representable");
583         return buf;
584 }
585
586 void
587 display_epoch_time(gchar *buf, int buflen, const time_t sec, gint32 frac,
588                 const to_str_time_res_t units)
589 {
590         double elapsed_secs;
591
592         elapsed_secs = difftime(sec,(time_t)0);
593
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. */
600         if (frac < 0) {
601                 frac = -frac;
602                 if (elapsed_secs >= 0) {
603                         if (buflen < 1) {
604                                 return;
605                         }
606                         buf[0] = '-';
607                         buf++;
608                         buflen--;
609                 }
610         }
611         switch (units) {
612
613                 case TO_STR_TIME_RES_T_SECS:
614                         g_snprintf(buf, buflen, "%0.0f", elapsed_secs);
615                         break;
616
617                 case TO_STR_TIME_RES_T_DSECS:
618                         g_snprintf(buf, buflen, "%0.0f.%01d", elapsed_secs, frac);
619                         break;
620
621                 case TO_STR_TIME_RES_T_CSECS:
622                         g_snprintf(buf, buflen, "%0.0f.%02d", elapsed_secs, frac);
623                         break;
624
625                 case TO_STR_TIME_RES_T_MSECS:
626                         g_snprintf(buf, buflen, "%0.0f.%03d", elapsed_secs, frac);
627                         break;
628
629                 case TO_STR_TIME_RES_T_USECS:
630                         g_snprintf(buf, buflen, "%0.0f.%06d", elapsed_secs, frac);
631                         break;
632
633                 case TO_STR_TIME_RES_T_NSECS:
634                         g_snprintf(buf, buflen, "%0.0f.%09d", elapsed_secs, frac);
635                         break;
636         }
637 }
638
639 void
640 display_signed_time(gchar *buf, int buflen, const gint32 sec, gint32 frac,
641                 const to_str_time_res_t units)
642 {
643         /* this buffer is not NUL terminated */
644         gint8 num_buf[16]; /* max: '-2147483648', '.1000000000' */
645         gint8 *num_end = &num_buf[16];
646         gint8 *num_ptr;
647         int num_len;
648
649         if (buflen < 1)
650                 return;
651
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. */
656         if (frac < 0) {
657                 frac = -frac;
658                 if (sec >= 0) {
659                         buf[0] = '-';
660                         buf++;
661                         buflen--;
662                 }
663         }
664
665         num_ptr = int_to_str_back(num_end, sec);
666
667         num_len = MIN((int) (num_end - num_ptr), buflen);
668         memcpy(buf, num_ptr, num_len);
669         buf += num_len;
670         buflen -= num_len;
671
672         switch (units) {
673                 case TO_STR_TIME_RES_T_SECS:
674                 default:
675                         /* no fraction */
676                         num_ptr = NULL;
677                         break;
678
679                 case TO_STR_TIME_RES_T_DSECS:
680                         num_ptr = uint_to_str_back_len(num_end, frac, 1);
681                         break;
682
683                 case TO_STR_TIME_RES_T_CSECS:
684                         num_ptr = uint_to_str_back_len(num_end, frac, 2);
685                         break;
686
687                 case TO_STR_TIME_RES_T_MSECS:
688                         num_ptr = uint_to_str_back_len(num_end, frac, 3);
689                         break;
690
691                 case TO_STR_TIME_RES_T_USECS:
692                         num_ptr = uint_to_str_back_len(num_end, frac, 6);
693                         break;
694
695                 case TO_STR_TIME_RES_T_NSECS:
696                         num_ptr = uint_to_str_back_len(num_end, frac, 9);
697                         break;
698         }
699
700         if (num_ptr != NULL)
701         {
702                 *(--num_ptr) = '.';
703
704                 num_len = MIN((int) (num_end - num_ptr), buflen);
705                 memcpy(buf, num_ptr, num_len);
706                 buf += num_len;
707                 buflen -= num_len;
708         }
709
710         /* need to NUL terminate, we know that buffer had at least 1 byte */
711         if (buflen == 0)
712                 buf--;
713         *buf = '\0';
714 }
715
716 #define PLURALIZE(n)    (((n) > 1) ? "s" : "")
717 #define COMMA(do_it)    ((do_it) ? ", " : "")
718
719 /*
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
724  */
725 #define TIME_SECS_LEN   (10+1+4+2+2+5+2+2+7+2+2+7+4)
726
727 /*
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
730  * into a buffer.
731  * "is_nsecs" says that "frac" is nanoseconds if true and milliseconds
732  * if false.
733  */
734 static void
735 unsigned_time_secs_to_str_buf(guint32 time_val, const guint32 frac,
736     const gboolean is_nsecs, wmem_strbuf_t *buf)
737 {
738         int hours, mins, secs;
739         gboolean do_comma = FALSE;
740
741         secs = time_val % 60;
742         time_val /= 60;
743         mins = time_val % 60;
744         time_val /= 60;
745         hours = time_val % 24;
746         time_val /= 24;
747
748         if (time_val != 0) {
749                 wmem_strbuf_append_printf(buf, "%u day%s", time_val, PLURALIZE(time_val));
750                 do_comma = TRUE;
751         }
752         if (hours != 0) {
753                 wmem_strbuf_append_printf(buf, "%s%u hour%s", COMMA(do_comma), hours, PLURALIZE(hours));
754                 do_comma = TRUE;
755         }
756         if (mins != 0) {
757                 wmem_strbuf_append_printf(buf, "%s%u minute%s", COMMA(do_comma), mins, PLURALIZE(mins));
758                 do_comma = TRUE;
759         }
760         if (secs != 0 || frac != 0) {
761                 if (frac != 0) {
762                         if (is_nsecs)
763                                 wmem_strbuf_append_printf(buf, "%s%u.%09u seconds", COMMA(do_comma), secs, frac);
764                         else
765                                 wmem_strbuf_append_printf(buf, "%s%u.%03u seconds", COMMA(do_comma), secs, frac);
766                 } else
767                         wmem_strbuf_append_printf(buf, "%s%u second%s", COMMA(do_comma), secs, PLURALIZE(secs));
768         }
769 }
770
771 gchar *
772 unsigned_time_secs_to_str(wmem_allocator_t *scope, const guint32 time_val)
773 {
774         wmem_strbuf_t *buf;
775
776         if (time_val == 0) {
777                 return wmem_strdup(scope, "0 seconds");
778         }
779
780         buf = wmem_strbuf_sized_new(scope, TIME_SECS_LEN+1, TIME_SECS_LEN+1);
781
782         unsigned_time_secs_to_str_buf(time_val, 0, FALSE, buf);
783
784         return wmem_strbuf_finalize(buf);
785 }
786
787 /*
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
790  * into a buffer.
791  * "is_nsecs" says that "frac" is nanoseconds if true and milliseconds
792  * if false.
793  */
794 static void
795 signed_time_secs_to_str_buf(gint32 time_val, const guint32 frac,
796     const gboolean is_nsecs, wmem_strbuf_t *buf)
797 {
798         if(time_val < 0){
799                 wmem_strbuf_append_printf(buf, "-");
800                 if(time_val == G_MININT32) {
801                         /*
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().
806                          *
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?)
810                          */
811                         unsigned_time_secs_to_str_buf(G_MAXUINT32, frac,
812                             is_nsecs, buf);
813                 } else {
814                         /*
815                          * We now know -secs will fit into a guint32;
816                          * negate it and pass that to
817                          * unsigned_time_secs_to_str_buf().
818                          */
819                         unsigned_time_secs_to_str_buf(-time_val, frac,
820                             is_nsecs, buf);
821                 }
822         } else
823                 unsigned_time_secs_to_str_buf(time_val, frac, is_nsecs, buf);
824 }
825
826 gchar *
827 signed_time_secs_to_str(wmem_allocator_t *scope, const gint32 time_val)
828 {
829         wmem_strbuf_t *buf;
830
831         if (time_val == 0) {
832                 return wmem_strdup(scope, "0 seconds");
833         }
834
835         buf = wmem_strbuf_sized_new(scope, TIME_SECS_LEN+1, TIME_SECS_LEN+1);
836
837         signed_time_secs_to_str_buf(time_val, 0, FALSE, buf);
838
839         return wmem_strbuf_finalize(buf);
840 }
841
842 /*
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.
845  */
846 gchar *
847 signed_time_msecs_to_str(wmem_allocator_t *scope, gint32 time_val)
848 {
849         wmem_strbuf_t *buf;
850         int msecs;
851
852         if (time_val == 0) {
853                 return wmem_strdup(scope, "0 seconds");
854         }
855
856         buf = wmem_strbuf_sized_new(scope, TIME_SECS_LEN+1+3+1, TIME_SECS_LEN+1+3+1);
857
858         if (time_val<0) {
859                 /* oops we got passed a negative time */
860                 time_val= -time_val;
861                 msecs = time_val % 1000;
862                 time_val /= 1000;
863                 time_val= -time_val;
864         } else {
865                 msecs = time_val % 1000;
866                 time_val /= 1000;
867         }
868
869         signed_time_secs_to_str_buf(time_val, msecs, FALSE, buf);
870
871         return wmem_strbuf_finalize(buf);
872 }
873
874 /*
875  * Display a relative time as days/hours/minutes/seconds.
876  */
877 gchar *
878 rel_time_to_str(wmem_allocator_t *scope, const nstime_t *rel_time)
879 {
880         wmem_strbuf_t *buf;
881         gint32 time_val;
882         gint32 nsec;
883
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");
892         }
893
894         buf = wmem_strbuf_sized_new(scope, 1+TIME_SECS_LEN+1+6+1, 1+TIME_SECS_LEN+1+6+1);
895
896         if (nsec < 0) {
897                 nsec = -nsec;
898                 wmem_strbuf_append_c(buf, '-');
899
900                 /*
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.
904                  */
905                 time_val = (gint) -rel_time->secs;
906         }
907
908         signed_time_secs_to_str_buf(time_val, nsec, TRUE, buf);
909
910         return wmem_strbuf_finalize(buf);
911 }
912
913 #define REL_TIME_SECS_LEN       (1+10+1+9+1)
914
915 /*
916  * Display a relative time as seconds.
917  */
918 gchar *
919 rel_time_to_secs_str(wmem_allocator_t *scope, const nstime_t *rel_time)
920 {
921         gchar *buf;
922
923         buf=(gchar *)wmem_alloc(scope, REL_TIME_SECS_LEN);
924
925         display_signed_time(buf, REL_TIME_SECS_LEN, (gint32) rel_time->secs,
926                         rel_time->nsecs, TO_STR_TIME_RES_T_NSECS);
927         return buf;
928 }
929
930 /*
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.
933  * Ex: ..xx x...
934  */
935
936 char *
937 decode_bits_in_field(const guint bit_offset, const gint no_of_bits, const guint64 value)
938 {
939         guint64 mask = 0,tmp;
940         char *str;
941         int bit, str_p = 0;
942         int i;
943
944         mask = 1;
945         mask = mask << (no_of_bits-1);
946
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++){
950                 if(bit&&(!(bit%4))){
951                         str[str_p] = ' ';
952                         str_p++;
953                 }
954                 str[str_p] = '.';
955                 str_p++;
956         }
957
958         /* read the bits for the int */
959         for(i=0;i<no_of_bits;i++){
960                 if(bit&&(!(bit%4))){
961                         str[str_p] = ' ';
962                         str_p++;
963                 }
964                 if(bit&&(!(bit%8))){
965                         str[str_p] = ' ';
966                         str_p++;
967                 }
968                 bit++;
969                 tmp = value & mask;
970                 if(tmp != 0){
971                         str[str_p] = '1';
972                         str_p++;
973                 } else {
974                         str[str_p] = '0';
975                         str_p++;
976                 }
977                 mask = mask>>1;
978         }
979
980         for(;bit%8;bit++){
981                 if(bit&&(!(bit%4))){
982                         str[str_p] = ' ';
983                         str_p++;
984                 }
985                 str[str_p] = '.';
986                 str_p++;
987         }
988         return str;
989 }
990
991 /*
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.
994    */
995 void
996 ip_to_str_buf(const guint8 *ad, gchar *buf, const int buf_len)
997 {
998         register gchar const *p;
999         register gchar *b=buf;
1000
1001         if (buf_len < WS_INET_ADDRSTRLEN) {
1002                 g_strlcpy(buf, BUF_TOO_SMALL_ERR, buf_len);  /* Let the unexpected value alert user */
1003                 return;
1004         }
1005
1006         p=fast_strings[*ad++];
1007         do {
1008                 *b++=*p;
1009                 p++;
1010         } while(*p);
1011         *b++='.';
1012
1013         p=fast_strings[*ad++];
1014         do {
1015                 *b++=*p;
1016                 p++;
1017         } while(*p);
1018         *b++='.';
1019
1020         p=fast_strings[*ad++];
1021         do {
1022                 *b++=*p;
1023                 p++;
1024         } while(*p);
1025         *b++='.';
1026
1027         p=fast_strings[*ad];
1028         do {
1029                 *b++=*p;
1030                 p++;
1031         } while(*p);
1032         *b=0;
1033 }
1034
1035 int
1036 ip6_to_str_buf_with_pfx(const ws_in6_addr *addr, gchar *buf, int buf_size, const char *prefix)
1037 {
1038         int bytes;    /* the number of bytes which would be produced if the buffer was large enough. */
1039         gchar addr_buf[WS_INET6_ADDRSTRLEN];
1040         int len;
1041
1042         if (prefix == NULL)
1043                 prefix = "";
1044         bytes = g_snprintf(buf, buf_size, "%s%s", prefix, ws_inet_ntop6(addr, addr_buf, sizeof(addr_buf)));
1045         len = bytes - 1;
1046
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 */
1049         }
1050         return len;
1051 }
1052
1053 int
1054 ip6_to_str_buf(const ws_in6_addr *addr, gchar *buf, int buf_size)
1055 {
1056         gchar addr_buf[WS_INET6_ADDRSTRLEN];
1057         int len;
1058
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) */
1061
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 */
1064         }
1065         return len;
1066 }
1067
1068 gchar *
1069 guid_to_str(wmem_allocator_t *scope, const e_guid_t *guid)
1070 {
1071         gchar *buf;
1072
1073         buf=(gchar *)wmem_alloc(scope, GUID_STR_LEN);
1074         return guid_to_str_buf(guid, buf, GUID_STR_LEN);
1075 }
1076
1077 gchar *
1078 guid_to_str_buf(const e_guid_t *guid, gchar *buf, int buf_len)
1079 {
1080         char *tempptr = buf;
1081
1082         if (buf_len < GUID_STR_LEN) {
1083                 g_strlcpy(buf, BUF_TOO_SMALL_ERR, buf_len);/* Let the unexpected value alert user */
1084                 return buf;
1085         }
1086
1087         /* 37 bytes */
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 */
1097
1098         *tempptr   = '\0';
1099         return buf;
1100 }
1101
1102 gchar *
1103 eui64_to_str(wmem_allocator_t *scope, const guint64 ad) {
1104         gchar *buf, *tmp;
1105         guint8 *p_eui64;
1106
1107         p_eui64=(guint8 *)wmem_alloc(NULL, 8);
1108         buf=(gchar *)wmem_alloc(scope, EUI64_STR_LEN);
1109
1110         /* Copy and convert the address to network byte order. */
1111         *(guint64 *)(void *)(p_eui64) = pntoh64(&(ad));
1112
1113         tmp = bytes_to_hexstr_punct(buf, p_eui64, 8, ':');
1114         *tmp = '\0'; /* NULL terminate */
1115         wmem_free(NULL, p_eui64);
1116         return buf;
1117 }
1118
1119 const gchar *
1120 port_type_to_str (port_type type)
1121 {
1122         switch (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]";
1136         }
1137 }
1138
1139 char *
1140 oct_to_str_back(char *ptr, guint32 value)
1141 {
1142         while (value) {
1143                 *(--ptr) = '0' + (value & 0x7);
1144                 value >>= 3;
1145         }
1146
1147         *(--ptr) = '0';
1148         return ptr;
1149 }
1150
1151 char *
1152 oct64_to_str_back(char *ptr, guint64 value)
1153 {
1154         while (value) {
1155                 *(--ptr) = '0' + (value & 0x7);
1156                 value >>= 3;
1157         }
1158
1159         *(--ptr) = '0';
1160         return ptr;
1161 }
1162
1163 char *
1164 hex_to_str_back(char *ptr, int len, guint32 value)
1165 {
1166         do {
1167                 *(--ptr) = low_nibble_of_octet_to_hex(value);
1168                 value >>= 4;
1169                 len--;
1170         } while (value);
1171
1172         /* pad */
1173         while (len > 0) {
1174                 *(--ptr) = '0';
1175                 len--;
1176         }
1177
1178         *(--ptr) = 'x';
1179         *(--ptr) = '0';
1180
1181         return ptr;
1182 }
1183
1184 char *
1185 hex64_to_str_back(char *ptr, int len, guint64 value)
1186 {
1187         do {
1188                 *(--ptr) = low_nibble_of_octet_to_hex(value & 0xF);
1189                 value >>= 4;
1190                 len--;
1191         } while (value);
1192
1193         /* pad */
1194         while (len > 0) {
1195                 *(--ptr) = '0';
1196                 len--;
1197         }
1198
1199         *(--ptr) = 'x';
1200         *(--ptr) = '0';
1201
1202         return ptr;
1203 }
1204
1205 char *
1206 uint_to_str_back(char *ptr, guint32 value)
1207 {
1208         char const *p;
1209
1210         /* special case */
1211         if (value == 0)
1212                 *(--ptr) = '0';
1213
1214         while (value >= 10) {
1215                 p = fast_strings[100 + (value % 100)];
1216
1217                 value /= 100;
1218
1219                 *(--ptr) = p[2];
1220                 *(--ptr) = p[1];
1221         }
1222
1223         if (value)
1224                 *(--ptr) = (value) | '0';
1225
1226         return ptr;
1227 }
1228
1229 char *
1230 uint64_to_str_back(char *ptr, guint64 value)
1231 {
1232         char const *p;
1233
1234         /* special case */
1235         if (value == 0)
1236                 *(--ptr) = '0';
1237
1238         while (value >= 10) {
1239                 p = fast_strings[100 + (value % 100)];
1240
1241                 value /= 100;
1242
1243                 *(--ptr) = p[2];
1244                 *(--ptr) = p[1];
1245         }
1246
1247         /* value will be 0..9, so using '& 0xF' is safe, and faster than '% 10' */
1248         if (value)
1249                 *(--ptr) = (value & 0xF) | '0';
1250
1251         return ptr;
1252 }
1253
1254 char *
1255 uint_to_str_back_len(char *ptr, guint32 value, int len)
1256 {
1257         char *new_ptr;
1258
1259         new_ptr = uint_to_str_back(ptr, value);
1260
1261         /* substract from len number of generated characters */
1262         len -= (int)(ptr - new_ptr);
1263
1264         /* pad remaining with '0' */
1265         while (len > 0)
1266         {
1267                 *(--new_ptr) = '0';
1268                 len--;
1269         }
1270
1271         return new_ptr;
1272 }
1273
1274 char *
1275 uint64_to_str_back_len(char *ptr, guint64 value, int len)
1276 {
1277         char *new_ptr;
1278
1279         new_ptr = uint64_to_str_back(ptr, value);
1280
1281         /* substract from len number of generated characters */
1282         len -= (int)(ptr - new_ptr);
1283
1284         /* pad remaining with '0' */
1285         while (len > 0)
1286         {
1287                 *(--new_ptr) = '0';
1288                 len--;
1289         }
1290
1291         return new_ptr;
1292 }
1293
1294 char *
1295 int_to_str_back(char *ptr, gint32 value)
1296 {
1297         if (value < 0) {
1298                 ptr = uint_to_str_back(ptr, -value);
1299                 *(--ptr) = '-';
1300         } else
1301                 ptr = uint_to_str_back(ptr, value);
1302
1303         return ptr;
1304 }
1305
1306 char *
1307 int64_to_str_back(char *ptr, gint64 value)
1308 {
1309         if (value < 0) {
1310                 ptr = uint64_to_str_back(ptr, -value);
1311                 *(--ptr) = '-';
1312         } else
1313                 ptr = uint64_to_str_back(ptr, value);
1314
1315         return ptr;
1316 }
1317
1318 /*
1319  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
1320  *
1321  * Local variables:
1322  * c-basic-offset: 8
1323  * tab-width: 8
1324  * indent-tabs-mode: t
1325  * End:
1326  *
1327  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1328  * :indentSize=8:tabSize=8:noTabs=false:
1329  */