5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2002 Pekka Riikonen
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.
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.
20 #include "silcincludes.h"
21 #include "silcstrutil.h"
23 static unsigned char pem_enc[64] =
24 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
26 /* Encodes data into PEM encoding. Returns NULL terminated PEM encoded
27 data string. Note: This is originally public domain code and is
30 char *silc_pem_encode(unsigned char *data, SilcUInt32 len)
33 SilcUInt32 bits, c, char_count;
40 pem = silc_calloc(((len * 8 + 5) / 6) + 5, sizeof(*pem));
42 for (i = 0; i < len; i++) {
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];
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];
64 if (char_count == 1) {
68 pem[j++] = pem_enc[(bits >> 6) & 0x3f];
76 /* Same as above but puts newline ('\n') every 72 characters. */
78 char *silc_pem_encode_file(unsigned char *data, SilcUInt32 data_len)
84 pem = silc_pem_encode(data, data_len);
87 pem2 = silc_calloc(len + (len / 72) + 1, sizeof(*pem2));
89 for (i = 0, j = 0, cols = 1; i < len; i++, cols++) {
104 /* Decodes PEM into data. Returns the decoded data. Note: This is
105 originally public domain code and is still PD. */
107 unsigned char *silc_pem_decode(unsigned char *pem, SilcUInt32 pem_len,
111 SilcUInt32 len, c, char_count, bits;
113 static char ialpha[256], decoder[256];
115 for (i = 64 - 1; i >= 0; i--) {
116 ialpha[pem_enc[i]] = 1;
117 decoder[pem_enc[i]] = i;
129 data = silc_calloc(((len * 6) / 8), sizeof(*data));
131 for (i = 0; i < len; i++) {
137 if (c > 127 || !ialpha[c])
143 if (char_count == 4) {
144 data[j++] = bits >> 16;
145 data[j++] = (bits >> 8) & 0xff;
146 data[j++] = bits & 0xff;
160 data[j++] = bits >> 10;
163 data[j++] = bits >> 16;
164 data[j++] = (bits >> 8) & 0xff;
174 /* Encodes the string `bin' of which encoding is `bin_encoding' to the
175 UTF-8 encoding into the buffer `utf8' which is of size of `utf8_size'.
176 Returns the length of the UTF-8 encoded string, or zero (0) on error.
177 By default `bin_encoding' is ASCII, and the caller needs to know the
178 encoding of the input string if it is anything else. */
180 SilcUInt32 silc_utf8_encode(const unsigned char *bin, SilcUInt32 bin_len,
181 SilcStringEncoding bin_encoding,
182 unsigned char *utf8, SilcUInt32 utf8_size)
184 SilcUInt32 enclen = 0, i, charval = 0;
186 if (!bin || !bin_len)
189 for (i = 0; i < bin_len; i++) {
190 switch (bin_encoding) {
191 case SILC_STRING_ASCII:
194 case SILC_STRING_ASCII_ESC:
196 case SILC_STRING_BMP:
198 case SILC_STRING_UNIVERSAL:
202 if (charval < 0x80) {
204 if (enclen > utf8_size)
207 utf8[enclen] = (unsigned char)charval;
210 } else if (charval < 0x800) {
212 if (enclen + 2 > utf8_size)
215 utf8[enclen ] = (unsigned char )(((charval >> 6) & 0x1f) | 0xc0);
216 utf8[enclen + 1] = (unsigned char )((charval & 0x3f) | 0x80);
219 } else if (charval < 0x10000) {
221 if (enclen + 3 > utf8_size)
224 utf8[enclen ] = (unsigned char )(((charval >> 12) & 0xf) | 0xe0);
225 utf8[enclen + 1] = (unsigned char )(((charval >> 6) & 0x3f) | 0x80);
226 utf8[enclen + 2] = (unsigned char )((charval & 0x3f) | 0x80);
229 } else if (charval < 0x200000) {
231 if (enclen + 4 > utf8_size)
234 utf8[enclen ] = (unsigned char )(((charval >> 18) & 0x7) | 0xf0);
235 utf8[enclen + 1] = (unsigned char )(((charval >> 12) & 0x3f) | 0x80);
236 utf8[enclen + 2] = (unsigned char )(((charval >> 6) & 0x3f) | 0x80);
237 utf8[enclen + 3] = (unsigned char )((charval & 0x3f) | 0x80);
240 } else if (charval < 0x4000000) {
242 if (enclen + 5 > utf8_size)
245 utf8[enclen ] = (unsigned char )(((charval >> 24) & 0x3) | 0xf8);
246 utf8[enclen + 1] = (unsigned char )(((charval >> 18) & 0x3f) | 0x80);
247 utf8[enclen + 2] = (unsigned char )(((charval >> 12) & 0x3f) | 0x80);
248 utf8[enclen + 3] = (unsigned char )(((charval >> 6) & 0x3f) | 0x80);
249 utf8[enclen + 4] = (unsigned char )((charval & 0x3f) | 0x80);
254 if (enclen + 6 > utf8_size)
257 utf8[enclen ] = (unsigned char )(((charval >> 30) & 0x1) | 0xfc);
258 utf8[enclen + 1] = (unsigned char )(((charval >> 24) & 0x3f) | 0x80);
259 utf8[enclen + 2] = (unsigned char )(((charval >> 18) & 0x3f) | 0x80);
260 utf8[enclen + 3] = (unsigned char )(((charval >> 12) & 0x3f) | 0x80);
261 utf8[enclen + 4] = (unsigned char )(((charval >> 6) & 0x3f) | 0x80);
262 utf8[enclen + 5] = (unsigned char )((charval & 0x3f) | 0x80);
271 /* Decodes UTF-8 encoded string `utf8' to string of which encoding is
272 to be `bin_encoding', into the `bin' buffer of size of `bin_size'.
273 Returns the length of the decoded buffer, or zero (0) on error.
274 By default `bin_encoding' is ASCII, and the caller needs to know to
275 which encoding the output string is to be encoded if ASCII is not
278 SilcUInt32 silc_utf8_decode(const unsigned char *utf8, SilcUInt32 utf8_len,
279 SilcStringEncoding bin_encoding,
280 unsigned char *bin, SilcUInt32 bin_size)
282 SilcUInt32 enclen = 0, i, charval;
284 if (!utf8 || !utf8_len)
287 for (i = 0; i < utf8_len; i++) {
288 if ((utf8[i] & 0x80) == 0x00) {
289 charval = utf8[i] & 0x7f;
290 } else if ((utf8[i] & 0xe0) == 0xc0) {
294 if ((utf8[i + 1] & 0xc0) != 0x80)
297 charval = (utf8[i++] & 0x1f) << 6;
298 charval |= utf8[i] & 0x3f;
301 } else if ((utf8[i] & 0xf0) == 0xe0) {
305 if (((utf8[i + 1] & 0xc0) != 0x80) ||
306 ((utf8[i + 2] & 0xc0) != 0x80))
309 charval = (utf8[i++] & 0xf) << 12;
310 charval |= (utf8[i++] & 0x3f) << 6;
311 charval |= utf8[i] & 0x3f;
314 } else if ((utf8[i] & 0xf8) == 0xf0) {
318 if (((utf8[i + 1] & 0xc0) != 0x80) ||
319 ((utf8[i + 2] & 0xc0) != 0x80) ||
320 ((utf8[i + 3] & 0xc0) != 0x80))
323 charval = ((SilcUInt32)(utf8[i++] & 0x7)) << 18;
324 charval |= (utf8[i++] & 0x3f) << 12;
325 charval |= (utf8[i++] & 0x3f) << 6;
326 charval |= utf8[i] & 0x3f;
327 if (charval < 0x10000)
329 } else if ((utf8[i] & 0xfc) == 0xf8) {
333 if (((utf8[i + 1] & 0xc0) != 0x80) ||
334 ((utf8[i + 2] & 0xc0) != 0x80) ||
335 ((utf8[i + 3] & 0xc0) != 0x80) ||
336 ((utf8[i + 4] & 0xc0) != 0x80))
339 charval = ((SilcUInt32)(utf8[i++] & 0x3)) << 24;
340 charval |= ((SilcUInt32)(utf8[i++] & 0x3f)) << 18;
341 charval |= ((SilcUInt32)(utf8[i++] & 0x3f)) << 12;
342 charval |= (utf8[i++] & 0x3f) << 6;
343 charval |= utf8[i] & 0x3f;
344 if (charval < 0x200000)
346 } else if ((utf8[i] & 0xfe) == 0xfc) {
350 if (((utf8[i + 1] & 0xc0) != 0x80) ||
351 ((utf8[i + 2] & 0xc0) != 0x80) ||
352 ((utf8[i + 3] & 0xc0) != 0x80) ||
353 ((utf8[i + 4] & 0xc0) != 0x80) ||
354 ((utf8[i + 5] & 0xc0) != 0x80))
357 charval = ((SilcUInt32)(utf8[i++] & 0x1)) << 30;
358 charval |= ((SilcUInt32)(utf8[i++] & 0x3f)) << 24;
359 charval |= ((SilcUInt32)(utf8[i++] & 0x3f)) << 18;
360 charval |= ((SilcUInt32)(utf8[i++] & 0x3f)) << 12;
361 charval |= (utf8[i++] & 0x3f) << 6;
362 charval |= utf8[i] & 0x3f;
363 if (charval < 0x4000000)
369 switch (bin_encoding) {
370 case SILC_STRING_ASCII:
372 if (enclen + 1 > bin_size)
375 bin[enclen] = (unsigned char)charval;
379 case SILC_STRING_ASCII_ESC:
382 case SILC_STRING_BMP:
385 case SILC_STRING_UNIVERSAL:
394 /* Returns the length of UTF-8 encoded string if the `bin' of
395 encoding of `bin_encoding' is encoded with silc_utf8_encode. */
397 SilcUInt32 silc_utf8_encoded_len(const unsigned char *bin, SilcUInt32 bin_len,
398 SilcStringEncoding bin_encoding)
400 return silc_utf8_encode(bin, bin_len, bin_encoding, NULL, 0);
403 /* Returns TRUE if the `utf8' string of length of `utf8_len' is valid
404 UTF-8 encoded string, FALSE if it is not UTF-8 encoded string. */
406 bool silc_utf8_valid(const unsigned char *utf8, SilcUInt32 utf8_len)
408 return silc_utf8_decode(utf8, utf8_len, 0, NULL, 0) != 0;