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