X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcutil%2Fsilcstrutil.c;h=de215d60bb6957aa744536acd020efb59922750b;hb=413da0f8686910f5e627393157566ae729ca99c4;hp=d1f04883d69d99818031a839b35feda68cc30f8c;hpb=b3e67d3dfa6409755be33f352b5a86fbb094a570;p=silc.git diff --git a/lib/silcutil/silcstrutil.c b/lib/silcutil/silcstrutil.c index d1f04883..de215d60 100644 --- a/lib/silcutil/silcstrutil.c +++ b/lib/silcutil/silcstrutil.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2002 Pekka Riikonen + Copyright (C) 2002 - 2003 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,8 +25,7 @@ static unsigned char pem_enc[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /* Encodes data into PEM encoding. Returns NULL terminated PEM encoded - data string. Note: This is originally public domain code and is - still PD. */ + data string. */ char *silc_pem_encode(unsigned char *data, SilcUInt32 len) { @@ -102,8 +101,7 @@ char *silc_pem_encode_file(unsigned char *data, SilcUInt32 data_len) return pem2; } -/* Decodes PEM into data. Returns the decoded data. Note: This is - originally public domain code and is still PD. */ +/* Decodes PEM into data. Returns the decoded data. */ unsigned char *silc_pem_decode(unsigned char *pem, SilcUInt32 pem_len, SilcUInt32 *ret_len) @@ -187,16 +185,76 @@ SilcUInt32 silc_utf8_encode(const unsigned char *bin, SilcUInt32 bin_len, if (!bin || !bin_len) return 0; + if (silc_utf8_valid(bin, bin_len) && bin_len <= utf8_size) { + memcpy(utf8, bin, bin_len); + return bin_len; + } + + if (bin_encoding == SILC_STRING_LANGUAGE) { +#if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) && defined(CODESET) + char *fromconv, *icp, *ocp; + iconv_t icd; + size_t inlen, outlen; + + setlocale(LC_CTYPE, ""); + fromconv = nl_langinfo(CODESET); + if (fromconv && strlen(fromconv)) { + icd = iconv_open("UTF-8", fromconv); + icp = (char *)bin; + ocp = (char *)utf8; + inlen = bin_len; + outlen = utf8_size; + if (icp && ocp && icd != (iconv_t)-1) { + if (iconv(icd, &icp, &inlen, &ocp, &outlen) != -1) { + utf8_size -= outlen; + iconv_close(icd); + return utf8_size; + } + } + if (icd != (iconv_t)-1) + iconv_close(icd); + } +#endif + + /* Fallback to 8-bit ASCII */ + bin_encoding = SILC_STRING_ASCII; + } + for (i = 0; i < bin_len; i++) { switch (bin_encoding) { case SILC_STRING_ASCII: charval = bin[i]; break; case SILC_STRING_ASCII_ESC: + SILC_NOT_IMPLEMENTED("SILC_STRING_ASCII_ESC"); + return 0; break; case SILC_STRING_BMP: + if (i + 1 >= bin_len) + return 0; + SILC_GET16_MSB(charval, bin + i); + i += 1; + break; + case SILC_STRING_BMP_LSB: + if (i + 1 >= bin_len) + return 0; + SILC_GET16_LSB(charval, bin + i); + i += 1; break; case SILC_STRING_UNIVERSAL: + if (i + 3 >= bin_len) + return 0; + SILC_GET32_MSB(charval, bin + i); + i += 3; + break; + case SILC_STRING_UNIVERSAL_LSB: + if (i + 3 >= bin_len) + return 0; + SILC_GET32_LSB(charval, bin + i); + i += 3; + break; + default: + return 0; break; } @@ -285,12 +343,42 @@ SilcUInt32 silc_utf8_decode(const unsigned char *utf8, SilcUInt32 utf8_len, if (!utf8 || !utf8_len) return 0; + if (bin_encoding == SILC_STRING_LANGUAGE) { +#if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) && defined(CODESET) + char *toconv, *icp, *ocp; + iconv_t icd; + size_t inlen, outlen; + + setlocale(LC_CTYPE, ""); + toconv = nl_langinfo(CODESET); + if (toconv && strlen(toconv)) { + icd = iconv_open(toconv, "UTF-8"); + icp = (char *)utf8; + ocp = (char *)bin; + inlen = utf8_len; + outlen = bin_size; + if (icp && ocp && icd != (iconv_t)-1) { + if (iconv(icd, &icp, &inlen, &ocp, &outlen) != -1) { + bin_size -= outlen; + iconv_close(icd); + return bin_size; + } + } + if (icd != (iconv_t)-1) + iconv_close(icd); + } +#endif + + /* Fallback to 8-bit ASCII */ + bin_encoding = SILC_STRING_ASCII; + } + for (i = 0; i < utf8_len; i++) { if ((utf8[i] & 0x80) == 0x00) { charval = utf8[i] & 0x7f; } else if ((utf8[i] & 0xe0) == 0xc0) { - if (utf8_len < 2) - return 0; + if (i + 1 >= utf8_len) + return 0; if ((utf8[i + 1] & 0xc0) != 0x80) return 0; @@ -300,8 +388,8 @@ SilcUInt32 silc_utf8_decode(const unsigned char *utf8, SilcUInt32 utf8_len, if (charval < 0x80) return 0; } else if ((utf8[i] & 0xf0) == 0xe0) { - if (utf8_len < 3) - return 0; + if (i + 2 >= utf8_len) + return 0; if (((utf8[i + 1] & 0xc0) != 0x80) || ((utf8[i + 2] & 0xc0) != 0x80)) @@ -313,8 +401,8 @@ SilcUInt32 silc_utf8_decode(const unsigned char *utf8, SilcUInt32 utf8_len, if (charval < 0x800) return 0; } else if ((utf8[i] & 0xf8) == 0xf0) { - if (utf8_len < 4) - return 0; + if (i + 3 >= utf8_len) + return 0; if (((utf8[i + 1] & 0xc0) != 0x80) || ((utf8[i + 2] & 0xc0) != 0x80) || @@ -328,8 +416,8 @@ SilcUInt32 silc_utf8_decode(const unsigned char *utf8, SilcUInt32 utf8_len, if (charval < 0x10000) return 0; } else if ((utf8[i] & 0xfc) == 0xf8) { - if (utf8_len < 5) - return 0; + if (i + 4 >= utf8_len) + return 0; if (((utf8[i + 1] & 0xc0) != 0x80) || ((utf8[i + 2] & 0xc0) != 0x80) || @@ -345,8 +433,8 @@ SilcUInt32 silc_utf8_decode(const unsigned char *utf8, SilcUInt32 utf8_len, if (charval < 0x200000) return 0; } else if ((utf8[i] & 0xfe) == 0xfc) { - if (utf8_len < 6) - return 0; + if (i + 5 >= utf8_len) + return 0; if (((utf8[i + 1] & 0xc0) != 0x80) || ((utf8[i + 2] & 0xc0) != 0x80) || @@ -378,12 +466,30 @@ SilcUInt32 silc_utf8_decode(const unsigned char *utf8, SilcUInt32 utf8_len, enclen++; break; case SILC_STRING_ASCII_ESC: + SILC_NOT_IMPLEMENTED("SILC_STRING_ASCII_ESC"); return 0; break; case SILC_STRING_BMP: - return 0; + if (bin) + SILC_PUT16_MSB(charval, bin + enclen); + enclen += 2; + break; + case SILC_STRING_BMP_LSB: + if (bin) + SILC_PUT16_LSB(charval, bin + enclen); + enclen += 2; break; case SILC_STRING_UNIVERSAL: + if (bin) + SILC_PUT32_MSB(charval, bin + enclen); + enclen += 4; + break; + case SILC_STRING_UNIVERSAL_LSB: + if (bin) + SILC_PUT32_LSB(charval, bin + enclen); + enclen += 4; + break; + default: return 0; break; } @@ -401,6 +507,15 @@ SilcUInt32 silc_utf8_encoded_len(const unsigned char *bin, SilcUInt32 bin_len, return silc_utf8_encode(bin, bin_len, bin_encoding, NULL, 0); } +/* Returns the length of decoded string if the `bin' of encoding of + `bin_encoding' is decoded with silc_utf8_decode. */ + +SilcUInt32 silc_utf8_decoded_len(const unsigned char *bin, SilcUInt32 bin_len, + SilcStringEncoding bin_encoding) +{ + return silc_utf8_decode(bin, bin_len, bin_encoding, NULL, 0); +} + /* Returns TRUE if the `utf8' string of length of `utf8_len' is valid UTF-8 encoded string, FALSE if it is not UTF-8 encoded string. */ @@ -408,3 +523,97 @@ bool silc_utf8_valid(const unsigned char *utf8, SilcUInt32 utf8_len) { return silc_utf8_decode(utf8, utf8_len, 0, NULL, 0) != 0; } + +/* Mime constants and macros */ +#define MIME_VERSION "MIME-Version: " +#define MIME_VERSION_LEN 14 +#define MIME_CONTENT_TYPE "Content-Type: " +#define MIME_CONTENT_TYPE_LEN 14 +#define MIME_TRANSFER_ENCODING "Content-Transfer-Encoding: " +#define MIME_TRANSFER_ENCODING_LEN 27 + +#define MIME_GET_FIELD(header, mime, mime_len, field, field_len, \ + dest, dest_size) \ +do { \ + if (dest) { \ + char *f = strstr(header, field); \ + if (f) { \ + f = (char *)mime + (f - header) + field_len; \ + for (i = 0; i < (mime_len - (f - (char *)mime)); i++) { \ + if (f[i] == '\r' || f[i] == '\n' || i == dest_size) \ + break; \ + dest[i] = f[i]; \ + } \ + } \ + } \ +} while(0) + +/* Parses MIME object and MIME header in it. */ + +bool +silc_mime_parse(const unsigned char *mime, SilcUInt32 mime_len, + char *version, SilcUInt32 version_size, + char *content_type, SilcUInt32 content_type_size, + char *transfer_encoding, SilcUInt32 transfer_encoding_size, + unsigned char **mime_data_ptr, SilcUInt32 *mime_data_len) +{ + int i; + char header[256]; + + memcpy(header, mime, 256 > mime_len ? mime_len : 256); + header[sizeof(header) - 1] = '\0'; + + /* Check for mandatory Content-Type field */ + if (!strstr(header, MIME_CONTENT_TYPE)) + return FALSE; + + /* Get the pointer to the data area in the object */ + for (i = 0; i < mime_len; i++) { + if (mime_len >= i + 4 && + mime[i ] == '\r' && mime[i + 1] == '\n' && + mime[i + 2] == '\r' && mime[i + 3] == '\n') + break; + } + if (i >= mime_len) + return FALSE; + + if (mime_data_ptr) + *mime_data_ptr = (unsigned char *)mime + i + 4; + if (mime_data_len) + *mime_data_len = mime_len - ((mime + i + 4) - mime); + + /* Get MIME version, Content-Type and Transfer Encoding fields */ + MIME_GET_FIELD(header, mime, mime_len, + MIME_VERSION, MIME_VERSION_LEN, + version, version_size); + MIME_GET_FIELD(header, mime, mime_len, + MIME_CONTENT_TYPE, MIME_CONTENT_TYPE_LEN, + content_type, content_type_size); + MIME_GET_FIELD(header, mime, mime_len, + MIME_TRANSFER_ENCODING, MIME_TRANSFER_ENCODING_LEN, + transfer_encoding, transfer_encoding_size); + + return TRUE; +} + +/* Concatenates the `src' into `dest'. If `src_len' is more than the + size of the `dest' (minus NULL at the end) the `src' will be + truncated to fit. */ + +char *silc_strncat(char *dest, SilcUInt32 dest_size, + const char *src, SilcUInt32 src_len) +{ + int len; + + dest[dest_size - 1] = '\0'; + + len = dest_size - 1 - strlen(dest); + if (len < src_len) { + if (len > 0) + strncat(dest, src, len); + } else { + strncat(dest, src, src_len); + } + + return dest; +}