summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2016-08-26 14:48:24 +0200
committerNikos Mavrogiannopoulos <nmav@redhat.com>2016-09-06 14:55:00 +0200
commitcc3b48450d31191ee326a03dd384a29e555d9262 (patch)
treef80de1a207110a4e15717543086140a692466a31
parentfa9d49e99e1cf28b8847901a6d9235d1b4d23e61 (diff)
downloadgnutls-cc3b48450d31191ee326a03dd384a29e555d9262.tar.gz
Added _gnutls_utf8_to_ucs2()
This function allows to convert between UTF8 to UCS2 big-endian.
-rw-r--r--lib/system.h2
-rw-r--r--lib/system/iconv.c152
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