diff options
author | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2016-08-26 14:48:24 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2016-09-06 14:55:00 +0200 |
commit | cc3b48450d31191ee326a03dd384a29e555d9262 (patch) | |
tree | f80de1a207110a4e15717543086140a692466a31 | |
parent | fa9d49e99e1cf28b8847901a6d9235d1b4d23e61 (diff) | |
download | gnutls-cc3b48450d31191ee326a03dd384a29e555d9262.tar.gz |
Added _gnutls_utf8_to_ucs2()
This function allows to convert between UTF8 to UCS2 big-endian.
-rw-r--r-- | lib/system.h | 2 | ||||
-rw-r--r-- | lib/system/iconv.c | 152 |
2 files changed, 153 insertions, 1 deletions
diff --git a/lib/system.h b/lib/system.h index 61bb5dc7c5..f16fe43ecc 100644 --- a/lib/system.h +++ b/lib/system.h @@ -110,6 +110,8 @@ inline static void gettime(struct timespec *t) int _gnutls_find_config_path(char *path, size_t max_size); int _gnutls_ucs2_to_utf8(const void *data, size_t size, gnutls_datum_t * output, unsigned bigendian); +int _gnutls_utf8_to_ucs2(const void *data, size_t size, + gnutls_datum_t * output); int gnutls_system_global_init(void); void gnutls_system_global_deinit(void); diff --git a/lib/system/iconv.c b/lib/system/iconv.c index c0e4480d1f..b06a6db346 100644 --- a/lib/system/iconv.c +++ b/lib/system/iconv.c @@ -106,7 +106,7 @@ int _gnutls_ucs2_to_utf8(const void *data, size_t size, } dst[len - 1] = 0; - output->data = dst; + output->data = (uint8_t*)dst; output->size = ret; ret = 0; @@ -120,6 +120,81 @@ int _gnutls_ucs2_to_utf8(const void *data, size_t size, return ret; } +int _gnutls_utf8_to_ucs2(const void *data, size_t size, + gnutls_datum_t * output) +{ + int ret; + unsigned i; + int len = 0; + char *dst = NULL; + static unsigned flags = 0; + static int checked = 0; + uint8_t tmp; + + if (checked == 0) { + /* Not all windows versions support MB_ERR_INVALID_CHARS */ + ret = + MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, + "\xff\xff\xff\xff\xff\xff\x00", -1, NULL, 0); + if (ret > 0) + flags = MB_ERR_INVALID_CHARS; + checked = 1; + } + + if (((uint8_t *) data)[size-1] == 0) { + size --; + } + + ret = + MultiByteToWideChar(CP_UTF8, flags, + data, size, NULL, 0); + if (ret == 0) { + _gnutls_debug_log("WideCharToMultiByte: %d\n", (int)GetLastError()); + ret = gnutls_assert_val(GNUTLS_E_PARSING_ERROR); + goto fail; + } + + /* we got the number of characters needed, allocate some extra + * bytes for more complex encodings */ + len = ret*2; + dst = gnutls_calloc(1, len+2); + if (dst == NULL) { + ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + goto fail; + } + dst[0] = 0; + + ret = + MultiByteToWideChar(CP_UTF8, flags, + data, size, (void*)dst, len/2); + if (ret == 0) { + ret = gnutls_assert_val(GNUTLS_E_PARSING_ERROR); + goto fail; + } + + /* convert to BE */ + for (i = 0; i < (unsigned)len; i += 2) { + tmp = dst[i]; + dst[i] = dst[1 + i]; + dst[1 + i] = tmp; + } + + dst[len] = 0; + dst[len+1] = 0; + + output->data = (uint8_t*)dst; + output->size = len; + + ret = 0; + goto cleanup; + + fail: + gnutls_free(dst); + + cleanup: + return ret; +} + #elif defined(HAVE_ICONV) || defined(HAVE_LIBICONV) #include <iconv.h> @@ -177,6 +252,54 @@ int _gnutls_ucs2_to_utf8(const void *data, size_t size, return ret; } +int _gnutls_utf8_to_ucs2(const void *data, size_t size, + gnutls_datum_t * output) +{ + iconv_t conv; + int ret; + size_t orig, dstlen = size * 4; + char *src = (void *) data; + uint8_t *dst = NULL; + char *pdst; + + if (size == 0) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + conv = iconv_open("UTF-16BE", "UTF-8"); + if (conv == (iconv_t) - 1) + return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + + dst = gnutls_malloc(dstlen+2); + pdst = (char*)dst; + if (dst == NULL) { + ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + goto fail; + } + + orig = dstlen; + ret = iconv(conv, &src, &size, &pdst, &dstlen); + if (ret == -1) { + ret = gnutls_assert_val(GNUTLS_E_PARSING_ERROR); + goto fail; + } + + output->data = (void *) dst; + output->size = orig - dstlen; + output->data[output->size] = 0; + output->data[output->size+1] = 0; + + ret = 0; + goto cleanup; + + fail: + gnutls_free(dst); + + cleanup: + iconv_close(conv); + + return ret; +} + #else /* Can convert only english (ASCII) */ @@ -209,4 +332,31 @@ int _gnutls_ucs2_to_utf8(const void *data, size_t size, return 0; } + +int _gnutls_utf8_to_ucs2(const void *data, size_t size, + gnutls_datum_t * output) +{ + unsigned int i, j; + char *dst; + const char *src = data; + + dst = gnutls_malloc(2*size + 2); + if (dst == NULL) + return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + + for (i = j = 0; i < size; i += 2, j++) { + if (!c_isascii(src[j])) + return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); + + dst[i] = 0; + dst[i+1] = src[j]; + } + + output->data = (void *) dst; + output->size = i; + output->data[output->size] = 0; + output->data[output->size+1] = 0; + + return 0; +} #endif |