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