Fix a key preference crash bug. Improve WPA passphrase and SSID length
[metze/wireshark/wip.git] / epan / strutil.c
1 /* strutil.c
2  * String utility routines
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., 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 <stdlib.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <glib.h>
33 #include "strutil.h"
34 #include "emem.h"
35
36 #ifdef _WIN32
37 #include <windows.h>
38 #include <tchar.h>
39 #include <wchar.h>
40 #endif
41
42 static const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
43                               '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
44
45 /*
46  * Given a pointer into a data buffer, and to the end of the buffer,
47  * find the end of the (putative) line at that position in the data
48  * buffer.
49  * Return a pointer to the EOL character(s) in "*eol".
50  */
51 const guchar *
52 find_line_end(const guchar *data, const guchar *dataend, const guchar **eol)
53 {
54   const guchar *lineend;
55
56   lineend = memchr(data, '\n', dataend - data);
57   if (lineend == NULL) {
58     /*
59      * No LF - line is probably continued in next TCP segment.
60      */
61     lineend = dataend;
62     *eol = dataend;
63   } else {
64     /*
65      * Is the LF at the beginning of the line?
66      */
67     if (lineend > data) {
68       /*
69        * No - is it preceded by a carriage return?
70        * (Perhaps it's supposed to be, but that's not guaranteed....)
71        */
72       if (*(lineend - 1) == '\r') {
73         /*
74          * Yes.  The EOL starts with the CR.
75          */
76         *eol = lineend - 1;
77       } else {
78         /*
79          * No.  The EOL starts with the LF.
80          */
81         *eol = lineend;
82
83         /*
84          * I seem to remember that we once saw lines ending with LF-CR
85          * in an HTTP request or response, so check if it's *followed*
86          * by a carriage return.
87          */
88         if (lineend < (dataend - 1) && *(lineend + 1) == '\r') {
89           /*
90            * It's <non-LF><LF><CR>; say it ends with the CR.
91            */
92           lineend++;
93         }
94       }
95     } else {
96       /*
97        * Yes - the EOL starts with the LF.
98        */
99       *eol = lineend;
100     }
101
102     /*
103      * Point to the character after the last character.
104      */
105     lineend++;
106   }
107   return lineend;
108 }
109
110 /*
111  * Get the length of the next token in a line, and the beginning of the
112  * next token after that (if any).
113  * Return 0 if there is no next token.
114  */
115 int
116 get_token_len(const guchar *linep, const guchar *lineend,
117               const guchar **next_token)
118 {
119   const guchar *tokenp;
120   int token_len;
121
122   tokenp = linep;
123
124   /*
125    * Search for a blank, a CR or an LF, or the end of the buffer.
126    */
127   while (linep < lineend && *linep != ' ' && *linep != '\r' && *linep != '\n')
128       linep++;
129   token_len = linep - tokenp;
130
131   /*
132    * Skip trailing blanks.
133    */
134   while (linep < lineend && *linep == ' ')
135     linep++;
136
137   *next_token = linep;
138
139   return token_len;
140 }
141
142
143 #define INITIAL_FMTBUF_SIZE     128
144
145 #if GLIB_MAJOR_VERSION >= 2
146 /*
147  * XXX - "isprint()" can return "true" for non-ASCII characters, but
148  * those don't work with GTK+ 1.3 or later, as they take UTF-8 strings
149  * as input.  Until we fix up Wireshark to properly handle non-ASCII
150  * characters in all output (both GUI displays and text printouts)
151  * in those versions of GTK+, we work around the problem by escaping
152  * all characters that aren't printable ASCII.
153  *
154  * We don't know what version of GTK+ we're using, as epan doesn't
155  * use any GTK+ stuff; we use GLib as a proxy for that, with GLib 2.x
156  * implying GTK+ 1.3 or later (we don't support GLib 1.3[.x]).
157  */
158 #undef isprint
159 #define isprint(c) (c >= 0x20 && c < 0x7f)
160 #endif
161
162 /*
163  * Given a string, generate a string from it that shows non-printable
164  * characters as C-style escapes, and return a pointer to it.
165  */
166 gchar *
167 format_text(const guchar *string, int len)
168 {
169   static gchar *fmtbuf[3];
170   static int fmtbuf_len[3];
171   static int idx;
172   int column;
173   const guchar *stringend = string + len;
174   guchar c;
175   int i;
176
177   idx = (idx + 1) % 3;
178
179   /*
180    * Allocate the buffer if it's not already allocated.
181    */
182   if (fmtbuf[idx] == NULL) {
183     fmtbuf[idx] = g_malloc(INITIAL_FMTBUF_SIZE);
184     fmtbuf_len[idx] = INITIAL_FMTBUF_SIZE;
185   }
186   column = 0;
187   while (string < stringend) {
188     /*
189      * Is there enough room for this character, if it expands to
190      * a backslash plus 3 octal digits (which is the most it can
191      * expand to), and also enough room for a terminating '\0'?
192      */
193     if (column+3+1 >= fmtbuf_len[idx]) {
194       /*
195        * Double the buffer's size if it's not big enough.
196        * The size of the buffer starts at 128, so doubling its size
197        * adds at least another 128 bytes, which is more than enough
198        * for one more character plus a terminating '\0'.
199        */
200       fmtbuf_len[idx] = fmtbuf_len[idx] * 2;
201       fmtbuf[idx] = g_realloc(fmtbuf[idx], fmtbuf_len[idx]);
202     }
203     c = *string++;
204
205     if (isprint(c)) {
206       fmtbuf[idx][column] = c;
207       column++;
208     } else {
209       fmtbuf[idx][column] =  '\\';
210       column++;
211       switch (c) {
212
213       case '\a':
214         fmtbuf[idx][column] = 'a';
215         column++;
216         break;
217
218       case '\b':
219         fmtbuf[idx][column] = 'b'; /* BS */
220         column++;
221         break;
222
223       case '\f':
224         fmtbuf[idx][column] = 'f'; /* FF */
225         column++;
226         break;
227
228       case '\n':
229         fmtbuf[idx][column] = 'n'; /* NL */
230         column++;
231         break;
232
233       case '\r':
234         fmtbuf[idx][column] = 'r'; /* CR */
235         column++;
236         break;
237
238       case '\t':
239         fmtbuf[idx][column] = 't'; /* tab */
240         column++;
241         break;
242
243       case '\v':
244         fmtbuf[idx][column] = 'v';
245         column++;
246         break;
247
248       default:
249         i = (c>>6)&03;
250         fmtbuf[idx][column] = i + '0';
251         column++;
252         i = (c>>3)&07;
253         fmtbuf[idx][column] = i + '0';
254         column++;
255         i = (c>>0)&07;
256         fmtbuf[idx][column] = i + '0';
257         column++;
258         break;
259       }
260     }
261   }
262   fmtbuf[idx][column] = '\0';
263   return fmtbuf[idx];
264 }
265
266 /*
267  * Given a string, generate a string from it that shows non-printable
268  * characters as C-style escapes except a whitespace character
269  * (space, tab, carriage return, new line, vertical tab, or formfeed)
270  * which will be replaved by a space, and return a pointer to it.
271  */
272 gchar *
273 format_text_wsp(const guchar *string, int len)
274 {
275   static gchar *fmtbuf[3];
276   static int fmtbuf_len[3];
277   static int idx;
278   int column;
279   const guchar *stringend = string + len;
280   guchar c;
281   int i;
282
283   idx = (idx + 1) % 3;
284
285   /*
286    * Allocate the buffer if it's not already allocated.
287    */
288   if (fmtbuf[idx] == NULL) {
289     fmtbuf[idx] = g_malloc(INITIAL_FMTBUF_SIZE);
290     fmtbuf_len[idx] = INITIAL_FMTBUF_SIZE;
291   }
292   column = 0;
293   while (string < stringend) {
294     /*
295      * Is there enough room for this character, if it expands to
296      * a backslash plus 3 octal digits (which is the most it can
297      * expand to), and also enough room for a terminating '\0'?
298      */
299     if (column+3+1 >= fmtbuf_len[idx]) {
300       /*
301        * Double the buffer's size if it's not big enough.
302        * The size of the buffer starts at 128, so doubling its size
303        * adds at least another 128 bytes, which is more than enough
304        * for one more character plus a terminating '\0'.
305        */
306       fmtbuf_len[idx] = fmtbuf_len[idx] * 2;
307       fmtbuf[idx] = g_realloc(fmtbuf[idx], fmtbuf_len[idx]);
308     }
309     c = *string++;
310
311     if (isprint(c)) {
312       fmtbuf[idx][column] = c;
313       column++;
314     } else if  (isspace(c)) {
315       fmtbuf[idx][column] = ' ';
316       column++;
317         }else {
318       fmtbuf[idx][column] =  '\\';
319       column++;
320       switch (c) {
321
322       case '\a':
323         fmtbuf[idx][column] = 'a';
324         column++;
325         break;
326
327       case '\b':
328         fmtbuf[idx][column] = 'b'; /* BS */
329         column++;
330         break;
331
332       case '\f':
333         fmtbuf[idx][column] = 'f'; /* FF */
334         column++;
335         break;
336
337       case '\n':
338         fmtbuf[idx][column] = 'n'; /* NL */
339         column++;
340         break;
341
342       case '\r':
343         fmtbuf[idx][column] = 'r'; /* CR */
344         column++;
345         break;
346
347       case '\t':
348         fmtbuf[idx][column] = 't'; /* tab */
349         column++;
350         break;
351
352       case '\v':
353         fmtbuf[idx][column] = 'v';
354         column++;
355         break;
356
357       default:
358         i = (c>>6)&03;
359         fmtbuf[idx][column] = i + '0';
360         column++;
361         i = (c>>3)&07;
362         fmtbuf[idx][column] = i + '0';
363         column++;
364         i = (c>>0)&07;
365         fmtbuf[idx][column] = i + '0';
366         column++;
367         break;
368       }
369     }
370   }
371   fmtbuf[idx][column] = '\0';
372   return fmtbuf[idx];
373 }
374
375 /* Max string length for displaying byte string.  */
376 #define MAX_BYTE_STR_LEN        48
377
378 /* Turn an array of bytes into a string showing the bytes in hex. */
379 #define N_BYTES_TO_STR_STRINGS  6
380 gchar *
381 bytes_to_str(const guint8 *bd, int bd_len) {
382   return bytes_to_str_punct(bd,bd_len,'\0');
383 }
384
385 /* Turn an array of bytes into a string showing the bytes in hex with
386  * punct as a bytes separator.
387  */
388 gchar *
389 bytes_to_str_punct(const guint8 *bd, int bd_len, gchar punct) {
390   gchar        *cur;
391   gchar        *p;
392   int           len;
393
394   cur=ep_alloc(MAX_BYTE_STR_LEN+3+1);
395   p = cur;
396   len = MAX_BYTE_STR_LEN;
397   while (bd_len > 0 && len > 0) {
398     *p++ = hex[(*bd) >> 4];
399     *p++ = hex[(*bd) & 0xF];
400     len -= 2;
401     bd++;
402     bd_len--;
403     if(punct && bd_len > 0){
404       *p++ = punct;
405       len--;
406     }
407   }
408   if (bd_len != 0) {
409     /* Note that we're not showing the full string.  */
410     *p++ = '.';
411     *p++ = '.';
412     *p++ = '.';
413   }
414   *p = '\0';
415   return cur;
416 }
417
418 static gboolean
419 is_byte_sep(guint8 c)
420 {
421         return (c == '-' || c == ':' || c == '.');
422 }
423
424 /* Turn a string of hex digits with optional separators (defined by
425  * is_byte_sep() into a byte array.
426  */
427 gboolean
428 hex_str_to_bytes(const char *hex_str, GByteArray *bytes, gboolean force_separators) {
429         guint8          val;
430         const guchar    *p, *q, *punct;
431         char            two_digits[3];
432         char            one_digit[2];
433
434         g_byte_array_set_size(bytes, 0);
435         if (! hex_str) {
436                 return FALSE;
437         }
438         p = (const guchar *)hex_str;
439         while (*p) {
440                 q = p+1;
441                 if (*q && isxdigit(*p) && isxdigit(*q)) {
442                         two_digits[0] = *p;
443                         two_digits[1] = *q;
444                         two_digits[2] = '\0';
445
446                         /*
447                          * Two or more hex digits in a row.
448                          * "strtoul()" will succeed, as it'll see at
449                          * least one hex digit.
450                          */
451                         val = (guint8) strtoul(two_digits, NULL, 16);
452                         g_byte_array_append(bytes, &val, 1);
453                         punct = q + 1;
454                         if (*punct) {
455                                 /*
456                                  * Make sure the character after
457                                  * the second hex digit is a byte
458                                  * separator, i.e. that we don't have
459                                  * more than two hex digits, or a
460                                  * bogus character.
461                                  */
462                                 if (is_byte_sep(*punct)) {
463                                         p = punct + 1;
464                                         continue;
465                                 }
466                                 else if (force_separators) {
467                                         return FALSE;
468                                         break;
469                                 }
470                         }
471                         p = punct;
472                         continue;
473                 }
474                 else if (*q && isxdigit(*p) && is_byte_sep(*q)) {
475                         one_digit[0] = *p;
476                         one_digit[1] = '\0';
477
478                         /*
479                          * Only one hex digit.
480                          * "strtoul()" will succeed, as it'll see that
481                          * hex digit.
482                          */
483                         val = (guint8) strtoul(one_digit, NULL, 16);
484                         g_byte_array_append(bytes, &val, 1);
485                         p = q + 1;
486                         continue;
487                 }
488                 else if (!*q && isxdigit(*p)) {
489                         one_digit[0] = *p;
490                         one_digit[1] = '\0';
491
492                         /*
493                          * Only one hex digit.
494                          * "strtoul()" will succeed, as it'll see that
495                          * hex digit.
496                          */
497                         val = (guint8) strtoul(one_digit, NULL, 16);
498                         g_byte_array_append(bytes, &val, 1);
499                         p = q;
500                         continue;
501                 }
502                 else {
503                         return FALSE;
504                 }
505         }
506         return TRUE;
507 }
508
509 /*
510  * Turn an RFC 3986 percent-encoded string into a byte array.
511  * XXX - We don't check for reserved characters.
512  */
513 #define HEX_DIGIT_BUF_LEN 3
514 gboolean
515 uri_str_to_bytes(const char *uri_str, GByteArray *bytes) {
516         guint8          val;
517         const char      *p;
518         char            hex_digit[HEX_DIGIT_BUF_LEN];
519
520         g_byte_array_set_size(bytes, 0);
521         if (! uri_str) {
522                 return FALSE;
523         }
524
525         p = uri_str;
526
527         while (*p) {
528                 if (! isascii(*p) || ! isprint(*p))
529                         return FALSE;
530                 if (*p == '%') {
531                         p++;
532                         if (*p == '\0') return FALSE;
533                         hex_digit[0] = *p;
534                         p++;
535                         if (*p == '\0') return FALSE;
536                         hex_digit[1] = *p;
537                         hex_digit[2] = '\0';
538                         if (! isxdigit(hex_digit[0]) || ! isxdigit(hex_digit[1]))
539                                 return FALSE;
540                         val = (guint8) strtoul(hex_digit, NULL, 16);
541                         g_byte_array_append(bytes, &val, 1);
542                 } else {
543                         g_byte_array_append(bytes, (guint8 *) p, 1);
544                 }
545                 p++;
546
547         }
548         return TRUE;
549 }
550
551 /*
552  * Given a GByteArray, generate a string from it that shows non-printable
553  * characters as percent-style escapes, and return a pointer to it.
554  */
555 gchar *
556 format_uri(const GByteArray *bytes, const gchar *reserved_chars)
557 {
558   static gchar *fmtbuf[3];
559   static guint fmtbuf_len[3];
560   static guint idx;
561   const gchar *reserved_def = ":/?#[]@!$&'()*+,;= ";
562   const gchar *reserved = reserved_def;
563   guint8 c;
564   guint column, i;
565   gboolean is_reserved = FALSE;
566
567   if (! bytes)
568     return "";
569
570   idx = (idx + 1) % 3;
571   if (reserved_chars)
572     reserved = reserved_chars;
573
574   /*
575    * Allocate the buffer if it's not already allocated.
576    */
577   if (fmtbuf[idx] == NULL) {
578     fmtbuf[idx] = g_malloc(INITIAL_FMTBUF_SIZE);
579     fmtbuf_len[idx] = INITIAL_FMTBUF_SIZE;
580   }
581   for (column = 0; column < bytes->len; column++) {
582     /*
583      * Is there enough room for this character, if it expands to
584      * a percent plus 2 hex digits (which is the most it can
585      * expand to), and also enough room for a terminating '\0'?
586      */
587     if (column+2+1 >= fmtbuf_len[idx]) {
588       /*
589        * Double the buffer's size if it's not big enough.
590        * The size of the buffer starts at 128, so doubling its size
591        * adds at least another 128 bytes, which is more than enough
592        * for one more character plus a terminating '\0'.
593        */
594       fmtbuf_len[idx] = fmtbuf_len[idx] * 2;
595       fmtbuf[idx] = g_realloc(fmtbuf[idx], fmtbuf_len[idx]);
596     }
597     c = bytes->data[column];
598
599     if (!isascii(c) || !isprint(c) || c == '%') {
600       is_reserved = TRUE;
601     }
602
603     for (i = 0; i < strlen(reserved); i++) {
604       if (c == reserved[i])
605         is_reserved = TRUE;
606     }
607
608     if (!is_reserved) {
609       fmtbuf[idx][column] = c;
610     } else {
611       fmtbuf[idx][column] = '%';
612       column++;
613       fmtbuf[idx][column] = hex[c >> 4];
614       column++;
615       fmtbuf[idx][column] = hex[c & 0xF];
616     }
617   }
618   fmtbuf[idx][column] = '\0';
619   return fmtbuf[idx];
620 }
621
622 /**
623  * Create a copy of a GByteArray
624  *
625  * @param ba The byte array to be copied.
626  * @return If ba exists, a freshly allocated copy.  NULL otherwise.
627  *
628  * XXX - Should this be in strutil.c?
629  */
630 GByteArray *
631 byte_array_dup(GByteArray *ba) {
632     GByteArray *new_ba;
633
634     if (!ba)
635         return NULL;
636
637     new_ba = g_byte_array_new();
638     g_byte_array_append(new_ba, ba->data, ba->len);
639     return new_ba;
640 }
641
642 #define SUBID_BUF_LEN 5
643 gboolean
644 oid_str_to_bytes(const char *oid_str, GByteArray *bytes) {
645   guint32 subid0, subid, sicnt, i;
646   const char *p, *dot;
647   guint8 buf[SUBID_BUF_LEN];
648
649   g_byte_array_set_size(bytes, 0);
650
651   /* check syntax */
652   p = oid_str;
653   dot = NULL;
654   while (*p) {
655     if (!isdigit(*p) && (*p != '.')) return FALSE;
656     if (*p == '.') {
657       if (p == oid_str) return FALSE;
658       if (!*(p+1)) return FALSE;
659       if ((p-1) == dot) return FALSE;
660       dot = p;
661     }
662     p++;
663   }
664   if (!dot) return FALSE;
665
666   p = oid_str;
667   sicnt = 0;
668   subid0 = 0;   /* squelch GCC complaints */
669   while (*p) {
670     subid = 0;
671     while (isdigit(*p)) {
672       subid *= 10;
673       subid += *p - '0';
674       p++;
675     }
676     if (sicnt == 0) {
677       subid0 = subid;
678       if (subid0 > 2) return FALSE;
679     } else if (sicnt == 1) {
680       if ((subid0 < 2) && (subid > 39)) return FALSE;
681       subid += 40 * subid0;
682     }
683     if (sicnt) {
684       i = SUBID_BUF_LEN;
685       do {
686         i--;
687         buf[i] = 0x80 | (subid % 0x80);
688         subid >>= 7;
689       } while (subid && i);
690       buf[SUBID_BUF_LEN-1] &= 0x7F;
691       g_byte_array_append(bytes, buf + i, SUBID_BUF_LEN - i);
692     }
693     sicnt++;
694     if (*p) p++;
695   }
696
697   return TRUE;
698 }
699
700 /**
701  * Compare the contents of two GByteArrays
702  *
703  * @param ba1 A byte array
704  * @param ba2 A byte array
705  * @return If both arrays are non-NULL and their lengths are equal and
706  *         their contents are equal, returns TRUE.  Otherwise, returns
707  *         FALSE.
708  *
709  * XXX - Should this be in strutil.c?
710  */
711 gboolean
712 byte_array_equal(GByteArray *ba1, GByteArray *ba2) {
713     if (!ba1 || !ba2)
714         return FALSE;
715
716     if (ba1->len != ba2->len)
717         return FALSE;
718
719     if (memcmp(ba1->data, ba2->data, ba1->len) != 0)
720         return FALSE;
721
722     return TRUE;
723 }
724
725
726 /* Return a XML escaped representation of the unescaped string.
727  * The returned string must be freed when no longer in use. */
728 gchar *
729 xml_escape(const gchar *unescaped)
730 {
731         GString *buffer = g_string_sized_new(128);
732         const gchar *p;
733         gchar c;
734 #if GLIB_MAJOR_VERSION < 2
735         gchar *ret;
736 #endif
737
738         p = unescaped;
739         while ( (c = *p++) ) {
740                 switch (c) {
741                         case '<':
742                                 g_string_append(buffer, "&lt;");
743                                 break;
744                         case '>':
745                                 g_string_append(buffer, "&gt;");
746                                 break;
747                         case '&':
748                                 g_string_append(buffer, "&amp;");
749                                 break;
750                         case '\'':
751                                 g_string_append(buffer, "&apos;");
752                                 break;
753                         case '"':
754                                 g_string_append(buffer, "&quot;");
755                                 break;
756                         default:
757                                 g_string_append_c(buffer, c);
758                                 break;
759                 }
760         }
761 #if GLIB_MAJOR_VERSION >= 2
762         /* Return the string value contained within the GString
763          * after getting rid of the GString structure.
764          * This is the way to do this, see the GLib reference. */
765         return g_string_free(buffer, FALSE);
766 #else
767         /* But it's not the way to do it in GLib 1.2[.x], as
768          * 1.2[.x]'s "g_string_free()" doesn't return anything.
769          * This is the way to do this in GLib 1.2[.x]. */
770         ret = buffer->str;
771         g_string_free(buffer, FALSE);
772         return ret;
773 #endif
774 }
775
776
777 /* Return the first occurrence of needle in haystack.
778  * If not found, return NULL.
779  * If either haystack or needle has 0 length, return NULL.
780  * Algorithm copied from GNU's glibc 2.3.2 memcmp() */
781 const guint8 *
782 epan_memmem(const guint8 *haystack, guint haystack_len,
783                 const guint8 *needle, guint needle_len)
784 {
785         const guint8 *begin;
786         const guint8 *const last_possible
787                 = haystack + haystack_len - needle_len;
788
789         if (needle_len == 0) {
790                 return NULL;
791         }
792
793         if (needle_len > haystack_len) {
794                 return NULL;
795         }
796
797         for (begin = haystack ; begin <= last_possible; ++begin) {
798                 if (begin[0] == needle[0] &&
799                         !memcmp(&begin[1], needle + 1,
800                                 needle_len - 1)) {
801                         return begin;
802                 }
803         }
804
805         return NULL;
806 }
807
808 /*
809  * Scan the search string to make sure it's valid hex.  Return the
810  * number of bytes in nbytes.
811  */
812 guint8 *
813 convert_string_to_hex(const char *string, size_t *nbytes)
814 {
815   size_t n_bytes;
816   const char *p;
817   guchar c;
818   guint8 *bytes, *q, byte_val;
819
820   n_bytes = 0;
821   p = &string[0];
822   for (;;) {
823     c = *p++;
824     if (c == '\0')
825       break;
826     if (isspace(c))
827       continue; /* allow white space */
828     if (c==':' || c=='.' || c=='-')
829       continue; /* skip any ':', '.', or '-' between bytes */
830     if (!isxdigit(c)) {
831       /* Not a valid hex digit - fail */
832       return NULL;
833     }
834
835     /*
836      * We can only match bytes, not nibbles; we must have a valid
837      * hex digit immediately after that hex digit.
838      */
839     c = *p++;
840     if (!isxdigit(c))
841       return NULL;
842
843     /* 2 hex digits = 1 byte */
844     n_bytes++;
845   }
846
847   /*
848    * Were we given any hex digits?
849    */
850   if (n_bytes == 0) {
851       /* No. */
852       return NULL;
853   }
854
855   /*
856    * OK, it's valid, and it generates "n_bytes" bytes; generate the
857    * raw byte array.
858    */
859   bytes = g_malloc(n_bytes);
860   p = &string[0];
861   q = &bytes[0];
862   for (;;) {
863     c = *p++;
864     if (c == '\0')
865       break;
866     if (isspace(c))
867       continue; /* allow white space */
868     if (c==':' || c=='.' || c=='-')
869       continue; /* skip any ':', '.', or '-' between bytes */
870     /* From the loop above, we know this is a hex digit */
871     if (isdigit(c))
872       byte_val = c - '0';
873     else if (c >= 'a')
874       byte_val = (c - 'a') + 10;
875     else
876       byte_val = (c - 'A') + 10;
877     byte_val <<= 4;
878
879     /* We also know this is a hex digit */
880     c = *p++;
881     if (isdigit(c))
882       byte_val |= c - '0';
883     else if (c >= 'a')
884       byte_val |= (c - 'a') + 10;
885     else if (c >= 'A')
886       byte_val |= (c - 'A') + 10;
887
888     *q++ = byte_val;
889   }
890   *nbytes = n_bytes;
891   return bytes;
892 }
893
894 /*
895  * Copy if if it's a case-sensitive search; uppercase it if it's
896  * a case-insensitive search.
897  */
898 char *
899 convert_string_case(const char *string, gboolean case_insensitive)
900 {
901   char *out_string;
902   const char *p;
903   char c;
904   char *q;
905
906   if (case_insensitive) {
907     out_string = g_malloc(strlen(string) + 1);
908     for (p = &string[0], q = &out_string[0]; (c = *p) != '\0'; p++, q++)
909       *q = toupper((unsigned char)*p);
910     *q = '\0';
911   } else
912     out_string = g_strdup(string);
913   return out_string;
914 }
915
916 /* g_strlcat() does not exist in GLib 1.2[.x] */
917 #if GLIB_MAJOR_VERSION < 2
918 gsize
919 g_strlcat(gchar *dst, gchar *src, gsize size)
920 {
921         int strl, strs;
922         strl=strlen(dst);
923         strs=strlen(src);
924         if(strl<size)
925                 g_snprintf(dst+strl, size-strl, "%s", src);
926         dst[size-1]=0;
927         return strl+strs;
928 }
929 #endif