Fix https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=8105 :
[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  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24
25 #include "config.h"
26
27 #include <stdio.h>
28 #include <string.h>
29 #include <time.h>
30 #include <glib.h>
31
32 #include "emem.h"
33 #include "proto.h"
34 #include "to_str.h"
35
36 /*
37  * If a user _does_ pass in a too-small buffer, this is probably
38  * going to be too long to fit.  However, even a partial string
39  * starting with "[Buf" should provide enough of a clue to be
40  * useful.
41  */
42 #define BUF_TOO_SMALL_ERR "[Buffer too small]"
43
44 static inline char *
45 byte_to_hex(char *out, guint32 dword) {
46   /* At least one version of Apple's C compiler/linker is buggy, causing
47      a complaint from the linker about the "literal C string section"
48      not ending with '\0' if we initialize a 16-element "char" array with
49      a 16-character string, the fact that initializing such an array with
50      such a string is perfectly legitimate ANSI C nonwithstanding, the 17th
51      '\0' byte in the string nonwithstanding. */
52   static const gchar hex_digits[16] =
53       { '0', '1', '2', '3', '4', '5', '6', '7',
54         '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
55
56   *out++ = hex_digits[(dword >> 4) & 0xF];
57   *out++ = hex_digits[dword & 0xF];
58   return out;
59 }
60
61 char *
62 word_to_hex(char *out, guint16 word) {
63   out = byte_to_hex(out, word >> 8);
64   out = byte_to_hex(out, word);
65   return out;
66 }
67
68 char *
69 word_to_hex_npad(char *out, guint16 word) {
70   static const gchar hex_digits[16] =
71       { '0', '1', '2', '3', '4', '5', '6', '7',
72         '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
73
74         if (word >= 0x1000)
75                 *out++ = hex_digits[(word >> 12) & 0xF];
76         if (word >= 0x0100)
77                 *out++ = hex_digits[(word >> 8) & 0xF];
78         if (word >= 0x0010)
79                 *out++ = hex_digits[(word >> 4) & 0xF];
80         *out++ = hex_digits[word & 0xF];
81         return out;
82 }
83
84 char *
85 dword_to_hex(char *out, guint32 dword) {
86   out = byte_to_hex(out, dword >> 24);
87   out = byte_to_hex(out, dword >> 16);
88   out = byte_to_hex(out, dword >>  8);
89   out = byte_to_hex(out, dword);
90   return out;
91 }
92
93 char *
94 dword_to_hex_punct(char *out, guint32 dword, char punct) {
95   out = byte_to_hex(out, dword >> 24);
96   *out++ = punct;
97   out = byte_to_hex(out, dword >> 16);
98   *out++ = punct;
99   out = byte_to_hex(out, dword >>  8);
100   *out++ = punct;
101   out = byte_to_hex(out, dword);
102   return out;
103 }
104
105 /*
106  * This does *not* null-terminate the string.  It returns a pointer
107  * to the position in the string following the last character it
108  * puts there, so that the caller can either put the null terminator
109  * in or can append more stuff to the buffer.
110  *
111  * There needs to be at least len * 2 bytes left in the buffer.
112  */
113 char *
114 bytes_to_hexstr(char *out, const guint8 *ad, guint32 len) {
115   guint32 i;
116
117   if (!ad)
118     REPORT_DISSECTOR_BUG("Null pointer passed to bytes_to_hexstr()");
119
120   for (i = 0; i < len; i++)
121     out = byte_to_hex(out, ad[i]);
122   return out;
123 }
124
125 /*
126  * This does *not* null-terminate the string.  It returns a pointer
127  * to the position in the string following the last character it
128  * puts there, so that the caller can either put the null terminator
129  * in or can append more stuff to the buffer.
130  *
131  * There needs to be at least len * 3 - 1 bytes left in the buffer.
132  */
133 char *
134 bytes_to_hexstr_punct(char *out, const guint8 *ad, guint32 len, char punct) {
135   guint32 i;
136
137   if (!ad)
138     REPORT_DISSECTOR_BUG("Null pointer passed to bytes_to_hexstr_punct()");
139
140   out = byte_to_hex(out, ad[0]);
141   for (i = 1; i < len; i++) {
142     *out++ = punct;
143     out = byte_to_hex(out, ad[i]);
144   }
145   return out;
146 }
147
148 /* Routine to convert a sequence of bytes to a hex string, one byte/two hex
149  * digits at at a time, with a specified punctuation character between
150  * the bytes.
151  *
152  * If punct is '\0', no punctuation is applied (and thus
153  * the resulting string is (len-1) bytes shorter)
154  */
155 const gchar *
156 bytestring_to_str(const guint8 *ad, const guint32 len, const char punct) {
157   gchar *buf;
158   size_t       buflen;
159
160   if (!ad)
161     REPORT_DISSECTOR_BUG("Null pointer passed to bytestring_to_str()");
162
163   /* XXX, Old code was using int as iterator... Why len is guint32 anyway?! (darkjames) */
164   if ( ((int) len) < 0)
165      return "";
166
167   if (!len)
168      return "";
169
170   if (punct)
171     buflen=len*3;
172   else
173     buflen=len*2 + 1;
174
175   buf=ep_alloc(buflen);
176
177   if (punct)
178     bytes_to_hexstr_punct(buf, ad, len, punct);
179   else
180     bytes_to_hexstr(buf, ad, len);
181
182   buf[buflen-1] = '\0';
183   return buf;
184 }
185
186 /* Max string length for displaying byte string.  */
187 #define MAX_BYTE_STR_LEN        48
188
189 gchar *
190 bytes_to_str(const guint8 *bd, int bd_len) {
191   gchar *cur;
192   gchar *cur_ptr;
193   int truncated = 0;
194
195   if (!bd)
196     REPORT_DISSECTOR_BUG("Null pointer passed to bytes_to_str()");
197
198   cur=ep_alloc(MAX_BYTE_STR_LEN+3+1);
199   if (bd_len <= 0) { cur[0] = '\0'; return cur; }
200
201   if (bd_len > MAX_BYTE_STR_LEN/2) {    /* bd_len > 24 */
202     truncated = 1;
203     bd_len = MAX_BYTE_STR_LEN/2;
204   }
205
206   cur_ptr = bytes_to_hexstr(cur, bd, bd_len);   /* max MAX_BYTE_STR_LEN bytes */
207
208   if (truncated)
209     cur_ptr = g_stpcpy(cur_ptr, "...");         /* 3 bytes */
210
211   *cur_ptr = '\0';                              /* 1 byte */
212   return cur;
213 }
214
215 /* Turn an array of bytes into a string showing the bytes in hex with
216  * punct as a bytes separator.
217  */
218 gchar *
219 bytes_to_str_punct(const guint8 *bd, int bd_len, gchar punct) {
220   gchar *cur;
221   gchar *cur_ptr;
222   int truncated = 0;
223
224   if (!punct)
225     return bytes_to_str(bd, bd_len);
226
227   cur=ep_alloc(MAX_BYTE_STR_LEN+3+1);
228   if (bd_len <= 0) { cur[0] = '\0'; return cur; }
229
230   if (bd_len > MAX_BYTE_STR_LEN/3) {    /* bd_len > 16 */
231    truncated = 1;
232    bd_len = MAX_BYTE_STR_LEN/3;
233   }
234
235   cur_ptr = bytes_to_hexstr_punct(cur, bd, bd_len, punct); /* max MAX_BYTE_STR_LEN-1 bytes */
236
237   if (truncated) {
238     *cur_ptr++ = punct;                         /* 1 byte */
239     cur_ptr    = g_stpcpy(cur_ptr, "...");      /* 3 bytes */
240   }
241
242   *cur_ptr = '\0';
243   return cur;
244 }
245
246 static int
247 guint32_to_str_buf_len(const guint32 u) {
248     if (u >= 1000000000)return 10;
249     if (u >= 100000000) return 9;
250     if (u >= 10000000)  return 8;
251     if (u >= 1000000)   return 7;
252     if (u >= 100000)    return 6;
253     if (u >= 10000)     return 5;
254     if (u >= 1000)      return 4;
255     if (u >= 100)       return 3;
256     if (u >= 10)        return 2;
257
258     return 1;
259 }
260
261 static const char * const fast_strings[] = {
262 "0", "1", "2", "3", "4", "5", "6", "7",
263 "8", "9", "10", "11", "12", "13", "14", "15",
264 "16", "17", "18", "19", "20", "21", "22", "23",
265 "24", "25", "26", "27", "28", "29", "30", "31",
266 "32", "33", "34", "35", "36", "37", "38", "39",
267 "40", "41", "42", "43", "44", "45", "46", "47",
268 "48", "49", "50", "51", "52", "53", "54", "55",
269 "56", "57", "58", "59", "60", "61", "62", "63",
270 "64", "65", "66", "67", "68", "69", "70", "71",
271 "72", "73", "74", "75", "76", "77", "78", "79",
272 "80", "81", "82", "83", "84", "85", "86", "87",
273 "88", "89", "90", "91", "92", "93", "94", "95",
274 "96", "97", "98", "99", "100", "101", "102", "103",
275 "104", "105", "106", "107", "108", "109", "110", "111",
276 "112", "113", "114", "115", "116", "117", "118", "119",
277 "120", "121", "122", "123", "124", "125", "126", "127",
278 "128", "129", "130", "131", "132", "133", "134", "135",
279 "136", "137", "138", "139", "140", "141", "142", "143",
280 "144", "145", "146", "147", "148", "149", "150", "151",
281 "152", "153", "154", "155", "156", "157", "158", "159",
282 "160", "161", "162", "163", "164", "165", "166", "167",
283 "168", "169", "170", "171", "172", "173", "174", "175",
284 "176", "177", "178", "179", "180", "181", "182", "183",
285 "184", "185", "186", "187", "188", "189", "190", "191",
286 "192", "193", "194", "195", "196", "197", "198", "199",
287 "200", "201", "202", "203", "204", "205", "206", "207",
288 "208", "209", "210", "211", "212", "213", "214", "215",
289 "216", "217", "218", "219", "220", "221", "222", "223",
290 "224", "225", "226", "227", "228", "229", "230", "231",
291 "232", "233", "234", "235", "236", "237", "238", "239",
292 "240", "241", "242", "243", "244", "245", "246", "247",
293 "248", "249", "250", "251", "252", "253", "254", "255"
294 };
295
296 void
297 guint32_to_str_buf(guint32 u, gchar *buf, int buf_len) {
298   int str_len = guint32_to_str_buf_len(u)+1;
299
300   gchar *bp = &buf[str_len];
301   gchar const *p;
302
303   if (buf_len < str_len) {
304     g_strlcpy(buf, BUF_TOO_SMALL_ERR, buf_len); /* Let the unexpected value alert user */
305     return;
306   }
307
308   *--bp = '\0';
309
310   while (u >= 10) {
311     p = fast_strings[100 + (u % 100)];
312
313     *--bp = p[2];
314     *--bp = p[1];
315
316     u /= 100;
317   }
318
319   if (bp != buf) /* ugly, fixme! */
320     *--bp = (u % 10) | '0';
321 }
322
323 gchar *
324 guint32_to_str(const guint32 u) {
325   int str_len = 16; /* guint32_to_str_buf_len(u)+1; */
326
327   gchar *bp = ep_alloc(str_len);
328   guint32_to_str_buf(u, bp, str_len);
329
330   return bp;
331 }
332
333 #define PLURALIZE(n)    (((n) > 1) ? "s" : "")
334 #define COMMA(do_it)    ((do_it) ? ", " : "")
335
336 /*
337  * Maximum length of a string showing days/hours/minutes/seconds.
338  * (Does not include the terminating '\0'.)
339  * Includes space for a '-' sign for any negative components.
340  * -12345 days, 12 hours, 12 minutes, 12.123 seconds
341  */
342 #define TIME_SECS_LEN   (10+1+4+2+2+5+2+2+7+2+2+7+4)
343
344 /*
345  * Convert a value in seconds and fractions of a second to a string,
346  * giving time in days, hours, minutes, and seconds, and put the result
347  * into a buffer.
348  * "is_nsecs" says that "frac" is microseconds if true and milliseconds
349  * if false.
350  * If time is negative, add a '-' to all non-null components.
351  */
352 static void
353 time_secs_to_str_buf(gint32 time_val, const guint32 frac, const gboolean is_nsecs,
354                            emem_strbuf_t *buf)
355 {
356   int hours, mins, secs;
357   const gchar *msign = "";
358   gboolean do_comma = FALSE;
359
360   if(time_val == G_MININT32) {  /* That Which Shall Not Be Negated */
361     ep_strbuf_append_printf(buf, "Unable to cope with time value %d", time_val);
362     return;
363   }
364
365   if(time_val < 0){
366     time_val = -time_val;
367     msign = "-";
368   }
369
370   secs = time_val % 60;
371   time_val /= 60;
372   mins = time_val % 60;
373   time_val /= 60;
374   hours = time_val % 24;
375   time_val /= 24;
376
377   if (time_val != 0) {
378     ep_strbuf_append_printf(buf, "%s%u day%s", msign, time_val, PLURALIZE(time_val));
379     do_comma = TRUE;
380     msign="";
381   }
382   if (hours != 0) {
383     ep_strbuf_append_printf(buf, "%s%s%u hour%s", COMMA(do_comma), msign, hours, PLURALIZE(hours));
384     do_comma = TRUE;
385     msign="";
386   }
387   if (mins != 0) {
388     ep_strbuf_append_printf(buf, "%s%s%u minute%s", COMMA(do_comma), msign, mins, PLURALIZE(mins));
389     do_comma = TRUE;
390     msign="";
391   }
392   if (secs != 0 || frac != 0) {
393     if (frac != 0) {
394       if (is_nsecs)
395         ep_strbuf_append_printf(buf, "%s%s%u.%09u seconds", COMMA(do_comma), msign, secs, frac);
396       else
397         ep_strbuf_append_printf(buf, "%s%s%u.%03u seconds", COMMA(do_comma), msign, secs, frac);
398     } else
399       ep_strbuf_append_printf(buf, "%s%s%u second%s", COMMA(do_comma), msign, secs, PLURALIZE(secs));
400   }
401 }
402
403 gchar *
404 time_secs_to_str(const gint32 time_val)
405 {
406   emem_strbuf_t *buf;
407
408   buf=ep_strbuf_sized_new(TIME_SECS_LEN+1, TIME_SECS_LEN+1);
409
410   if (time_val == 0) {
411     ep_strbuf_append(buf, "0 seconds");
412     return buf->str;
413   }
414
415   time_secs_to_str_buf(time_val, 0, FALSE, buf);
416   return buf->str;
417 }
418
419 static void
420 time_secs_to_str_buf_unsigned(guint32 time_val, const guint32 frac, const gboolean is_nsecs,
421                          emem_strbuf_t *buf)
422 {
423   int hours, mins, secs;
424   gboolean do_comma = FALSE;
425
426   secs = time_val % 60;
427   time_val /= 60;
428   mins = time_val % 60;
429   time_val /= 60;
430   hours = time_val % 24;
431   time_val /= 24;
432
433   if (time_val != 0) {
434     ep_strbuf_append_printf(buf, "%u day%s", time_val, PLURALIZE(time_val));
435     do_comma = TRUE;
436   }
437   if (hours != 0) {
438     ep_strbuf_append_printf(buf, "%s%u hour%s", COMMA(do_comma), hours, PLURALIZE(hours));
439     do_comma = TRUE;
440   }
441   if (mins != 0) {
442     ep_strbuf_append_printf(buf, "%s%u minute%s", COMMA(do_comma), mins, PLURALIZE(mins));
443     do_comma = TRUE;
444   }
445   if (secs != 0 || frac != 0) {
446     if (frac != 0) {
447       if (is_nsecs)
448         ep_strbuf_append_printf(buf, "%s%u.%09u seconds", COMMA(do_comma), secs, frac);
449       else
450         ep_strbuf_append_printf(buf, "%s%u.%03u seconds", COMMA(do_comma), secs, frac);
451     } else
452       ep_strbuf_append_printf(buf, "%s%u second%s", COMMA(do_comma), secs, PLURALIZE(secs));
453   }
454 }
455
456 gchar *
457 time_secs_to_str_unsigned(const guint32 time_val)
458 {
459   emem_strbuf_t *buf;
460
461   buf=ep_strbuf_sized_new(TIME_SECS_LEN+1, TIME_SECS_LEN+1);
462
463   if (time_val == 0) {
464     ep_strbuf_append(buf, "0 seconds");
465     return buf->str;
466   }
467
468   time_secs_to_str_buf_unsigned(time_val, 0, FALSE, buf);
469   return buf->str;
470 }
471
472
473 gchar *
474 time_msecs_to_str(gint32 time_val)
475 {
476   emem_strbuf_t *buf;
477   int msecs;
478
479   buf=ep_strbuf_sized_new(TIME_SECS_LEN+1+3+1, TIME_SECS_LEN+1+3+1);
480
481   if (time_val == 0) {
482     ep_strbuf_append(buf, "0 seconds");
483     return buf->str;
484   }
485
486   if(time_val<0){
487     /* oops we got passed a negative time */
488     time_val= -time_val;
489     msecs = time_val % 1000;
490     time_val /= 1000;
491     time_val= -time_val;
492   } else {
493     msecs = time_val % 1000;
494     time_val /= 1000;
495   }
496
497   time_secs_to_str_buf(time_val, msecs, FALSE, buf);
498   return buf->str;
499 }
500
501 static const char *mon_names[12] = {
502         "Jan",
503         "Feb",
504         "Mar",
505         "Apr",
506         "May",
507         "Jun",
508         "Jul",
509         "Aug",
510         "Sep",
511         "Oct",
512         "Nov",
513         "Dec"
514 };
515
516 static const gchar *get_zonename(struct tm *tmp) {
517 #if defined(HAVE_TM_ZONE)
518         return tmp->tm_zone;
519 #else
520         if ((tmp->tm_isdst != 0) && (tmp->tm_isdst != 1)) {
521                 return "???";
522         }
523 # if defined(HAVE_TZNAME)
524         return tzname[tmp->tm_isdst];
525
526 # elif defined(_WIN32)
527         /* Windows C Runtime:                                                 */
528         /*   _tzname is encoded using the "system default ansi code page"     */
529         /*     ("which is not necessarily the same as the C library locale"). */
530         /*     So: _tzname must be converted to UTF8 before use.              */
531         /*   Alternative: use Windows GetTimeZoneInformation() to get the     */
532         /*     timezone name in UTF16 and convert same to UTF8.               */
533         /*   XXX: the result is that the timezone name will be based upon the */
534         /*    system code page (iow: the charset of the system).              */
535         /*    Since Wireshark is not internationalized, it would seem more    */
536         /*    correct to show the timezone name in English, no matter what    */
537         /*    the system code page, but I don't how to do that (or if it's    */
538         /*    really even possible).                                          */
539         /*    In any case converting to UTF8 presumably at least keeps GTK    */
540         /*    happy. (A bug was reported wherein Wireshark crashed in GDK     */
541         /*    on a "Japanese version of Windows XP" when trying to copy       */
542         /*    the date/time string (containing a copy of _tz_name) to the     */
543         /*    clipboard).                                                     */
544
545         {
546                 static char *ws_tzname[2] = {NULL, NULL};
547
548                 /* The g_malloc'd value returned from g_locale_to_utf8() is   */
549                 /*  cached for all further use so there's no need to ever     */
550                 /*  g_free() that value.                                      */
551                 if (ws_tzname[tmp->tm_isdst] == NULL) {
552                         ws_tzname[tmp->tm_isdst] = g_locale_to_utf8(_tzname[tmp->tm_isdst], -1, NULL, NULL, NULL);
553                         if (ws_tzname[tmp->tm_isdst] == NULL) {
554                                 ws_tzname[tmp->tm_isdst] = "???";
555                         }
556                 }
557                 return ws_tzname[tmp->tm_isdst];
558         }
559 # else
560         return tmp->tm_isdst ? "?DT" : "?ST";
561
562 # endif
563 #endif
564 }
565
566 gchar *
567 abs_time_to_str(const nstime_t *abs_time, const absolute_time_display_e fmt,
568    gboolean show_zone)
569 {
570         struct tm *tmp = NULL;
571         const char *zonename = "???";
572         gchar *buf = NULL;
573
574 #if (defined _WIN32) && (_MSC_VER < 1500)
575         /* calling localtime() on MSVC 2005 with huge values causes it to crash */
576         /* XXX - find the exact value that still does work */
577         /* XXX - using _USE_32BIT_TIME_T might be another way to circumvent this problem */
578         if(abs_time->secs > 2000000000) {
579             tmp = NULL;
580         } else
581 #endif
582         switch (fmt) {
583
584         case ABSOLUTE_TIME_UTC:
585         case ABSOLUTE_TIME_DOY_UTC:
586                 tmp = gmtime(&abs_time->secs);
587                 zonename = "UTC";
588                 break;
589
590         case ABSOLUTE_TIME_LOCAL:
591                 tmp = localtime(&abs_time->secs);
592                 if (tmp) {
593                         zonename = get_zonename(tmp);
594                 }
595                 break;
596         }
597         if (tmp) {
598                 switch (fmt) {
599
600                 case ABSOLUTE_TIME_DOY_UTC:
601                         if (show_zone) {
602                                 buf = ep_strdup_printf("%04d/%03d:%02d:%02d:%02d.%09ld %s",
603                                     tmp->tm_year + 1900,
604                                     tmp->tm_yday + 1,
605                                     tmp->tm_hour,
606                                     tmp->tm_min,
607                                     tmp->tm_sec,
608                                     (long)abs_time->nsecs,
609                                     zonename);
610                         } else {
611                                 buf = ep_strdup_printf("%04d/%03d:%02d:%02d:%02d.%09ld",
612                                     tmp->tm_year + 1900,
613                                     tmp->tm_yday + 1,
614                                     tmp->tm_hour,
615                                     tmp->tm_min,
616                                     tmp->tm_sec,
617                                     (long)abs_time->nsecs);
618                         }
619                         break;
620
621                 case ABSOLUTE_TIME_UTC:
622                 case ABSOLUTE_TIME_LOCAL:
623                         if (show_zone) {
624                                 buf = ep_strdup_printf("%s %2d, %d %02d:%02d:%02d.%09ld %s",
625                                     mon_names[tmp->tm_mon],
626                                     tmp->tm_mday,
627                                     tmp->tm_year + 1900,
628                                     tmp->tm_hour,
629                                     tmp->tm_min,
630                                     tmp->tm_sec,
631                                     (long)abs_time->nsecs,
632                                     zonename);
633                         } else {
634                                 buf = ep_strdup_printf("%s %2d, %d %02d:%02d:%02d.%09ld",
635                                     mon_names[tmp->tm_mon],
636                                     tmp->tm_mday,
637                                     tmp->tm_year + 1900,
638                                     tmp->tm_hour,
639                                     tmp->tm_min,
640                                     tmp->tm_sec,
641                                     (long)abs_time->nsecs);
642                         }
643                         break;
644                 }
645         } else
646                 buf = ep_strdup("Not representable");
647         return buf;
648 }
649
650 gchar *
651 abs_time_secs_to_str(const time_t abs_time, const absolute_time_display_e fmt,
652     gboolean show_zone)
653 {
654         struct tm *tmp = NULL;
655         const char *zonename = "???";
656         gchar *buf = NULL;
657
658 #if (defined _WIN32) && (_MSC_VER < 1500)
659         /* calling localtime() on MSVC 2005 with huge values causes it to crash */
660         /* XXX - find the exact value that still does work */
661         /* XXX - using _USE_32BIT_TIME_T might be another way to circumvent this problem */
662         if(abs_time > 2000000000) {
663             tmp = NULL;
664         } else
665 #endif
666         switch (fmt) {
667
668         case ABSOLUTE_TIME_UTC:
669         case ABSOLUTE_TIME_DOY_UTC:
670                 tmp = gmtime(&abs_time);
671                 zonename = "UTC";
672                 break;
673
674         case ABSOLUTE_TIME_LOCAL:
675                 tmp = localtime(&abs_time);
676                 if (tmp) {
677                         zonename = get_zonename(tmp);
678                 }
679                 break;
680         }
681         if (tmp) {
682                 switch (fmt) {
683
684                 case ABSOLUTE_TIME_DOY_UTC:
685                         if (show_zone) {
686                                 buf = ep_strdup_printf("%04d/%03d:%02d:%02d:%02d %s",
687                                     tmp->tm_year + 1900,
688                                     tmp->tm_yday + 1,
689                                     tmp->tm_hour,
690                                     tmp->tm_min,
691                                     tmp->tm_sec,
692                                     zonename);
693                         } else {
694                                 buf = ep_strdup_printf("%04d/%03d:%02d:%02d:%02d",
695                                     tmp->tm_year + 1900,
696                                     tmp->tm_yday + 1,
697                                     tmp->tm_hour,
698                                     tmp->tm_min,
699                                     tmp->tm_sec);
700                         }
701                         break;
702
703                 case ABSOLUTE_TIME_UTC:
704                 case ABSOLUTE_TIME_LOCAL:
705                         if (show_zone) {
706                                 buf = ep_strdup_printf("%s %2d, %d %02d:%02d:%02d %s",
707                                     mon_names[tmp->tm_mon],
708                                     tmp->tm_mday,
709                                     tmp->tm_year + 1900,
710                                     tmp->tm_hour,
711                                     tmp->tm_min,
712                                     tmp->tm_sec,
713                                     zonename);
714                         } else {
715                                 buf = ep_strdup_printf("%s %2d, %d %02d:%02d:%02d",
716                                     mon_names[tmp->tm_mon],
717                                     tmp->tm_mday,
718                                     tmp->tm_year + 1900,
719                                     tmp->tm_hour,
720                                     tmp->tm_min,
721                                     tmp->tm_sec);
722                         }
723                         break;
724                 }
725         } else
726                 buf = ep_strdup("Not representable");
727         return buf;
728 }
729
730 void
731 display_signed_time(gchar *buf, int buflen, const gint32 sec, gint32 frac,
732     const to_str_time_res_t units)
733 {
734         /* If the fractional part of the time stamp is negative,
735            print its absolute value and, if the seconds part isn't
736            (the seconds part should be zero in that case), stick
737            a "-" in front of the entire time stamp. */
738         if (frac < 0) {
739                 frac = -frac;
740                 if (sec >= 0) {
741                         if (buflen < 1) {
742                           return;
743                         }
744                         buf[0] = '-';
745                         buf++;
746                         buflen--;
747                 }
748         }
749         switch (units) {
750
751         case TO_STR_TIME_RES_T_SECS:
752                 g_snprintf(buf, buflen, "%d", sec);
753                 break;
754
755         case TO_STR_TIME_RES_T_DSECS:
756                 g_snprintf(buf, buflen, "%d.%01d", sec, frac);
757                 break;
758
759         case TO_STR_TIME_RES_T_CSECS:
760                 g_snprintf(buf, buflen, "%d.%02d", sec, frac);
761                 break;
762
763         case TO_STR_TIME_RES_T_MSECS:
764                 g_snprintf(buf, buflen, "%d.%03d", sec, frac);
765                 break;
766
767         case TO_STR_TIME_RES_T_USECS:
768                 g_snprintf(buf, buflen, "%d.%06d", sec, frac);
769                 break;
770
771         case TO_STR_TIME_RES_T_NSECS:
772                 g_snprintf(buf, buflen, "%d.%09d", sec, frac);
773                 break;
774         }
775 }
776
777
778 void
779 display_epoch_time(gchar *buf, int buflen, const time_t sec, gint32 frac,
780     const to_str_time_res_t units)
781 {
782         double elapsed_secs;
783
784         elapsed_secs = difftime(sec,(time_t)0);
785
786         /* This code copied from display_signed_time; keep it in case anyone
787            is looking at captures from before 1970 (???).
788            If the fractional part of the time stamp is negative,
789            print its absolute value and, if the seconds part isn't
790            (the seconds part should be zero in that case), stick
791            a "-" in front of the entire time stamp. */
792         if (frac < 0) {
793                 frac = -frac;
794                 if (elapsed_secs >= 0) {
795                         if (buflen < 1) {
796                           return;
797                         }
798                         buf[0] = '-';
799                         buf++;
800                         buflen--;
801                 }
802         }
803         switch (units) {
804
805         case TO_STR_TIME_RES_T_SECS:
806                 g_snprintf(buf, buflen, "%0.0f", elapsed_secs);
807                 break;
808
809         case TO_STR_TIME_RES_T_DSECS:
810                 g_snprintf(buf, buflen, "%0.0f.%01d", elapsed_secs, frac);
811                 break;
812
813         case TO_STR_TIME_RES_T_CSECS:
814                 g_snprintf(buf, buflen, "%0.0f.%02d", elapsed_secs, frac);
815                 break;
816
817         case TO_STR_TIME_RES_T_MSECS:
818                 g_snprintf(buf, buflen, "%0.0f.%03d", elapsed_secs, frac);
819                 break;
820
821         case TO_STR_TIME_RES_T_USECS:
822                 g_snprintf(buf, buflen, "%0.0f.%06d", elapsed_secs, frac);
823                 break;
824
825         case TO_STR_TIME_RES_T_NSECS:
826                 g_snprintf(buf, buflen, "%0.0f.%09d", elapsed_secs, frac);
827                 break;
828         }
829 }
830
831 /*
832  * Display a relative time as days/hours/minutes/seconds.
833  */
834 gchar *
835 rel_time_to_str(const nstime_t *rel_time)
836 {
837         emem_strbuf_t *buf;
838         gint32 time_val;
839         gint32 nsec;
840
841         buf=ep_strbuf_sized_new(1+TIME_SECS_LEN+1+6+1, 1+TIME_SECS_LEN+1+6+1);
842
843         /* If the nanoseconds 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         time_val = (gint) rel_time->secs;
848         nsec = rel_time->nsecs;
849         if (time_val == 0 && nsec == 0) {
850                 ep_strbuf_append(buf, "0.000000000 seconds");
851                 return buf->str;
852         }
853         if (nsec < 0) {
854                 nsec = -nsec;
855                 ep_strbuf_append_c(buf, '-');
856
857                 /*
858                  * We assume here that "rel_time->secs" is negative
859                  * or zero; if it's not, the time stamp is bogus,
860                  * with a positive seconds and negative microseconds.
861                  */
862                 time_val = (gint) -rel_time->secs;
863         }
864
865         time_secs_to_str_buf(time_val, nsec, TRUE, buf);
866         return buf->str;
867 }
868
869 #define REL_TIME_SECS_LEN       (1+10+1+9+1)
870
871 /*
872  * Display a relative time as seconds.
873  */
874 gchar *
875 rel_time_to_secs_str(const nstime_t *rel_time)
876 {
877         gchar *buf;
878
879         buf=ep_alloc(REL_TIME_SECS_LEN);
880
881         display_signed_time(buf, REL_TIME_SECS_LEN, (gint32) rel_time->secs,
882             rel_time->nsecs, TO_STR_TIME_RES_T_NSECS);
883         return buf;
884 }
885
886 /*
887  * Generates a string representing the bits in a bitfield at "bit_offset" from an 8 bit boundary
888  * with the length in bits of no_of_bits based on value.
889  * Ex: ..xx x...
890  */
891
892 char *
893 decode_bits_in_field(const guint bit_offset, const gint no_of_bits, const guint64 value)
894 {
895         guint64 mask = 0,tmp;
896         char *str;
897         int bit, str_p = 0;
898         int i;
899
900         mask = 1;
901         mask = mask << (no_of_bits-1);
902
903         /* Prepare the string, 256 pos for the bits and zero termination, + 64 for the spaces */
904         str=ep_alloc0(256+64);
905         for(bit=0;bit<((int)(bit_offset&0x07));bit++){
906                 if(bit&&(!(bit%4))){
907                         str[str_p] = ' ';
908                         str_p++;
909                 }
910                 str[str_p] = '.';
911                 str_p++;
912         }
913
914         /* read the bits for the int */
915         for(i=0;i<no_of_bits;i++){
916                 if(bit&&(!(bit%4))){
917                         str[str_p] = ' ';
918                         str_p++;
919                 }
920                 if(bit&&(!(bit%8))){
921                         str[str_p] = ' ';
922                         str_p++;
923                 }
924                 bit++;
925                 tmp = value & mask;
926                 if(tmp != 0){
927                         str[str_p] = '1';
928                         str_p++;
929                 } else {
930                         str[str_p] = '0';
931                         str_p++;
932                 }
933                 mask = mask>>1;
934         }
935
936         for(;bit%8;bit++){
937                 if(bit&&(!(bit%4))){
938                         str[str_p] = ' ';
939                         str_p++;
940                 }
941                 str[str_p] = '.';
942                 str_p++;
943         }
944         return str;
945 }
946
947 /* Generate, into "buf", a string showing the bits of a bitfield.
948    Return a pointer to the character after that string. */
949 /*XXX this needs a buf_len check */
950 char *
951 other_decode_bitfield_value(char *buf, const guint32 val, const guint32 mask, const int width)
952 {
953   int i;
954   guint32 bit;
955   char *p;
956
957   i = 0;
958   p = buf;
959   bit = 1 << (width - 1);
960   for (;;) {
961     if (mask & bit) {
962       /* This bit is part of the field.  Show its value. */
963       if (val & bit)
964         *p++ = '1';
965       else
966         *p++ = '0';
967     } else {
968       /* This bit is not part of the field. */
969       *p++ = '.';
970     }
971     bit >>= 1;
972     i++;
973     if (i >= width)
974       break;
975     if (i % 4 == 0)
976       *p++ = ' ';
977   }
978   *p = '\0';
979   return p;
980 }
981
982 char *
983 decode_bitfield_value(char *buf, const guint32 val, const guint32 mask, const int width)
984 {
985   char *p;
986
987   p = other_decode_bitfield_value(buf, val, mask, width);
988   strcpy(p, " = ");
989   p += 3;
990   return p;
991 }
992
993 /* Generate a string describing a Boolean bitfield (a one-bit field that
994    says something is either true or false). */
995 const char *
996 decode_boolean_bitfield(const guint32 val, const guint32 mask, const int width,
997     const char *truedesc, const char *falsedesc)
998 {
999   char *buf;
1000   char *p;
1001
1002   buf=ep_alloc(1025); /* is this a bit overkill? */
1003   p = decode_bitfield_value(buf, val, mask, width);
1004   if (val & mask)
1005     strcpy(p, truedesc);
1006   else
1007     strcpy(p, falsedesc);
1008   return buf;
1009 }
1010
1011 /* Generate a string describing a numeric bitfield (an N-bit field whose
1012    value is just a number). */
1013 const char *
1014 decode_numeric_bitfield(const guint32 val, const guint32 mask, const int width,
1015     const char *fmt)
1016 {
1017   char *buf;
1018   char *p;
1019   int shift = 0;
1020
1021   buf=ep_alloc(1025); /* isnt this a bit overkill? */
1022   /* Compute the number of bits we have to shift the bitfield right
1023      to extract its value. */
1024   while ((mask & (1<<shift)) == 0)
1025     shift++;
1026
1027   p = decode_bitfield_value(buf, val, mask, width);
1028   g_snprintf(p, (gulong) (1025-(p-buf)), fmt, (val & mask) >> shift);
1029   return buf;
1030 }
1031
1032 /*
1033  This function is very fast and this function is called a lot.
1034  XXX update the ep_address_to_str stuff to use this function.
1035 */
1036 void
1037 ip_to_str_buf(const guint8 *ad, gchar *buf, const int buf_len)
1038 {
1039         register gchar const *p;
1040         register gchar *b=buf;
1041
1042         if (buf_len < MAX_IP_STR_LEN) {
1043                 g_snprintf ( buf, buf_len, BUF_TOO_SMALL_ERR );                 /* Let the unexpected value alert user */
1044                 return;
1045         }
1046
1047         p=fast_strings[*ad++];
1048         do {
1049                 *b++=*p;
1050                 p++;
1051         } while(*p);
1052         *b++='.';
1053
1054         p=fast_strings[*ad++];
1055         do {
1056                 *b++=*p;
1057                 p++;
1058         } while(*p);
1059         *b++='.';
1060
1061         p=fast_strings[*ad++];
1062         do {
1063                 *b++=*p;
1064                 p++;
1065         } while(*p);
1066         *b++='.';
1067
1068         p=fast_strings[*ad];
1069         do {
1070                 *b++=*p;
1071                 p++;
1072         } while(*p);
1073         *b=0;
1074 }
1075
1076 gchar* guid_to_str(const e_guid_t *guid) {
1077   gchar *buf;
1078
1079   buf=ep_alloc(GUID_STR_LEN);
1080   return guid_to_str_buf(guid, buf, GUID_STR_LEN);
1081 }
1082
1083 gchar* guid_to_str_buf(const e_guid_t *guid, gchar *buf, int buf_len) {
1084   char *tempptr = buf;
1085
1086   if (buf_len < GUID_STR_LEN) {
1087      g_strlcpy(buf, BUF_TOO_SMALL_ERR, buf_len);/* Let the unexpected value alert user */
1088      return buf;
1089   }
1090
1091   /* 37 bytes */
1092   tempptr    = dword_to_hex(tempptr, guid->data1);              /*  8 bytes */
1093   *tempptr++ = '-';                                             /*  1 byte */
1094   tempptr    = word_to_hex(tempptr, guid->data2);               /*  4 bytes */
1095   *tempptr++ = '-';                                             /*  1 byte */
1096   tempptr    = word_to_hex(tempptr, guid->data3);               /*  4 bytes */
1097   *tempptr++ = '-';                                             /*  1 byte */
1098   tempptr    = bytes_to_hexstr(tempptr, &guid->data4[0], 2);    /*  4 bytes */
1099   *tempptr++ = '-';                                             /*  1 byte */
1100   tempptr    = bytes_to_hexstr(tempptr, &guid->data4[2], 6);    /* 12 bytes */
1101
1102   *tempptr   = '\0';
1103   return buf;
1104 }