Fixes to get it to compile on Win32.
[obnox/wireshark/wip.git] / util.c
1 /* util.c
2  * Utility routines
3  *
4  * $Id: util.c,v 1.66 2003/06/13 22:22:48 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <glib.h>
30
31 #include <stdlib.h>
32 #include <string.h>
33 #include <stdio.h>
34 #include <errno.h>
35
36 #ifdef HAVE_UNISTD_H
37 #include <unistd.h>
38 #endif
39
40 #ifdef HAVE_SYS_STAT_H
41 #include <sys/stat.h>
42 #endif
43
44 #ifdef NEED_SNPRINTF_H
45 # include "snprintf.h"
46 #endif
47
48 #ifdef NEED_MKSTEMP
49 #include "mkstemp.h"
50 #endif
51
52 #ifdef HAVE_IO_H
53 #include <io.h>
54 typedef int mode_t;     /* for win32 */
55 #endif
56
57 #ifdef HAVE_LIBZ
58 #include <zlib.h>       /* to get the libz version number */
59 #endif
60
61 #ifdef HAVE_LIBPCAP
62 #include <pcap.h>
63 #ifdef WIN32
64 #include "capture-wpcap.h"
65 #endif /* WIN32 */
66 #endif /* HAVE_LIBPCAP */
67
68 #ifdef HAVE_SOME_SNMP
69
70 #ifdef HAVE_NET_SNMP
71 #include <net-snmp/version.h>
72 #endif /* HAVE_NET_SNMP */
73
74 #ifdef HAVE_UCD_SNMP
75 #include <ucd-snmp/version.h>
76 #endif /* HAVE_UCD_SNMP */
77
78 #endif /* HAVE_SOME_SNMP */
79
80 #ifdef HAVE_SYS_UTSNAME_H
81 #include <sys/utsname.h>
82 #endif
83
84 #include "util.h"
85
86 /*
87  * See whether the last line in the string goes past column 80; if so,
88  * replace the blank at the specified point with a newline.
89  */
90 static void
91 do_word_wrap(GString *str, gint point)
92 {
93         char *line_begin;
94
95         line_begin = strrchr(str->str, '\n');
96         if (line_begin == NULL)
97                 line_begin = str->str;
98         else
99                 line_begin++;
100         if (strlen(line_begin) > 80) {
101                 g_assert(str->str[point] == ' ');
102                 str->str[point] = '\n';
103         }
104 }       
105
106 /*
107  * Get various library compile-time versions and append them to
108  * the specified GString.
109  */
110 void
111 get_compiled_version_info(GString *str)
112 {
113 #ifdef HAVE_LIBPCAP
114 #ifdef HAVE_PCAP_VERSION
115         extern char pcap_version[];
116 #endif /* HAVE_PCAP_VERSION */
117 #endif /* HAVE_LIBPCAP */
118         gint break_point;
119
120         g_string_append(str, "with ");
121         g_string_sprintfa(str,
122 #ifdef GLIB_MAJOR_VERSION
123             "GLib %d.%d.%d,", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION,
124             GLIB_MICRO_VERSION);
125 #else
126             "GLib (version unknown),");
127 #endif
128
129 #ifdef HAVE_LIBPCAP
130         g_string_append(str, " ");
131         break_point = str->len - 1;
132 #ifdef WIN32
133         g_string_append(str, "with WinPcap (version unknown)");
134 #else /* WIN32 */
135 #ifdef HAVE_PCAP_VERSION
136         g_string_sprintfa(str, "with libpcap %s,", pcap_version);
137 #else /* HAVE_PCAP_VERSION */
138         g_string_append("with libpcap (version unknown)");
139 #endif /* HAVE_PCAP_VERSION */
140         do_word_wrap(str, break_point);
141 #endif /* WIN32 */
142 #else /* HAVE_LIBPCAP */
143         g_string_append(str, " ");
144         break_point = str->len - 1;
145 #ifdef WIN32
146         g_string_append(str, "without WinPcap,");
147 #else /* WIN32 */
148         g_string_append(str, "without libpcap,");
149 #endif /* WIN32 */
150         do_word_wrap(str, break_point);
151 #endif /* HAVE_LIBPCAP */
152
153         g_string_append(str, " ");
154         break_point = str->len - 1;
155 #ifdef HAVE_LIBZ
156         g_string_append(str, "with libz ");
157 #ifdef ZLIB_VERSION
158         g_string_append(str, ZLIB_VERSION);
159 #else /* ZLIB_VERSION */
160         g_string_append(str, "(version unknown)");
161 #endif /* ZLIB_VERSION */
162 #else /* HAVE_LIBZ */
163         g_string_append(str, "without libz");
164 #endif /* HAVE_LIBZ */
165         g_string_append(str, ",");
166         do_word_wrap(str, break_point);
167
168 /* Oh, this is pretty. */
169 /* Oh, ha.  you think that was pretty.  Try this:! --Wes */
170         g_string_append(str, " ");
171         break_point = str->len - 1;
172 #ifdef HAVE_SOME_SNMP
173
174 #ifdef HAVE_UCD_SNMP
175         g_string_append(str, "with UCD-SNMP ");
176         g_string_append(str, VersionInfo);
177 #endif /* HAVE_UCD_SNMP */
178
179 #ifdef HAVE_NET_SNMP
180         g_string_append(str, "with Net-SNMP ");
181         g_string_append(str, netsnmp_get_version());
182 #endif /* HAVE_NET_SNMP */
183
184 #else /* no SNMP library */
185         g_string_append(str, "without UCD-SNMP or Net-SNMP");
186 #endif /* HAVE_SOME_SNMP */
187         g_string_append(str, ",");
188         do_word_wrap(str, break_point);
189
190         g_string_append(str, " ");
191         break_point = str->len - 1;
192 #ifdef HAVE_GNU_ADNS
193         g_string_append(str, "with ADNS");
194 #else
195         g_string_append(str, "without ADNS");
196 #endif /* HAVE_GNU_ADNS */
197         do_word_wrap(str, break_point);
198 }
199
200 /*
201  * Get various library run-time versions, and the OS version, and append
202  * them to the specified GString.
203  */
204 void
205 get_runtime_version_info(GString *str)
206 {
207 #if defined(WIN32)
208         OSVERSIONINFO info;
209 #elif defined(HAVE_SYS_UTSNAME_H)
210         struct utsname name;
211 #endif
212
213 #ifdef HAVE_LIBPCAP
214 #ifdef WIN32
215         /*
216          * On Windows, we might have been compiled with WinPcap but
217          * might not have it loaded; indicate whether we have it or
218          * not.
219          *
220          * XXX - when versions of libcap and WinPcap with
221          * "pcap_lib_version()" are released, we should use it
222          * here if available.
223          */
224         if (has_wpcap)
225                 g_string_sprintfa(str, "with WinPcap ");
226         else
227                 g_string_append(str, "without WinPcap ");
228 #endif /* WIN32 */
229 #endif /* HAVE_LIBPCAP */
230
231         g_string_append(str, "on ");
232 #if defined(WIN32)
233         info.dwOSVersionInfoSize = sizeof info;
234         if (!GetVersionEx(&info)) {
235                 /*
236                  * XXX - get the failure reason.
237                  */
238                 g_string_append(str, "unknown Windows version");
239                 return;
240         }
241         switch (info.dwPlatformId) {
242
243         case VER_PLATFORM_WIN32s:
244                 /* Shyeah, right. */
245                 g_string_sprintfa(str, "Windows 3.1 with Win32s");
246                 break;
247
248         case VER_PLATFORM_WIN32_WINDOWS:
249                 /* Windows OT */
250                 switch (info.dwMajorVersion) {
251
252                 case 4:
253                         /* 3 cheers for Microsoft marketing! */
254                         switch (info.dwMinorVersion) {
255
256                         case 0:
257                                 g_string_sprintfa(str, "Windows 95");
258                                 break;
259
260                         case 10:
261                                 g_string_sprintfa(str, "Windows 98");
262                                 break;
263
264                         case 90:
265                                 g_string_sprintfa(str, "Windows Me");
266                                 break;
267
268                         default:
269                                 g_string_sprintfa(str, "Windows OT, unknown version %u.%u",
270                                     info.dwMajorVersion, info.dwMinorVersion);
271                                 break;
272                         }
273                         break;
274
275                 default:
276                         g_string_sprintfa(str, "Windows OT, unknown version %u.%u",
277                             info.dwMajorVersion, info.dwMinorVersion);
278                         break;
279                 }
280                 break;
281
282         case VER_PLATFORM_WIN32_NT:
283                 /* Windows NT */
284                 switch (info.dwMajorVersion) {
285
286                 case 3:
287                 case 4:
288                         g_string_sprintfa(str, "Windows NT %u.%u",
289                             info.dwMajorVersion, info.dwMinorVersion);
290                         break;
291
292                 case 5:
293                         /* 3 cheers for Microsoft marketing! */
294                         switch (info.dwMinorVersion) {
295
296                         case 0:
297                                 g_string_sprintfa(str, "Windows 2000");
298                                 break;
299
300                         case 1:
301                                 g_string_sprintfa(str, "Windows XP");
302                                 break;
303
304                         case 2:
305                                 g_string_sprintfa(str, "Windows Server 2003");
306                                 break;
307
308                         default:
309                                 g_string_sprintfa(str, "Windows NT, unknown version %u.%u",
310                                     info.dwMajorVersion, info.dwMinorVersion);
311                                 break;
312                         }
313                         break;
314
315                 default:
316                         g_string_sprintfa(str, "Windows NT, unknown version %u.%u",
317                             info.dwMajorVersion, info.dwMinorVersion);
318                         break;
319                 }
320                 break;
321
322         default:
323                 g_string_sprintfa(str, "Unknown Windows platform %u version %u.%u",
324                     info.dwPlatformId, info.dwMajorVersion, info.dwMinorVersion);
325                 break;
326         }
327         if (info.szCSDVersion[0] != '\0')
328                 g_string_sprintfa(str, " %s", info.szCSDVersion);
329         g_string_sprintfa(str, ", build %u", info.dwBuildNumber);
330 #elif defined(HAVE_SYS_UTSNAME_H)
331         /*
332          * We have <sys/utsname.h>, so we assume we have "uname()".
333          */
334         if (uname(&name) < 0) {
335                 g_string_sprintfa(str, "unknown OS version (uname failed - %s)",
336                     strerror(errno));
337                 return;
338         }
339
340         if (strcmp(name.sysname, "AIX") == 0) {
341                 /*
342                  * Yay, IBM!  Thanks for doing something different
343                  * from most of the other UNIXes out there, and
344                  * making "name.version" apparently be the major
345                  * version number and "name.release" be the minor
346                  * version number.
347                  */
348                 g_string_sprintfa(str, "%s %s.%s", name.sysname, name.version,
349                     name.release);
350         } else {
351                 /*
352                  * XXX - get "version" on any other platforms?
353                  *
354                  * On Digital/Tru65 UNIX, it's something unknown.
355                  * On Solaris, it's some kind of build information.
356                  * On HP-UX, it appears to be some sort of subrevision
357                  * thing.
358                  */
359                 g_string_sprintfa(str, "%s %s", name.sysname, name.release);
360         }
361 #else
362         g_string_append(str, "an unknown OS");
363 #endif
364 }
365
366 /*
367  * Collect command-line arguments as a string consisting of the arguments,
368  * separated by spaces.
369  */
370 char *
371 get_args_as_string(int argc, char **argv, int optind)
372 {
373         int len;
374         int i;
375         char *argstring;
376
377         /*
378          * Find out how long the string will be.
379          */
380         len = 0;
381         for (i = optind; i < argc; i++) {
382                 len += strlen(argv[i]);
383                 len++;  /* space, or '\0' if this is the last argument */
384         }
385
386         /*
387          * Allocate the buffer for the string.
388          */
389         argstring = g_malloc(len);
390
391         /*
392          * Now construct the string.
393          */
394         strcpy(argstring, "");
395         i = optind;
396         for (;;) {
397                 strcat(argstring, argv[i]);
398                 i++;
399                 if (i == argc)
400                         break;
401                 strcat(argstring, " ");
402         }
403         return argstring;
404 }
405
406 static char *
407 setup_tmpdir(char *dir)
408 {
409         int len = strlen(dir);
410         char *newdir;
411
412         /* Append slash if necessary */
413         if (dir[len - 1] == '/') {
414                 newdir = dir;
415         }
416         else {
417                 newdir = g_malloc(len + 2);
418                 strcpy(newdir, dir);
419                 strcat(newdir, "/");
420         }
421         return newdir;
422 }
423
424 static int
425 try_tempfile(char *namebuf, int namebuflen, const char *dir, const char *pfx)
426 {
427         static const char suffix[] = "XXXXXXXXXX";
428         int namelen = strlen(dir) + strlen(pfx) + sizeof suffix;
429         mode_t old_umask;
430         int tmp_fd;
431
432         if (namebuflen < namelen) {
433                 /* Stick in a truncated name, so that if this error is
434                    reported with the file name, you at least get
435                    something. */
436                 snprintf(namebuf, namebuflen, "%s%s%s", dir, pfx, suffix);
437                 errno = ENAMETOOLONG;
438                 return -1;
439         }
440         strcpy(namebuf, dir);
441         strcat(namebuf, pfx);
442         strcat(namebuf, suffix);
443
444         /* The Single UNIX Specification doesn't say that "mkstemp()"
445            creates the temporary file with mode rw-------, so we
446            won't assume that all UNIXes will do so; instead, we set
447            the umask to 0077 to take away all group and other
448            permissions, attempt to create the file, and then put
449            the umask back. */
450         old_umask = umask(0077);
451         tmp_fd = mkstemp(namebuf);
452         umask(old_umask);
453         return tmp_fd;
454 }
455
456 static char *tmpdir = NULL;
457 #ifdef WIN32
458 static char *temp = NULL;
459 #endif
460 static char *E_tmpdir;
461
462 #ifndef P_tmpdir
463 #define P_tmpdir "/var/tmp"
464 #endif
465
466 int
467 create_tempfile(char *namebuf, int namebuflen, const char *pfx)
468 {
469         char *dir;
470         int fd;
471         static gboolean initialized;
472
473         if (!initialized) {
474                 if ((dir = getenv("TMPDIR")) != NULL)
475                         tmpdir = setup_tmpdir(dir);
476 #ifdef WIN32
477                 if ((dir = getenv("TEMP")) != NULL)
478                         temp = setup_tmpdir(dir);
479 #endif
480
481                 E_tmpdir = setup_tmpdir(P_tmpdir);
482                 initialized = TRUE;
483         }
484
485         if (tmpdir != NULL) {
486                 fd = try_tempfile(namebuf, namebuflen, tmpdir, pfx);
487                 if (fd != -1)
488                         return fd;
489         }
490
491 #ifdef WIN32
492         if (temp != NULL) {
493                 fd = try_tempfile(namebuf, namebuflen, temp, pfx);
494                 if (fd != -1)
495                         return fd;
496         }
497 #endif
498
499         fd = try_tempfile(namebuf, namebuflen, E_tmpdir, pfx);
500         if (fd != -1)
501                 return fd;
502
503         return try_tempfile(namebuf, namebuflen, "/tmp", pfx);
504 }
505
506 /* ASCII/EBCDIC conversion tables from
507  * http://www.room42.com/store/computer_center/code_tables.shtml
508  */
509 #if 0
510 static guint8 ASCII_translate_EBCDIC [ 256 ] = {
511     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
512     0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
513     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
514     0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
515     0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, 0x4D,
516     0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
517     0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
518     0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
519     0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8,
520     0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
521     0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
522     0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D,
523     0x7D, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
524     0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
525     0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
526     0xA8, 0xA9, 0xC0, 0x6A, 0xD0, 0xA1, 0x4B,
527     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
528     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
529     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
530     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
531     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
532     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
533     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
534     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
535     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
536     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
537     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
538     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
539     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
540     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
541     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B,
542     0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B
543 };
544
545 void
546 ASCII_to_EBCDIC(guint8 *buf, guint bytes)
547 {
548         guint   i;
549         guint8  *bufptr;
550
551         bufptr = buf;
552
553         for (i = 0; i < bytes; i++, bufptr++) {
554                 *bufptr = ASCII_translate_EBCDIC[*bufptr];
555         }
556 }
557
558 guint8
559 ASCII_to_EBCDIC1(guint8 c)
560 {
561         return ASCII_translate_EBCDIC[c];
562 }
563 #endif
564
565 static guint8 EBCDIC_translate_ASCII [ 256 ] = {
566     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
567     0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
568     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
569     0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
570     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
571     0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
572     0x2E, 0x2E, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
573     0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x2E, 0x3F,
574     0x20, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
575     0x2E, 0x2E, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
576     0x26, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
577     0x2E, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
578     0x2D, 0x2F, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
579     0x2E, 0x7C, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
580     0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
581     0x2E, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
582     0x2E, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
583     0x69, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
584     0x2E, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
585     0x72, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
586     0x2E, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
587     0x7A, 0x2E, 0x2E, 0x2E, 0x5B, 0x2E, 0x2E,
588     0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
589     0x2E, 0x2E, 0x2E, 0x2E, 0x5D, 0x2E, 0x2E,
590     0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
591     0x49, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
592     0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51,
593     0x52, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
594     0x5C, 0x2E, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
595     0x5A, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E,
596     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
597     0x39, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E
598 };
599
600 void
601 EBCDIC_to_ASCII(guint8 *buf, guint bytes)
602 {
603         guint   i;
604         guint8  *bufptr;
605
606         bufptr = buf;
607
608         for (i = 0; i < bytes; i++, bufptr++) {
609                 *bufptr = EBCDIC_translate_ASCII[*bufptr];
610         }
611 }
612
613 guint8
614 EBCDIC_to_ASCII1(guint8 c)
615 {
616         return EBCDIC_translate_ASCII[c];
617 }
618
619 /* Compute the difference between two seconds/microseconds time stamps. */
620 void
621 compute_timestamp_diff(gint *diffsec, gint *diffusec,
622         guint32 sec1, guint32 usec1, guint32 sec2, guint32 usec2)
623 {
624   if (sec1 == sec2) {
625     /* The seconds part of the first time is the same as the seconds
626        part of the second time, so if the microseconds part of the first
627        time is less than the microseconds part of the second time, the
628        first time is before the second time.  The microseconds part of
629        the delta should just be the difference between the microseconds
630        part of the first time and the microseconds part of the second
631        time; don't adjust the seconds part of the delta, as it's OK if
632        the microseconds part is negative. */
633
634     *diffsec = sec1 - sec2;
635     *diffusec = usec1 - usec2;
636   } else if (sec1 <= sec2) {
637     /* The seconds part of the first time is less than the seconds part
638        of the second time, so the first time is before the second time.
639
640        Both the "seconds" and "microseconds" value of the delta
641        should have the same sign, so if the difference between the
642        microseconds values would be *positive*, subtract 1,000,000
643        from it, and add one to the seconds value. */
644     *diffsec = sec1 - sec2;
645     if (usec2 >= usec1) {
646       *diffusec = usec1 - usec2;
647     } else {
648       *diffusec = (usec1 - 1000000) - usec2;
649       (*diffsec)++;
650     }
651   } else {
652     /* Oh, good, we're not caught in a chronosynclastic infindibulum. */
653     *diffsec = sec1 - sec2;
654     if (usec2 <= usec1) {
655       *diffusec = usec1 - usec2;
656     } else {
657       *diffusec = (usec1 + 1000000) - usec2;
658       (*diffsec)--;
659     }
660   }
661 }
662
663 /* Decode a base64 string in-place - simple and slow algorithm.
664    Return length of result. Taken from rproxy/librsync/base64.c by
665    Andrew Tridgell. */
666
667 size_t base64_decode(char *s)
668 {
669         static const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
670         int bit_offset, byte_offset, idx, i, n;
671         unsigned char *d = (unsigned char *)s;
672         char *p;
673
674         n=i=0;
675
676         while (*s && (p=strchr(b64, *s))) {
677                 idx = (int)(p - b64);
678                 byte_offset = (i*6)/8;
679                 bit_offset = (i*6)%8;
680                 d[byte_offset] &= ~((1<<(8-bit_offset))-1);
681                 if (bit_offset < 3) {
682                         d[byte_offset] |= (idx << (2-bit_offset));
683                         n = byte_offset+1;
684                 } else {
685                         d[byte_offset] |= (idx >> (bit_offset-2));
686                         d[byte_offset+1] = 0;
687                         d[byte_offset+1] |= (idx << (8-(bit_offset-2))) & 0xFF;
688                         n = byte_offset+2;
689                 }
690                 s++; i++;
691         }
692
693         return n;
694 }