1 /*
2
3 silcstrutil.c
4
5 Author: Pekka Riikonen <priikone@silcnet.org>
6
7 Copyright (C) 2002 - 2007 Pekka Riikonen
8
9 The contents of this file are subject to one of the Licenses specified
10 in the COPYING file; You may not use this file except in compliance
11 with the License.
12
13 The software distributed under the License is distributed on an "AS IS"
14 basis, in the hope that it will be useful, but WITHOUT WARRANTY OF ANY
15 KIND, either expressed or implied. See the COPYING file for more
16 information.
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 Base 64 encoding. Returns NULL terminated base 64 encoded
28 data string. */
29
silc_base64_encode(unsigned char * data,SilcUInt32 len)30 char *silc_base64_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
silc_base64_encode_file(unsigned char * data,SilcUInt32 data_len)78 char *silc_base64_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_base64_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 Base 64 into data. Returns the decoded data. */
105
silc_base64_decode(unsigned char * base64,SilcUInt32 base64_len,SilcUInt32 * ret_len)106 unsigned char *silc_base64_decode(unsigned char *base64,
107 SilcUInt32 base64_len,
108 SilcUInt32 *ret_len)
109 {
110 int i, j;
111 SilcUInt32 len, c, char_count, bits;
112 unsigned char *data;
113 static char ialpha[256], decoder[256];
114
115 for (i = 64 - 1; i >= 0; i--) {
116 ialpha[pem_enc[i]] = 1;
117 decoder[pem_enc[i]] = i;
118 }
119
120 char_count = 0;
121 bits = 0;
122 j = 0;
123
124 if (!base64_len)
125 len = strlen(base64);
126 else
127 len = base64_len;
128
129 data = silc_calloc(((len * 6) / 8), sizeof(*data));
130
131 for (i = 0; i < len; i++) {
132 c = base64[i];
133
134 if (c == '=')
135 break;
136
137 if (c > 127 || !ialpha[c])
138 continue;
139
140 bits += decoder[c];
141 char_count++;
142
143 if (char_count == 4) {
144 data[j++] = bits >> 16;
145 data[j++] = (bits >> 8) & 0xff;
146 data[j++] = bits & 0xff;
147 bits = 0;
148 char_count = 0;
149 } else {
150 bits <<= 6;
151 }
152 }
153
154 switch(char_count) {
155 case 1:
156 silc_free(data);
157 return NULL;
158 break;
159 case 2:
160 data[j++] = bits >> 10;
161 break;
162 case 3:
163 data[j++] = bits >> 16;
164 data[j++] = (bits >> 8) & 0xff;
165 break;
166 }
167
168 if (ret_len)
169 *ret_len = j;
170
171 return data;
172 }
173
174 /* Concatenates the `src' into `dest'. If `src_len' is more than the
175 size of the `dest' (minus NULL at the end) the `src' will be
176 truncated to fit. */
177
silc_strncat(char * dest,SilcUInt32 dest_size,const char * src,SilcUInt32 src_len)178 char *silc_strncat(char *dest, SilcUInt32 dest_size,
179 const char *src, SilcUInt32 src_len)
180 {
181 int len;
182
183 dest[dest_size - 1] = '\0';
184
185 len = dest_size - 1 - strlen(dest);
186 if (len < src_len) {
187 if (len > 0)
188 strncat(dest, src, len);
189 } else {
190 strncat(dest, src, src_len);
191 }
192
193 return dest;
194 }
195
196 /* Compares two strings. Strings may include wildcards '*' and '?'.
197 Returns TRUE if strings match. */
198
silc_string_compare(char * string1,char * string2)199 int silc_string_compare(char *string1, char *string2)
200 {
201 int i;
202 int slen1;
203 int slen2;
204 char *tmpstr1, *tmpstr2;
205
206 if (!string1 || !string2)
207 return FALSE;
208
209 slen1 = strlen(string1);
210 slen2 = strlen(string2);
211
212 /* See if they are same already */
213 if (!strncmp(string1, string2, slen2) && slen2 == slen1)
214 return TRUE;
215
216 if (slen2 < slen1)
217 if (!strchr(string1, '*'))
218 return FALSE;
219
220 /* Take copies of the original strings as we will change them */
221 tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
222 memcpy(tmpstr1, string1, slen1);
223 tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
224 memcpy(tmpstr2, string2, slen2);
225
226 for (i = 0; i < slen1; i++) {
227
228 /* * wildcard. Only one * wildcard is possible. */
229 if (tmpstr1[i] == '*')
230 if (!strncmp(tmpstr1, tmpstr2, i)) {
231 memset(tmpstr2, 0, slen2);
232 strncpy(tmpstr2, tmpstr1, i);
233 break;
234 }
235
236 /* ? wildcard */
237 if (tmpstr1[i] == '?') {
238 if (!strncmp(tmpstr1, tmpstr2, i)) {
239 if (!(slen1 < i + 1))
240 if (tmpstr1[i + 1] != '?' &&
241 tmpstr1[i + 1] != tmpstr2[i + 1])
242 continue;
243
244 if (!(slen1 < slen2))
245 tmpstr2[i] = '?';
246 }
247 }
248 }
249
250 /* if using *, remove it */
251 if (strchr(tmpstr1, '*'))
252 *strchr(tmpstr1, '*') = 0;
253
254 if (!strcmp(tmpstr1, tmpstr2)) {
255 memset(tmpstr1, 0, slen1);
256 memset(tmpstr2, 0, slen2);
257 silc_free(tmpstr1);
258 silc_free(tmpstr2);
259 return TRUE;
260 }
261
262 memset(tmpstr1, 0, slen1);
263 memset(tmpstr2, 0, slen2);
264 silc_free(tmpstr1);
265 silc_free(tmpstr2);
266 return FALSE;
267 }
268
269 /* Splits a string containing separator `ch' and returns an array of the
270 splitted strings. */
271
silc_string_split(const char * string,char ch,int * ret_count)272 char **silc_string_split(const char *string, char ch, int *ret_count)
273 {
274 char **splitted = NULL, sep[1], *item, *cp;
275 int i = 0, len;
276
277 if (!string)
278 return NULL;
279 if (!ret_count)
280 return NULL;
281
282 splitted = silc_calloc(1, sizeof(*splitted));
283 if (!splitted)
284 return NULL;
285
286 if (!strchr(string, ch)) {
287 splitted[0] = silc_memdup(string, strlen(string));
288 *ret_count = 1;
289 return splitted;
290 }
291
292 sep[0] = ch;
293 cp = (char *)string;
294 while(cp) {
295 len = strcspn(cp, sep);
296 item = silc_memdup(cp, len);
297 if (!item) {
298 silc_free(splitted);
299 return NULL;
300 }
301
302 cp += len;
303 if (strlen(cp) == 0)
304 cp = NULL;
305 else
306 cp++;
307
308 splitted = silc_realloc(splitted, (i + 1) * sizeof(*splitted));
309 if (!splitted)
310 return NULL;
311 splitted[i++] = item;
312 }
313 *ret_count = i;
314
315 return splitted;
316 }
317
318 /* Inspects the `string' for wildcards and returns regex string that can
319 be used by the GNU regex library. A comma (`,') in the `string' means
320 that the string is list. */
321
silc_string_regexify(const char * string)322 char *silc_string_regexify(const char *string)
323 {
324 int i, len, count;
325 char *regex;
326
327 if (!string)
328 return NULL;
329
330 len = strlen(string);
331 count = 4;
332 for (i = 0; i < len; i++) {
333 if (string[i] == '*' || string[i] == '?')
334 count++; /* Will add '.' */
335 if (string[i] == ',')
336 count += 2; /* Will add '|' and '^' */
337 }
338
339 regex = silc_calloc(len + count + 1, sizeof(*regex));
340 if (!regex)
341 return NULL;
342
343 count = 0;
344 regex[count++] = '(';
345 regex[count++] = '^';
346
347 for (i = 0; i < len; i++) {
348 if (string[i] == '*' || string[i] == '?') {
349 regex[count] = '.';
350 count++;
351 } else if (string[i] == ',') {
352 if (i + 2 == len)
353 continue;
354 regex[count++] = '|';
355 regex[count++] = '^';
356 continue;
357 }
358
359 regex[count++] = string[i];
360 }
361
362 regex[count++] = ')';
363 regex[count] = '$';
364
365 return regex;
366 }
367
368 /* Combines two regex strings into one regex string so that they can be
369 used as one by the GNU regex library. The `string2' is combine into
370 the `string1'. */
371
silc_string_regex_combine(const char * string1,const char * string2)372 char *silc_string_regex_combine(const char *string1, const char *string2)
373 {
374 char *tmp;
375 int len1, len2;
376
377 if (!string1 || !string2)
378 return NULL;
379
380 len1 = strlen(string1);
381 len2 = strlen(string2);
382
383 tmp = silc_calloc(2 + len1 + len2, sizeof(*tmp));
384 strncat(tmp, string1, len1 - 2);
385 strncat(tmp, "|", 1);
386 strncat(tmp, string2 + 1, len2 - 1);
387
388 return tmp;
389 }
390
391 /* Matches the two strings and returns TRUE if the strings match. */
392
silc_string_regex_match(const char * regex,const char * string)393 int silc_string_regex_match(const char *regex, const char *string)
394 {
395 regex_t preg;
396 int ret = FALSE;
397
398 if (regcomp(&preg, regex, REG_NOSUB | REG_EXTENDED) != 0)
399 return FALSE;
400
401 if (regexec(&preg, string, 0, NULL, 0) == 0)
402 ret = TRUE;
403
404 regfree(&preg);
405
406 return ret;
407 }
408
409 /* Do regex match to the two strings `string1' and `string2'. If the
410 `string2' matches the `string1' this returns TRUE. */
411
silc_string_match(const char * string1,const char * string2)412 int silc_string_match(const char *string1, const char *string2)
413 {
414 char *s1;
415 int ret = FALSE;
416
417 if (!string1 || !string2)
418 return ret;
419
420 s1 = silc_string_regexify(string1);
421 ret = silc_string_regex_match(s1, string2);
422 silc_free(s1);
423
424 return ret;
425 }
426