ISO14443: Fix Dead Store (Dead assignement/Dead increment) Warning found by Clang
[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 word_to_hex(char *out, guint16 word)
71 {
72         out = byte_to_hex(out, word >> 8);
73         out = byte_to_hex(out, word);
74         return out;
75 }
76
77 char *
78 word_to_hex_punct(char *out, guint16 word, char punct)
79 {
80         out = byte_to_hex(out, word >> 8);
81         *out++ = punct;
82         out = byte_to_hex(out, word);
83         return out;
84 }
85
86 char *
87 word_to_hex_npad(char *out, guint16 word)
88 {
89         if (word >= 0x1000)
90                 *out++ = low_nibble_of_octet_to_hex((guint8)(word >> 12));
91         if (word >= 0x0100)
92                 *out++ = low_nibble_of_octet_to_hex((guint8)(word >> 8));
93         if (word >= 0x0010)
94                 *out++ = low_nibble_of_octet_to_hex((guint8)(word >> 4));
95         *out++ = low_nibble_of_octet_to_hex((guint8)(word >> 0));
96         return out;
97 }
98
99 char *
100 dword_to_hex(char *out, guint32 dword)
101 {
102         out = word_to_hex(out, dword >> 16);
103         out = word_to_hex(out, dword);
104         return out;
105 }
106
107 char *
108 dword_to_hex_punct(char *out, guint32 dword, char punct)
109 {
110         out = word_to_hex_punct(out, dword >> 16, punct);
111         *out++ = punct;
112         out = word_to_hex_punct(out, dword, punct);
113         return out;
114 }
115
116 char *
117 qword_to_hex(char *out, guint64 qword)
118 {
119         out = dword_to_hex(out, (guint32)(qword >> 32));
120         out = dword_to_hex(out, (guint32)(qword & 0xffffffff));
121         return out;
122 }
123
124 char *
125 qword_to_hex_punct(char *out, guint64 qword, char punct)
126 {
127         out = dword_to_hex_punct(out, (guint32)(qword >> 32), punct);
128         *out++ = punct;
129         out = dword_to_hex_punct(out, (guint32)(qword & 0xffffffff), punct);
130         return out;
131 }
132
133 /*
134  * This does *not* null-terminate the string.  It returns a pointer
135  * to the position in the string following the last character it
136  * puts there, so that the caller can either put the null terminator
137  * in or can append more stuff to the buffer.
138  *
139  * There needs to be at least len * 2 bytes left in the buffer.
140  */
141 char *
142 bytes_to_hexstr(char *out, const guint8 *ad, guint32 len)
143 {
144         guint32 i;
145
146         if (!ad)
147                 REPORT_DISSECTOR_BUG("Null pointer passed to bytes_to_hexstr()");
148
149         for (i = 0; i < len; i++)
150                 out = byte_to_hex(out, ad[i]);
151         return out;
152 }
153
154 /*
155  * This does *not* null-terminate the string.  It returns a pointer
156  * to the position in the string following the last character it
157  * puts there, so that the caller can either put the null terminator
158  * in or can append more stuff to the buffer.
159  *
160  * There needs to be at least len * 3 - 1 bytes left in the buffer.
161  */
162 char *
163 bytes_to_hexstr_punct(char *out, const guint8 *ad, guint32 len, char punct)
164 {
165         guint32 i;
166
167         if (!ad)
168                 REPORT_DISSECTOR_BUG("Null pointer passed to bytes_to_hexstr_punct()");
169
170         out = byte_to_hex(out, ad[0]);
171         for (i = 1; i < len; i++) {
172                 *out++ = punct;
173                 out = byte_to_hex(out, ad[i]);
174         }
175         return out;
176 }
177
178 /* Max string length for displaying byte string.  */
179 #define MAX_BYTE_STR_LEN        48
180
181 /* Routine to convert a sequence of bytes to a hex string, one byte/two hex
182  * digits at at a time, with a specified punctuation character between
183  * the bytes.
184  *
185  * If punct is '\0', no punctuation is applied (and thus
186  * the resulting string is (len-1) bytes shorter)
187  */
188 const gchar *
189 bytestring_to_str(wmem_allocator_t *scope, const guint8 *ad, const guint32 len, const char punct)
190 {
191         gchar *buf;
192         guint32 buflen = len;
193         gchar *buf_ptr;
194         int truncated = 0;
195
196         if (!punct)
197                 return bytes_to_str(scope, ad, len);
198
199         if (!ad)
200                 REPORT_DISSECTOR_BUG("Null pointer passed to bytestring_to_str()");
201
202         if (len == 0)
203                 return wmem_strdup(scope, "");
204
205         buf=(gchar *)wmem_alloc(scope, MAX_BYTE_STR_LEN+3+1);
206         if (buflen > MAX_BYTE_STR_LEN/3) {      /* bd_len > 16 */
207                 truncated = 1;
208                 buflen = MAX_BYTE_STR_LEN/3;
209         }
210
211         buf_ptr = bytes_to_hexstr_punct(buf, ad, buflen, punct); /* max MAX_BYTE_STR_LEN-1 bytes */
212
213         if (truncated) {
214                 *buf_ptr++ = punct;                     /* 1 byte */
215                 buf_ptr    = g_stpcpy(buf_ptr, "...");  /* 3 bytes */
216         }
217
218         *buf_ptr = '\0';
219         return buf;
220 }
221
222 char *
223 bytes_to_str(wmem_allocator_t *scope, const guint8 *bd, int bd_len)
224 {
225         gchar *cur;
226         gchar *cur_ptr;
227         int truncated = 0;
228
229         if (!bd)
230                 REPORT_DISSECTOR_BUG("Null pointer passed to bytes_to_str()");
231
232         cur=(gchar *)wmem_alloc(scope, MAX_BYTE_STR_LEN+3+1);
233         if (bd_len <= 0) { cur[0] = '\0'; return cur; }
234
235         if (bd_len > MAX_BYTE_STR_LEN/2) {      /* bd_len > 24 */
236                 truncated = 1;
237                 bd_len = MAX_BYTE_STR_LEN/2;
238         }
239
240         cur_ptr = bytes_to_hexstr(cur, bd, bd_len);     /* max MAX_BYTE_STR_LEN bytes */
241
242         if (truncated)
243                 cur_ptr = g_stpcpy(cur_ptr, "...");     /* 3 bytes */
244
245         *cur_ptr = '\0';                                /* 1 byte */
246         return cur;
247 }
248
249 static int
250 guint32_to_str_buf_len(const guint32 u)
251 {
252         /* ((2^32)-1) == 2147483647 */
253         if (u >= 1000000000)return 10;
254         if (u >= 100000000) return 9;
255         if (u >= 10000000)  return 8;
256         if (u >= 1000000)   return 7;
257         if (u >= 100000)    return 6;
258         if (u >= 10000)     return 5;
259         if (u >= 1000)      return 4;
260         if (u >= 100)       return 3;
261         if (u >= 10)        return 2;
262
263         return 1;
264 }
265
266 static int
267 guint64_to_str_buf_len(const guint64 u)
268 {
269         /* ((2^64)-1) == 18446744073709551615 */
270
271         if (u >= G_GUINT64_CONSTANT(10000000000000000000)) return 20;
272         if (u >= G_GUINT64_CONSTANT(1000000000000000000))  return 19;
273         if (u >= G_GUINT64_CONSTANT(100000000000000000))   return 18;
274         if (u >= G_GUINT64_CONSTANT(10000000000000000))    return 17;
275         if (u >= G_GUINT64_CONSTANT(1000000000000000))     return 16;
276         if (u >= G_GUINT64_CONSTANT(100000000000000))      return 15;
277         if (u >= G_GUINT64_CONSTANT(10000000000000))       return 14;
278         if (u >= G_GUINT64_CONSTANT(1000000000000))        return 13;
279         if (u >= G_GUINT64_CONSTANT(100000000000))         return 12;
280         if (u >= G_GUINT64_CONSTANT(10000000000))          return 11;
281         if (u >= G_GUINT64_CONSTANT(1000000000))           return 10;
282         if (u >= G_GUINT64_CONSTANT(100000000))            return 9;
283         if (u >= G_GUINT64_CONSTANT(10000000))             return 8;
284         if (u >= G_GUINT64_CONSTANT(1000000))              return 7;
285         if (u >= G_GUINT64_CONSTANT(100000))               return 6;
286         if (u >= G_GUINT64_CONSTANT(10000))                return 5;
287         if (u >= G_GUINT64_CONSTANT(1000))                 return 4;
288         if (u >= G_GUINT64_CONSTANT(100))                  return 3;
289         if (u >= G_GUINT64_CONSTANT(10))                   return 2;
290
291         return 1;
292 }
293
294 static const char fast_strings[][4] = {
295         "0", "1", "2", "3", "4", "5", "6", "7",
296         "8", "9", "10", "11", "12", "13", "14", "15",
297         "16", "17", "18", "19", "20", "21", "22", "23",
298         "24", "25", "26", "27", "28", "29", "30", "31",
299         "32", "33", "34", "35", "36", "37", "38", "39",
300         "40", "41", "42", "43", "44", "45", "46", "47",
301         "48", "49", "50", "51", "52", "53", "54", "55",
302         "56", "57", "58", "59", "60", "61", "62", "63",
303         "64", "65", "66", "67", "68", "69", "70", "71",
304         "72", "73", "74", "75", "76", "77", "78", "79",
305         "80", "81", "82", "83", "84", "85", "86", "87",
306         "88", "89", "90", "91", "92", "93", "94", "95",
307         "96", "97", "98", "99", "100", "101", "102", "103",
308         "104", "105", "106", "107", "108", "109", "110", "111",
309         "112", "113", "114", "115", "116", "117", "118", "119",
310         "120", "121", "122", "123", "124", "125", "126", "127",
311         "128", "129", "130", "131", "132", "133", "134", "135",
312         "136", "137", "138", "139", "140", "141", "142", "143",
313         "144", "145", "146", "147", "148", "149", "150", "151",
314         "152", "153", "154", "155", "156", "157", "158", "159",
315         "160", "161", "162", "163", "164", "165", "166", "167",
316         "168", "169", "170", "171", "172", "173", "174", "175",
317         "176", "177", "178", "179", "180", "181", "182", "183",
318         "184", "185", "186", "187", "188", "189", "190", "191",
319         "192", "193", "194", "195", "196", "197", "198", "199",
320         "200", "201", "202", "203", "204", "205", "206", "207",
321         "208", "209", "210", "211", "212", "213", "214", "215",
322         "216", "217", "218", "219", "220", "221", "222", "223",
323         "224", "225", "226", "227", "228", "229", "230", "231",
324         "232", "233", "234", "235", "236", "237", "238", "239",
325         "240", "241", "242", "243", "244", "245", "246", "247",
326         "248", "249", "250", "251", "252", "253", "254", "255"
327 };
328
329 void
330 guint32_to_str_buf(guint32 u, gchar *buf, int buf_len)
331 {
332         int str_len = guint32_to_str_buf_len(u)+1;
333
334         gchar *bp = &buf[str_len];
335
336         if (buf_len < str_len) {
337                 g_strlcpy(buf, BUF_TOO_SMALL_ERR, buf_len);     /* Let the unexpected value alert user */
338                 return;
339         }
340
341         *--bp = '\0';
342
343         uint_to_str_back(bp, u);
344 }
345
346 void
347 guint64_to_str_buf(guint64 u, gchar *buf, int buf_len)
348 {
349         int str_len = guint64_to_str_buf_len(u)+1;
350
351         gchar *bp = &buf[str_len];
352
353         if (buf_len < str_len) {
354                 g_strlcpy(buf, BUF_TOO_SMALL_ERR, buf_len);     /* Let the unexpected value alert user */
355                 return;
356         }
357
358         *--bp = '\0';
359
360         uint64_to_str_back(bp, u);
361 }
362
363 #define PLURALIZE(n)    (((n) > 1) ? "s" : "")
364 #define COMMA(do_it)    ((do_it) ? ", " : "")
365
366 /*
367  * Maximum length of a string showing days/hours/minutes/seconds.
368  * (Does not include the terminating '\0'.)
369  * Includes space for a '-' sign for any negative components.
370  * -12345 days, 12 hours, 12 minutes, 12.123 seconds
371  */
372 #define TIME_SECS_LEN   (10+1+4+2+2+5+2+2+7+2+2+7+4)
373
374 /*
375  * Convert a value in seconds and fractions of a second to a string,
376  * giving time in days, hours, minutes, and seconds, and put the result
377  * into a buffer.
378  * "is_nsecs" says that "frac" is microseconds if true and milliseconds
379  * if false.
380  * If time is negative, add a '-' to all non-null components.
381  */
382 static void
383 time_secs_to_str_buf(gint32 time_val, const guint32 frac, const gboolean is_nsecs,
384                 wmem_strbuf_t *buf)
385 {
386         int hours, mins, secs;
387         const gchar *msign = "";
388         gboolean do_comma = FALSE;
389
390         if(time_val == G_MININT32) {    /* That Which Shall Not Be Negated */
391                 wmem_strbuf_append_printf(buf, "Unable to cope with time value %d", time_val);
392                 return;
393         }
394
395         if(time_val < 0){
396                 time_val = -time_val;
397                 msign = "-";
398         }
399
400         secs = time_val % 60;
401         time_val /= 60;
402         mins = time_val % 60;
403         time_val /= 60;
404         hours = time_val % 24;
405         time_val /= 24;
406
407         if (time_val != 0) {
408                 wmem_strbuf_append_printf(buf, "%s%u day%s", msign, time_val, PLURALIZE(time_val));
409                 do_comma = TRUE;
410                 msign="";
411         }
412         if (hours != 0) {
413                 wmem_strbuf_append_printf(buf, "%s%s%u hour%s", COMMA(do_comma), msign, hours, PLURALIZE(hours));
414                 do_comma = TRUE;
415                 msign="";
416         }
417         if (mins != 0) {
418                 wmem_strbuf_append_printf(buf, "%s%s%u minute%s", COMMA(do_comma), msign, mins, PLURALIZE(mins));
419                 do_comma = TRUE;
420                 msign="";
421         }
422         if (secs != 0 || frac != 0) {
423                 if (frac != 0) {
424                         if (is_nsecs)
425                                 wmem_strbuf_append_printf(buf, "%s%s%u.%09u seconds", COMMA(do_comma), msign, secs, frac);
426                         else
427                                 wmem_strbuf_append_printf(buf, "%s%s%u.%03u seconds", COMMA(do_comma), msign, secs, frac);
428                 } else
429                         wmem_strbuf_append_printf(buf, "%s%s%u second%s", COMMA(do_comma), msign, secs, PLURALIZE(secs));
430         }
431 }
432
433 gchar *
434 time_secs_to_str(wmem_allocator_t *scope, const gint32 time_val)
435 {
436         wmem_strbuf_t *buf;
437
438         if (time_val == 0) {
439                 return wmem_strdup(scope, "0 seconds");
440         }
441
442         buf = wmem_strbuf_sized_new(scope, TIME_SECS_LEN+1, TIME_SECS_LEN+1);
443
444         time_secs_to_str_buf(time_val, 0, FALSE, buf);
445
446         return wmem_strbuf_finalize(buf);
447 }
448
449 static void
450 time_secs_to_str_buf_unsigned(guint32 time_val, const guint32 frac, const gboolean is_nsecs,
451                 wmem_strbuf_t *buf)
452 {
453         int hours, mins, secs;
454         gboolean do_comma = FALSE;
455
456         secs = time_val % 60;
457         time_val /= 60;
458         mins = time_val % 60;
459         time_val /= 60;
460         hours = time_val % 24;
461         time_val /= 24;
462
463         if (time_val != 0) {
464                 wmem_strbuf_append_printf(buf, "%u day%s", time_val, PLURALIZE(time_val));
465                 do_comma = TRUE;
466         }
467         if (hours != 0) {
468                 wmem_strbuf_append_printf(buf, "%s%u hour%s", COMMA(do_comma), hours, PLURALIZE(hours));
469                 do_comma = TRUE;
470         }
471         if (mins != 0) {
472                 wmem_strbuf_append_printf(buf, "%s%u minute%s", COMMA(do_comma), mins, PLURALIZE(mins));
473                 do_comma = TRUE;
474         }
475         if (secs != 0 || frac != 0) {
476                 if (frac != 0) {
477                         if (is_nsecs)
478                                 wmem_strbuf_append_printf(buf, "%s%u.%09u seconds", COMMA(do_comma), secs, frac);
479                         else
480                                 wmem_strbuf_append_printf(buf, "%s%u.%03u seconds", COMMA(do_comma), secs, frac);
481                 } else
482                         wmem_strbuf_append_printf(buf, "%s%u second%s", COMMA(do_comma), secs, PLURALIZE(secs));
483         }
484 }
485
486 gchar *
487 time_secs_to_str_unsigned(wmem_allocator_t *scope, const guint32 time_val)
488 {
489         wmem_strbuf_t *buf;
490
491         if (time_val == 0) {
492                 return wmem_strdup(scope, "0 seconds");
493         }
494
495         buf = wmem_strbuf_sized_new(scope, TIME_SECS_LEN+1, TIME_SECS_LEN+1);
496
497         time_secs_to_str_buf_unsigned(time_val, 0, FALSE, buf);
498
499         return wmem_strbuf_finalize(buf);
500 }
501
502
503 gchar *
504 time_msecs_to_str(wmem_allocator_t *scope, gint32 time_val)
505 {
506         wmem_strbuf_t *buf;
507         int msecs;
508
509         if (time_val == 0) {
510                 return wmem_strdup(scope, "0 seconds");
511         }
512
513         buf = wmem_strbuf_sized_new(scope, TIME_SECS_LEN+1+3+1, TIME_SECS_LEN+1+3+1);
514
515         if (time_val<0) {
516                 /* oops we got passed a negative time */
517                 time_val= -time_val;
518                 msecs = time_val % 1000;
519                 time_val /= 1000;
520                 time_val= -time_val;
521         } else {
522                 msecs = time_val % 1000;
523                 time_val /= 1000;
524         }
525
526         time_secs_to_str_buf(time_val, msecs, FALSE, buf);
527
528         return wmem_strbuf_finalize(buf);
529 }
530
531 static const char mon_names[12][4] = {
532         "Jan",
533         "Feb",
534         "Mar",
535         "Apr",
536         "May",
537         "Jun",
538         "Jul",
539         "Aug",
540         "Sep",
541         "Oct",
542         "Nov",
543         "Dec"
544 };
545
546 static const gchar *
547 get_zonename(struct tm *tmp)
548 {
549 #if defined(HAVE_TM_ZONE)
550         return tmp->tm_zone;
551 #else
552         if ((tmp->tm_isdst != 0) && (tmp->tm_isdst != 1)) {
553                 return "???";
554         }
555 # if defined(HAVE_TZNAME)
556         return tzname[tmp->tm_isdst];
557
558 # elif defined(_WIN32)
559         /* Windows C Runtime:                                                 */
560         /*   _tzname is encoded using the "system default ansi code page"     */
561         /*     ("which is not necessarily the same as the C library locale"). */
562         /*     So: _tzname must be converted to UTF8 before use.              */
563         /*   Alternative: use Windows GetTimeZoneInformation() to get the     */
564         /*     timezone name in UTF16 and convert same to UTF8.               */
565         /*   XXX: the result is that the timezone name will be based upon the */
566         /*    system code page (iow: the charset of the system).              */
567         /*    Since Wireshark is not internationalized, it would seem more    */
568         /*    correct to show the timezone name in English, no matter what    */
569         /*    the system code page, but I don't how to do that (or if it's    */
570         /*    really even possible).                                          */
571         /*    In any case converting to UTF8 presumably at least keeps GTK    */
572         /*    happy. (A bug was reported wherein Wireshark crashed in GDK     */
573         /*    on a "Japanese version of Windows XP" when trying to copy       */
574         /*    the date/time string (containing a copy of _tz_name) to the     */
575         /*    clipboard).                                                     */
576
577         {
578                 static char *ws_tzname[2] = {NULL, NULL};
579
580                 /* The g_malloc'd value returned from g_locale_to_utf8() is   */
581                 /*  cached for all further use so there's no need to ever     */
582                 /*  g_free() that value.                                      */
583                 if (ws_tzname[tmp->tm_isdst] == NULL) {
584                         ws_tzname[tmp->tm_isdst] = g_locale_to_utf8(_tzname[tmp->tm_isdst], -1, NULL, NULL, NULL);
585                         if (ws_tzname[tmp->tm_isdst] == NULL) {
586                                 ws_tzname[tmp->tm_isdst] = "???";
587                         }
588                 }
589                 return ws_tzname[tmp->tm_isdst];
590         }
591 # else
592         return tmp->tm_isdst ? "?DT" : "?ST";
593
594 # endif
595 #endif
596 }
597
598 gchar *
599 abs_time_to_str(wmem_allocator_t *scope, const nstime_t *abs_time, const absolute_time_display_e fmt,
600                 gboolean show_zone)
601 {
602         struct tm *tmp = NULL;
603         const char *zonename = "???";
604         gchar *buf = NULL;
605
606
607         switch (fmt) {
608
609                 case ABSOLUTE_TIME_UTC:
610                 case ABSOLUTE_TIME_DOY_UTC:
611                         tmp = gmtime(&abs_time->secs);
612                         zonename = "UTC";
613                         break;
614
615                 case ABSOLUTE_TIME_LOCAL:
616                         tmp = localtime(&abs_time->secs);
617                         if (tmp) {
618                                 zonename = get_zonename(tmp);
619                         }
620                         break;
621         }
622         if (tmp) {
623                 switch (fmt) {
624
625                         case ABSOLUTE_TIME_DOY_UTC:
626                                 if (show_zone) {
627                                         buf = wmem_strdup_printf(scope,
628                                                         "%04d/%03d:%02d:%02d:%02d.%09ld %s",
629                                                         tmp->tm_year + 1900,
630                                                         tmp->tm_yday + 1,
631                                                         tmp->tm_hour,
632                                                         tmp->tm_min,
633                                                         tmp->tm_sec,
634                                                         (long)abs_time->nsecs,
635                                                         zonename);
636                                 } else {
637                                         buf = wmem_strdup_printf(scope,
638                                                         "%04d/%03d:%02d:%02d:%02d.%09ld",
639                                                         tmp->tm_year + 1900,
640                                                         tmp->tm_yday + 1,
641                                                         tmp->tm_hour,
642                                                         tmp->tm_min,
643                                                         tmp->tm_sec,
644                                                         (long)abs_time->nsecs);
645                                 }
646                                 break;
647
648                         case ABSOLUTE_TIME_UTC:
649                         case ABSOLUTE_TIME_LOCAL:
650                                 if (show_zone) {
651                                         buf = wmem_strdup_printf(scope,
652                                                         "%s %2d, %d %02d:%02d:%02d.%09ld %s",
653                                                         mon_names[tmp->tm_mon],
654                                                         tmp->tm_mday,
655                                                         tmp->tm_year + 1900,
656                                                         tmp->tm_hour,
657                                                         tmp->tm_min,
658                                                         tmp->tm_sec,
659                                                         (long)abs_time->nsecs,
660                                                         zonename);
661                                 } else {
662                                         buf = wmem_strdup_printf(scope,
663                                                         "%s %2d, %d %02d:%02d:%02d.%09ld",
664                                                         mon_names[tmp->tm_mon],
665                                                         tmp->tm_mday,
666                                                         tmp->tm_year + 1900,
667                                                         tmp->tm_hour,
668                                                         tmp->tm_min,
669                                                         tmp->tm_sec,
670                                                         (long)abs_time->nsecs);
671                                 }
672                                 break;
673                 }
674         } else
675                 buf = wmem_strdup(scope, "Not representable");
676         return buf;
677 }
678
679 gchar *
680 abs_time_secs_to_str(wmem_allocator_t *scope, const time_t abs_time, const absolute_time_display_e fmt,
681                 gboolean show_zone)
682 {
683         struct tm *tmp = NULL;
684         const char *zonename = "???";
685         gchar *buf = NULL;
686
687         switch (fmt) {
688
689                 case ABSOLUTE_TIME_UTC:
690                 case ABSOLUTE_TIME_DOY_UTC:
691                         tmp = gmtime(&abs_time);
692                         zonename = "UTC";
693                         break;
694
695                 case ABSOLUTE_TIME_LOCAL:
696                         tmp = localtime(&abs_time);
697                         if (tmp) {
698                                 zonename = get_zonename(tmp);
699                         }
700                         break;
701         }
702         if (tmp) {
703                 switch (fmt) {
704
705                         case ABSOLUTE_TIME_DOY_UTC:
706                                 if (show_zone) {
707                                         buf = wmem_strdup_printf(scope,
708                                                         "%04d/%03d:%02d:%02d:%02d %s",
709                                                         tmp->tm_year + 1900,
710                                                         tmp->tm_yday + 1,
711                                                         tmp->tm_hour,
712                                                         tmp->tm_min,
713                                                         tmp->tm_sec,
714                                                         zonename);
715                                 } else {
716                                         buf = wmem_strdup_printf(scope,
717                                                         "%04d/%03d:%02d:%02d:%02d",
718                                                         tmp->tm_year + 1900,
719                                                         tmp->tm_yday + 1,
720                                                         tmp->tm_hour,
721                                                         tmp->tm_min,
722                                                         tmp->tm_sec);
723                                 }
724                                 break;
725
726                         case ABSOLUTE_TIME_UTC:
727                         case ABSOLUTE_TIME_LOCAL:
728                                 if (show_zone) {
729                                         buf = wmem_strdup_printf(scope,
730                                                         "%s %2d, %d %02d:%02d:%02d %s",
731                                                         mon_names[tmp->tm_mon],
732                                                         tmp->tm_mday,
733                                                         tmp->tm_year + 1900,
734                                                         tmp->tm_hour,
735                                                         tmp->tm_min,
736                                                         tmp->tm_sec,
737                                                         zonename);
738                                 } else {
739                                         buf = wmem_strdup_printf(scope,
740                                                         "%s %2d, %d %02d:%02d:%02d",
741                                                         mon_names[tmp->tm_mon],
742                                                         tmp->tm_mday,
743                                                         tmp->tm_year + 1900,
744                                                         tmp->tm_hour,
745                                                         tmp->tm_min,
746                                                         tmp->tm_sec);
747                                 }
748                                 break;
749                 }
750         } else
751                 buf = wmem_strdup(scope, "Not representable");
752         return buf;
753 }
754
755 void
756 display_signed_time(gchar *buf, int buflen, const gint32 sec, gint32 frac,
757                 const to_str_time_res_t units)
758 {
759         /* this buffer is not NUL terminated */
760         gint8 num_buf[16]; /* max: '-2147483648', '.1000000000' */
761         gint8 *num_end = &num_buf[16];
762         gint8 *num_ptr;
763         int num_len;
764
765         if (buflen < 1)
766                 return;
767
768         /* If the fractional part of the time stamp is negative,
769            print its absolute value and, if the seconds part isn't
770            (the seconds part should be zero in that case), stick
771            a "-" in front of the entire time stamp. */
772         if (frac < 0) {
773                 frac = -frac;
774                 if (sec >= 0) {
775                         buf[0] = '-';
776                         buf++;
777                         buflen--;
778                 }
779         }
780
781         num_ptr = int_to_str_back(num_end, sec);
782
783         num_len = MIN((int) (num_end - num_ptr), buflen);
784         memcpy(buf, num_ptr, num_len);
785         buf += num_len;
786         buflen -= num_len;
787
788         switch (units) {
789                 case TO_STR_TIME_RES_T_SECS:
790                 default:
791                         /* no fraction */
792                         num_ptr = NULL;
793                         break;
794
795                 case TO_STR_TIME_RES_T_DSECS:
796                         num_ptr = uint_to_str_back_len(num_end, frac, 1);
797                         break;
798
799                 case TO_STR_TIME_RES_T_CSECS:
800                         num_ptr = uint_to_str_back_len(num_end, frac, 2);
801                         break;
802
803                 case TO_STR_TIME_RES_T_MSECS:
804                         num_ptr = uint_to_str_back_len(num_end, frac, 3);
805                         break;
806
807                 case TO_STR_TIME_RES_T_USECS:
808                         num_ptr = uint_to_str_back_len(num_end, frac, 6);
809                         break;
810
811                 case TO_STR_TIME_RES_T_NSECS:
812                         num_ptr = uint_to_str_back_len(num_end, frac, 9);
813                         break;
814         }
815
816         if (num_ptr != NULL)
817         {
818                 *(--num_ptr) = '.';
819
820                 num_len = MIN((int) (num_end - num_ptr), buflen);
821                 memcpy(buf, num_ptr, num_len);
822                 buf += num_len;
823                 buflen -= num_len;
824         }
825
826         /* need to NUL terminate, we know that buffer had at least 1 byte */
827         if (buflen == 0)
828                 buf--;
829         *buf = '\0';
830 }
831
832
833 void
834 display_epoch_time(gchar *buf, int buflen, const time_t sec, gint32 frac,
835                 const to_str_time_res_t units)
836 {
837         double elapsed_secs;
838
839         elapsed_secs = difftime(sec,(time_t)0);
840
841         /* This code copied from display_signed_time; keep it in case anyone
842            is looking at captures from before 1970 (???).
843            If the fractional part of the time stamp is negative,
844            print its absolute value and, if the seconds part isn't
845            (the seconds part should be zero in that case), stick
846            a "-" in front of the entire time stamp. */
847         if (frac < 0) {
848                 frac = -frac;
849                 if (elapsed_secs >= 0) {
850                         if (buflen < 1) {
851                                 return;
852                         }
853                         buf[0] = '-';
854                         buf++;
855                         buflen--;
856                 }
857         }
858         switch (units) {
859
860                 case TO_STR_TIME_RES_T_SECS:
861                         g_snprintf(buf, buflen, "%0.0f", elapsed_secs);
862                         break;
863
864                 case TO_STR_TIME_RES_T_DSECS:
865                         g_snprintf(buf, buflen, "%0.0f.%01d", elapsed_secs, frac);
866                         break;
867
868                 case TO_STR_TIME_RES_T_CSECS:
869                         g_snprintf(buf, buflen, "%0.0f.%02d", elapsed_secs, frac);
870                         break;
871
872                 case TO_STR_TIME_RES_T_MSECS:
873                         g_snprintf(buf, buflen, "%0.0f.%03d", elapsed_secs, frac);
874                         break;
875
876                 case TO_STR_TIME_RES_T_USECS:
877                         g_snprintf(buf, buflen, "%0.0f.%06d", elapsed_secs, frac);
878                         break;
879
880                 case TO_STR_TIME_RES_T_NSECS:
881                         g_snprintf(buf, buflen, "%0.0f.%09d", elapsed_secs, frac);
882                         break;
883         }
884 }
885
886 /*
887  * Display a relative time as days/hours/minutes/seconds.
888  */
889 gchar *
890 rel_time_to_str(wmem_allocator_t *scope, const nstime_t *rel_time)
891 {
892         wmem_strbuf_t *buf;
893         gint32 time_val;
894         gint32 nsec;
895
896         /* If the nanoseconds part of the time stamp is negative,
897            print its absolute value and, if the seconds part isn't
898            (the seconds part should be zero in that case), stick
899            a "-" in front of the entire time stamp. */
900         time_val = (gint) rel_time->secs;
901         nsec = rel_time->nsecs;
902         if (time_val == 0 && nsec == 0) {
903                 return wmem_strdup(scope, "0.000000000 seconds");
904         }
905
906         buf = wmem_strbuf_sized_new(scope, 1+TIME_SECS_LEN+1+6+1, 1+TIME_SECS_LEN+1+6+1);
907
908         if (nsec < 0) {
909                 nsec = -nsec;
910                 wmem_strbuf_append_c(buf, '-');
911
912                 /*
913                  * We assume here that "rel_time->secs" is negative
914                  * or zero; if it's not, the time stamp is bogus,
915                  * with a positive seconds and negative microseconds.
916                  */
917                 time_val = (gint) -rel_time->secs;
918         }
919
920         time_secs_to_str_buf(time_val, nsec, TRUE, buf);
921
922         return wmem_strbuf_finalize(buf);
923 }
924
925 #define REL_TIME_SECS_LEN       (1+10+1+9+1)
926
927 /*
928  * Display a relative time as seconds.
929  */
930 gchar *
931 rel_time_to_secs_str(wmem_allocator_t *scope, const nstime_t *rel_time)
932 {
933         gchar *buf;
934
935         buf=(gchar *)wmem_alloc(scope, REL_TIME_SECS_LEN);
936
937         display_signed_time(buf, REL_TIME_SECS_LEN, (gint32) rel_time->secs,
938                         rel_time->nsecs, TO_STR_TIME_RES_T_NSECS);
939         return buf;
940 }
941
942 /*
943  * Generates a string representing the bits in a bitfield at "bit_offset" from an 8 bit boundary
944  * with the length in bits of no_of_bits based on value.
945  * Ex: ..xx x...
946  */
947
948 char *
949 decode_bits_in_field(const guint bit_offset, const gint no_of_bits, const guint64 value)
950 {
951         guint64 mask = 0,tmp;
952         char *str;
953         int bit, str_p = 0;
954         int i;
955
956         mask = 1;
957         mask = mask << (no_of_bits-1);
958
959         /* Prepare the string, 256 pos for the bits and zero termination, + 64 for the spaces */
960         str=(char *)wmem_alloc0(wmem_packet_scope(), 256+64);
961         for(bit=0;bit<((int)(bit_offset&0x07));bit++){
962                 if(bit&&(!(bit%4))){
963                         str[str_p] = ' ';
964                         str_p++;
965                 }
966                 str[str_p] = '.';
967                 str_p++;
968         }
969
970         /* read the bits for the int */
971         for(i=0;i<no_of_bits;i++){
972                 if(bit&&(!(bit%4))){
973                         str[str_p] = ' ';
974                         str_p++;
975                 }
976                 if(bit&&(!(bit%8))){
977                         str[str_p] = ' ';
978                         str_p++;
979                 }
980                 bit++;
981                 tmp = value & mask;
982                 if(tmp != 0){
983                         str[str_p] = '1';
984                         str_p++;
985                 } else {
986                         str[str_p] = '0';
987                         str_p++;
988                 }
989                 mask = mask>>1;
990         }
991
992         for(;bit%8;bit++){
993                 if(bit&&(!(bit%4))){
994                         str[str_p] = ' ';
995                         str_p++;
996                 }
997                 str[str_p] = '.';
998                 str_p++;
999         }
1000         return str;
1001 }
1002
1003 /*
1004    This function is very fast and this function is called a lot.
1005    XXX update the address_to_str stuff to use this function.
1006    */
1007 void
1008 ip_to_str_buf(const guint8 *ad, gchar *buf, const int buf_len)
1009 {
1010         register gchar const *p;
1011         register gchar *b=buf;
1012
1013         if (buf_len < MAX_IP_STR_LEN) {
1014                 g_strlcpy(buf, BUF_TOO_SMALL_ERR, buf_len);  /* Let the unexpected value alert user */
1015                 return;
1016         }
1017
1018         p=fast_strings[*ad++];
1019         do {
1020                 *b++=*p;
1021                 p++;
1022         } while(*p);
1023         *b++='.';
1024
1025         p=fast_strings[*ad++];
1026         do {
1027                 *b++=*p;
1028                 p++;
1029         } while(*p);
1030         *b++='.';
1031
1032         p=fast_strings[*ad++];
1033         do {
1034                 *b++=*p;
1035                 p++;
1036         } while(*p);
1037         *b++='.';
1038
1039         p=fast_strings[*ad];
1040         do {
1041                 *b++=*p;
1042                 p++;
1043         } while(*p);
1044         *b=0;
1045 }
1046
1047 gchar *
1048 guid_to_str(wmem_allocator_t *scope, const e_guid_t *guid)
1049 {
1050         gchar *buf;
1051
1052         buf=(gchar *)wmem_alloc(scope, GUID_STR_LEN);
1053         return guid_to_str_buf(guid, buf, GUID_STR_LEN);
1054 }
1055
1056 gchar *
1057 guid_to_str_buf(const e_guid_t *guid, gchar *buf, int buf_len)
1058 {
1059         char *tempptr = buf;
1060
1061         if (buf_len < GUID_STR_LEN) {
1062                 g_strlcpy(buf, BUF_TOO_SMALL_ERR, buf_len);/* Let the unexpected value alert user */
1063                 return buf;
1064         }
1065
1066         /* 37 bytes */
1067         tempptr    = dword_to_hex(tempptr, guid->data1);                /*  8 bytes */
1068         *tempptr++ = '-';                                               /*  1 byte */
1069         tempptr    = word_to_hex(tempptr, guid->data2);                 /*  4 bytes */
1070         *tempptr++ = '-';                                               /*  1 byte */
1071         tempptr    = word_to_hex(tempptr, guid->data3);                 /*  4 bytes */
1072         *tempptr++ = '-';                                               /*  1 byte */
1073         tempptr    = bytes_to_hexstr(tempptr, &guid->data4[0], 2);      /*  4 bytes */
1074         *tempptr++ = '-';                                               /*  1 byte */
1075         tempptr    = bytes_to_hexstr(tempptr, &guid->data4[2], 6);      /* 12 bytes */
1076
1077         *tempptr   = '\0';
1078         return buf;
1079 }
1080
1081 gchar *
1082 eui64_to_str(wmem_allocator_t *scope, const guint64 ad) {
1083         gchar *buf, *tmp;
1084         guint8 *p_eui64;
1085
1086         p_eui64=(guint8 *)wmem_alloc(NULL, 8);
1087         buf=(gchar *)wmem_alloc(scope, EUI64_STR_LEN);
1088
1089         /* Copy and convert the address to network byte order. */
1090         *(guint64 *)(void *)(p_eui64) = pntoh64(&(ad));
1091
1092         tmp = bytes_to_hexstr_punct(buf, p_eui64, 8, ':');
1093         *tmp = '\0'; /* NULL terminate */
1094         wmem_free(NULL, p_eui64);
1095         return buf;
1096 }
1097
1098 const gchar *
1099 port_type_to_str (port_type type)
1100 {
1101         switch (type) {
1102                 case PT_NONE:           return "NONE";
1103                 case PT_SCTP:           return "SCTP";
1104                 case PT_TCP:            return "TCP";
1105                 case PT_UDP:            return "UDP";
1106                 case PT_DCCP:           return "DCCP";
1107                 case PT_IPX:            return "IPX";
1108                 case PT_NCP:            return "NCP";
1109                 case PT_EXCHG:          return "FC EXCHG";
1110                 case PT_DDP:            return "DDP";
1111                 case PT_SBCCS:          return "FICON SBCCS";
1112                 case PT_IDP:            return "IDP";
1113                 case PT_TIPC:           return "TIPC";
1114                 case PT_USB:            return "USB";
1115                 case PT_I2C:            return "I2C";
1116                 case PT_IBQP:           return "IBQP";
1117                 case PT_BLUETOOTH:      return "BLUETOOTH";
1118                 case PT_TDMOP:          return "TDMOP";
1119                 default:                return "[Unknown]";
1120         }
1121 }
1122
1123 char *
1124 oct_to_str_back(char *ptr, guint32 value)
1125 {
1126         while (value) {
1127                 *(--ptr) = '0' + (value & 0x7);
1128                 value >>= 3;
1129         }
1130
1131         *(--ptr) = '0';
1132         return ptr;
1133 }
1134
1135 char *
1136 oct64_to_str_back(char *ptr, guint64 value)
1137 {
1138         while (value) {
1139                 *(--ptr) = '0' + (value & 0x7);
1140                 value >>= 3;
1141         }
1142
1143         *(--ptr) = '0';
1144         return ptr;
1145 }
1146
1147 char *
1148 hex_to_str_back(char *ptr, int len, guint32 value)
1149 {
1150         do {
1151                 *(--ptr) = low_nibble_of_octet_to_hex(value);
1152                 value >>= 4;
1153                 len--;
1154         } while (value);
1155
1156         /* pad */
1157         while (len > 0) {
1158                 *(--ptr) = '0';
1159                 len--;
1160         }
1161
1162         *(--ptr) = 'x';
1163         *(--ptr) = '0';
1164
1165         return ptr;
1166 }
1167
1168 char *
1169 hex64_to_str_back(char *ptr, int len, guint64 value)
1170 {
1171         do {
1172                 *(--ptr) = low_nibble_of_octet_to_hex(value & 0xF);
1173                 value >>= 4;
1174                 len--;
1175         } while (value);
1176
1177         /* pad */
1178         while (len > 0) {
1179                 *(--ptr) = '0';
1180                 len--;
1181         }
1182
1183         *(--ptr) = 'x';
1184         *(--ptr) = '0';
1185
1186         return ptr;
1187 }
1188
1189 char *
1190 uint_to_str_back(char *ptr, guint32 value)
1191 {
1192         char const *p;
1193
1194         /* special case */
1195         if (value == 0)
1196                 *(--ptr) = '0';
1197
1198         while (value >= 10) {
1199                 p = fast_strings[100 + (value % 100)];
1200
1201                 value /= 100;
1202
1203                 *(--ptr) = p[2];
1204                 *(--ptr) = p[1];
1205         }
1206
1207         if (value)
1208                 *(--ptr) = (value) | '0';
1209
1210         return ptr;
1211 }
1212
1213 char *
1214 uint64_to_str_back(char *ptr, guint64 value)
1215 {
1216         char const *p;
1217
1218         /* special case */
1219         if (value == 0)
1220                 *(--ptr) = '0';
1221
1222         while (value >= 10) {
1223                 p = fast_strings[100 + (value % 100)];
1224
1225                 value /= 100;
1226
1227                 *(--ptr) = p[2];
1228                 *(--ptr) = p[1];
1229         }
1230
1231         /* value will be 0..9, so using '& 0xF' is safe, and faster than '% 10' */
1232         if (value)
1233                 *(--ptr) = (value & 0xF) | '0';
1234
1235         return ptr;
1236 }
1237
1238 char *
1239 uint_to_str_back_len(char *ptr, guint32 value, int len)
1240 {
1241         char *new_ptr;
1242
1243         new_ptr = uint_to_str_back(ptr, value);
1244
1245         /* substract from len number of generated characters */
1246         len -= (int)(ptr - new_ptr);
1247
1248         /* pad remaining with '0' */
1249         while (len > 0)
1250         {
1251                 *(--new_ptr) = '0';
1252                 len--;
1253         }
1254
1255         return new_ptr;
1256 }
1257
1258 char *
1259 uint64_to_str_back_len(char *ptr, guint64 value, int len)
1260 {
1261         char *new_ptr;
1262
1263         new_ptr = uint64_to_str_back(ptr, value);
1264
1265         /* substract from len number of generated characters */
1266         len -= (int)(ptr - new_ptr);
1267
1268         /* pad remaining with '0' */
1269         while (len > 0)
1270         {
1271                 *(--new_ptr) = '0';
1272                 len--;
1273         }
1274
1275         return new_ptr;
1276 }
1277
1278 char *
1279 int_to_str_back(char *ptr, gint32 value)
1280 {
1281         if (value < 0) {
1282                 ptr = uint_to_str_back(ptr, -value);
1283                 *(--ptr) = '-';
1284         } else
1285                 ptr = uint_to_str_back(ptr, value);
1286
1287         return ptr;
1288 }
1289
1290 char *
1291 int64_to_str_back(char *ptr, gint64 value)
1292 {
1293         if (value < 0) {
1294                 ptr = uint64_to_str_back(ptr, -value);
1295                 *(--ptr) = '-';
1296         } else
1297                 ptr = uint64_to_str_back(ptr, value);
1298
1299         return ptr;
1300 }
1301
1302 /*
1303  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
1304  *
1305  * Local variables:
1306  * c-basic-offset: 8
1307  * tab-width: 8
1308  * indent-tabs-mode: t
1309  * End:
1310  *
1311  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1312  * :indentSize=8:tabSize=8:noTabs=false:
1313  */