db912fe3204b99ba3dcff8fedd3871760baf786e
[silc.git] / lib / silcutil / silcstrutil.c
1 /*
2
3   silcstrutil.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2002 - 2006 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 /* Concatenates the `src' into `dest'.  If `src_len' is more than the
174    size of the `dest' (minus NULL at the end) the `src' will be
175    truncated to fit. */
176
177 char *silc_strncat(char *dest, SilcUInt32 dest_size,
178                    const char *src, SilcUInt32 src_len)
179 {
180   int len;
181
182   dest[dest_size - 1] = '\0';
183
184   len = dest_size - 1 - strlen(dest);
185   if (len < src_len) {
186     if (len > 0)
187       strncat(dest, src, len);
188   } else {
189     strncat(dest, src, src_len);
190   }
191
192   return dest;
193 }
194
195 /* Compares two strings. Strings may include wildcards '*' and '?'.
196    Returns TRUE if strings match. */
197
198 int silc_string_compare(char *string1, char *string2)
199 {
200   int i;
201   int slen1;
202   int slen2;
203   char *tmpstr1, *tmpstr2;
204
205   if (!string1 || !string2)
206     return FALSE;
207
208   slen1 = strlen(string1);
209   slen2 = strlen(string2);
210
211   /* See if they are same already */
212   if (!strncmp(string1, string2, slen2) && slen2 == slen1)
213     return TRUE;
214
215   if (slen2 < slen1)
216     if (!strchr(string1, '*'))
217       return FALSE;
218
219   /* Take copies of the original strings as we will change them */
220   tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
221   memcpy(tmpstr1, string1, slen1);
222   tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
223   memcpy(tmpstr2, string2, slen2);
224
225   for (i = 0; i < slen1; i++) {
226
227     /* * wildcard. Only one * wildcard is possible. */
228     if (tmpstr1[i] == '*')
229       if (!strncmp(tmpstr1, tmpstr2, i)) {
230         memset(tmpstr2, 0, slen2);
231         strncpy(tmpstr2, tmpstr1, i);
232         break;
233       }
234
235     /* ? wildcard */
236     if (tmpstr1[i] == '?') {
237       if (!strncmp(tmpstr1, tmpstr2, i)) {
238         if (!(slen1 < i + 1))
239           if (tmpstr1[i + 1] != '?' &&
240               tmpstr1[i + 1] != tmpstr2[i + 1])
241             continue;
242
243         if (!(slen1 < slen2))
244           tmpstr2[i] = '?';
245       }
246     }
247   }
248
249   /* if using *, remove it */
250   if (strchr(tmpstr1, '*'))
251     *strchr(tmpstr1, '*') = 0;
252
253   if (!strcmp(tmpstr1, tmpstr2)) {
254     memset(tmpstr1, 0, slen1);
255     memset(tmpstr2, 0, slen2);
256     silc_free(tmpstr1);
257     silc_free(tmpstr2);
258     return TRUE;
259   }
260
261   memset(tmpstr1, 0, slen1);
262   memset(tmpstr2, 0, slen2);
263   silc_free(tmpstr1);
264   silc_free(tmpstr2);
265   return FALSE;
266 }
267
268 /* Splits a string containing separator `ch' and returns an array of the
269    splitted strings. */
270
271 char **silc_string_split(const char *string, char ch, int *ret_count)
272 {
273   char **splitted = NULL, sep[1], *item, *cp;
274   int i = 0, len;
275
276   if (!string)
277     return NULL;
278   if (!ret_count)
279     return NULL;
280
281   splitted = silc_calloc(1, sizeof(*splitted));
282   if (!splitted)
283     return NULL;
284
285   if (!strchr(string, ch)) {
286     splitted[0] = silc_memdup(string, strlen(string));
287     *ret_count = 1;
288     return splitted;
289   }
290
291   sep[0] = ch;
292   cp = (char *)string;
293   while(cp) {
294     len = strcspn(cp, sep);
295     item = silc_memdup(cp, len);
296     if (!item) {
297       silc_free(splitted);
298       return NULL;
299     }
300
301     cp += len;
302     if (strlen(cp) == 0)
303       cp = NULL;
304     else
305       cp++;
306
307     splitted = silc_realloc(splitted, (i + 1) * sizeof(*splitted));
308     if (!splitted)
309       return NULL;
310     splitted[i++] = item;
311   }
312   *ret_count = i;
313
314   return splitted;
315 }