Added preliminary Symbian support.
[silc.git] / lib / silcutil / silcstrutil.c
1 /*
2
3   silcstrutil.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2002 - 2007 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
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 */
19 /* $Id$ */
20
21 #include "silc.h"
22 #include "silcstrutil.h"
23
24 static unsigned char pem_enc[64] =
25 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
26
27 /* Encodes data into PEM encoding. Returns NULL terminated PEM encoded
28    data string. */
29
30 char *silc_pem_encode(unsigned char *data, SilcUInt32 len)
31 {
32   int i, j;
33   SilcUInt32 bits, c, char_count;
34   char *pem;
35
36   char_count = 0;
37   bits = 0;
38   j = 0;
39
40   pem = silc_calloc(((len * 8 + 5) / 6) + 5, sizeof(*pem));
41
42   for (i = 0; i < len; i++) {
43     c = data[i];
44     bits += c;
45     char_count++;
46
47     if (char_count == 3) {
48       pem[j++] = pem_enc[bits  >> 18];
49       pem[j++] = pem_enc[(bits >> 12) & 0x3f];
50       pem[j++] = pem_enc[(bits >> 6)  & 0x3f];
51       pem[j++] = pem_enc[bits & 0x3f];
52       bits = 0;
53       char_count = 0;
54     } else {
55       bits <<= 8;
56     }
57   }
58
59   if (char_count != 0) {
60     bits <<= 16 - (8 * char_count);
61     pem[j++] = pem_enc[bits >> 18];
62     pem[j++] = pem_enc[(bits >> 12) & 0x3f];
63
64     if (char_count == 1) {
65       pem[j++] = '=';
66       pem[j] = '=';
67     } else {
68       pem[j++] = pem_enc[(bits >> 6) & 0x3f];
69       pem[j] = '=';
70     }
71   }
72
73   return pem;
74 }
75
76 /* Same as above but puts newline ('\n') every 72 characters. */
77
78 char *silc_pem_encode_file(unsigned char *data, SilcUInt32 data_len)
79 {
80   int i, j;
81   SilcUInt32 len, cols;
82   char *pem, *pem2;
83
84   pem = silc_pem_encode(data, data_len);
85   len = strlen(pem);
86
87   pem2 = silc_calloc(len + (len / 72) + 1, sizeof(*pem2));
88
89   for (i = 0, j = 0, cols = 1; i < len; i++, cols++) {
90     if (cols == 72) {
91       pem2[i] = '\n';
92       cols = 0;
93       len++;
94       continue;
95     }
96
97     pem2[i] = pem[j++];
98   }
99
100   silc_free(pem);
101   return pem2;
102 }
103
104 /* Decodes PEM into data. Returns the decoded data. */
105
106 unsigned char *silc_pem_decode(unsigned char *pem, SilcUInt32 pem_len,
107                                SilcUInt32 *ret_len)
108 {
109   int i, j;
110   SilcUInt32 len, c, char_count, bits;
111   unsigned char *data;
112   static char ialpha[256], decoder[256];
113
114   for (i = 64 - 1; i >= 0; i--) {
115     ialpha[pem_enc[i]] = 1;
116     decoder[pem_enc[i]] = i;
117   }
118
119   char_count = 0;
120   bits = 0;
121   j = 0;
122
123   if (!pem_len)
124     len = strlen(pem);
125   else
126     len = pem_len;
127
128   data = silc_calloc(((len * 6) / 8), sizeof(*data));
129
130   for (i = 0; i < len; i++) {
131     c = pem[i];
132
133     if (c == '=')
134       break;
135
136     if (c > 127 || !ialpha[c])
137       continue;
138
139     bits += decoder[c];
140     char_count++;
141
142     if (char_count == 4) {
143       data[j++] = bits >> 16;
144       data[j++] = (bits >> 8) & 0xff;
145       data[j++] = bits & 0xff;
146       bits = 0;
147       char_count = 0;
148     } else {
149       bits <<= 6;
150     }
151   }
152
153   switch(char_count) {
154   case 1:
155     silc_free(data);
156     return NULL;
157     break;
158   case 2:
159     data[j++] = bits >> 10;
160     break;
161   case 3:
162     data[j++] = bits >> 16;
163     data[j++] = (bits >> 8) & 0xff;
164     break;
165   }
166
167   if (ret_len)
168     *ret_len = j;
169
170   return data;
171 }
172
173 #ifndef HAVE_SNPRINTF
174 /* Outputs string according to the `format'. */
175
176 int silc_snprintf(char *str, SilcUInt32 size, const char *format, ...)
177 {
178
179 }
180 #endif /* HAVE_SNPRINTF */
181
182 /* Concatenates the `src' into `dest'.  If `src_len' is more than the
183    size of the `dest' (minus NULL at the end) the `src' will be
184    truncated to fit. */
185
186 char *silc_strncat(char *dest, SilcUInt32 dest_size,
187                    const char *src, SilcUInt32 src_len)
188 {
189   int len;
190
191   dest[dest_size - 1] = '\0';
192
193   len = dest_size - 1 - strlen(dest);
194   if (len < src_len) {
195     if (len > 0)
196       strncat(dest, src, len);
197   } else {
198     strncat(dest, src, src_len);
199   }
200
201   return dest;
202 }
203
204 /* Compares two strings. Strings may include wildcards '*' and '?'.
205    Returns TRUE if strings match. */
206
207 int silc_string_compare(char *string1, char *string2)
208 {
209   int i;
210   int slen1;
211   int slen2;
212   char *tmpstr1, *tmpstr2;
213
214   if (!string1 || !string2)
215     return FALSE;
216
217   slen1 = strlen(string1);
218   slen2 = strlen(string2);
219
220   /* See if they are same already */
221   if (!strncmp(string1, string2, slen2) && slen2 == slen1)
222     return TRUE;
223
224   if (slen2 < slen1)
225     if (!strchr(string1, '*'))
226       return FALSE;
227
228   /* Take copies of the original strings as we will change them */
229   tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
230   memcpy(tmpstr1, string1, slen1);
231   tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
232   memcpy(tmpstr2, string2, slen2);
233
234   for (i = 0; i < slen1; i++) {
235
236     /* * wildcard. Only one * wildcard is possible. */
237     if (tmpstr1[i] == '*')
238       if (!strncmp(tmpstr1, tmpstr2, i)) {
239         memset(tmpstr2, 0, slen2);
240         strncpy(tmpstr2, tmpstr1, i);
241         break;
242       }
243
244     /* ? wildcard */
245     if (tmpstr1[i] == '?') {
246       if (!strncmp(tmpstr1, tmpstr2, i)) {
247         if (!(slen1 < i + 1))
248           if (tmpstr1[i + 1] != '?' &&
249               tmpstr1[i + 1] != tmpstr2[i + 1])
250             continue;
251
252         if (!(slen1 < slen2))
253           tmpstr2[i] = '?';
254       }
255     }
256   }
257
258   /* if using *, remove it */
259   if (strchr(tmpstr1, '*'))
260     *strchr(tmpstr1, '*') = 0;
261
262   if (!strcmp(tmpstr1, tmpstr2)) {
263     memset(tmpstr1, 0, slen1);
264     memset(tmpstr2, 0, slen2);
265     silc_free(tmpstr1);
266     silc_free(tmpstr2);
267     return TRUE;
268   }
269
270   memset(tmpstr1, 0, slen1);
271   memset(tmpstr2, 0, slen2);
272   silc_free(tmpstr1);
273   silc_free(tmpstr2);
274   return FALSE;
275 }
276
277 /* Splits a string containing separator `ch' and returns an array of the
278    splitted strings. */
279
280 char **silc_string_split(const char *string, char ch, int *ret_count)
281 {
282   char **splitted = NULL, sep[1], *item, *cp;
283   int i = 0, len;
284
285   if (!string)
286     return NULL;
287   if (!ret_count)
288     return NULL;
289
290   splitted = silc_calloc(1, sizeof(*splitted));
291   if (!splitted)
292     return NULL;
293
294   if (!strchr(string, ch)) {
295     splitted[0] = silc_memdup(string, strlen(string));
296     *ret_count = 1;
297     return splitted;
298   }
299
300   sep[0] = ch;
301   cp = (char *)string;
302   while(cp) {
303     len = strcspn(cp, sep);
304     item = silc_memdup(cp, len);
305     if (!item) {
306       silc_free(splitted);
307       return NULL;
308     }
309
310     cp += len;
311     if (strlen(cp) == 0)
312       cp = NULL;
313     else
314       cp++;
315
316     splitted = silc_realloc(splitted, (i + 1) * sizeof(*splitted));
317     if (!splitted)
318       return NULL;
319     splitted[i++] = item;
320   }
321   *ret_count = i;
322
323   return splitted;
324 }