summaryrefslogtreecommitdiff
path: root/lib/system/iconv.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/system/iconv.c')
-rw-r--r--lib/system/iconv.c153
1 files changed, 138 insertions, 15 deletions
diff --git a/lib/system/iconv.c b/lib/system/iconv.c
index c133ea382e..9e5a905e72 100644
--- a/lib/system/iconv.c
+++ b/lib/system/iconv.c
@@ -31,6 +31,33 @@
#include <sys/types.h>
#include <c-ctype.h>
+static void change_u16_endianness(uint8_t *dst, const uint8_t *src, unsigned size, unsigned be)
+{
+ unsigned convert = 0;
+ unsigned i;
+ uint8_t tmp;
+
+#ifdef WORDS_BIGENDIAN
+ if (!be)
+ convert = 1;
+#else
+ if (be)
+ convert = 1;
+#endif
+
+ /* convert to LE */
+ if (convert) {
+ for (i = 0; i < size; i += 2) {
+ tmp = src[i];
+ dst[i] = src[1 + i];
+ dst[1 + i] = tmp;
+ }
+ } else {
+ if (dst != src)
+ memcpy(dst, src, size);
+ }
+}
+
#if defined(_WIN32)
#include <windows.h>
#include <winnls.h>
@@ -64,15 +91,8 @@ int _gnutls_ucs2_to_utf8(const void *data, size_t size,
if (src == NULL)
return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
- /* convert to LE */
- if (be) {
- for (i = 0; i < size; i += 2) {
- src[i] = ((uint8_t *) data)[1 + i];
- src[1 + i] = ((uint8_t *) data)[i];
- }
- } else {
- memcpy(src, data, size);
- }
+ /* convert to LE if needed */
+ change_u16_endianness(src, data, size, be);
src[size] = 0;
src[size+1] = 0;
@@ -173,12 +193,8 @@ int _gnutls_utf8_to_ucs2(const void *data, size_t size,
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;
- }
+ /* convert to BE if needed */
+ change_u16_endianness(dst, dst, len, 1);
dst[len] = 0;
dst[len+1] = 0;
@@ -196,6 +212,113 @@ int _gnutls_utf8_to_ucs2(const void *data, size_t size,
return ret;
}
+#elif defined(HAVE_LIBUNISTRING)
+
+#include <unistr.h>
+#include "num.h"
+
+int _gnutls_ucs2_to_utf8(const void *data, size_t size,
+ gnutls_datum_t * output, unsigned be)
+{
+ int ret;
+ size_t dstlen;
+ uint8_t *src;
+ uint8_t *tmp_dst = NULL;
+ uint8_t *dst = NULL;
+
+ if (size > 2 && ((uint8_t *) data)[size-1] == 0 && ((uint8_t *) data)[size-2] == 0) {
+ size -= 2;
+ }
+
+ if (size == 0)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ src = gnutls_malloc(size+2);
+ if (src == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ /* convert to LE if needed */
+ change_u16_endianness(src, data, size, be);
+
+ dstlen = 0;
+ tmp_dst = u16_to_u8((uint16_t*)src, size/2, NULL, &dstlen);
+ if (tmp_dst == NULL) {
+ ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+ goto fail;
+ }
+
+ dst = gnutls_malloc(dstlen+1);
+ if (dst == NULL) {
+ gnutls_assert();
+ ret = GNUTLS_E_MEMORY_ERROR;
+ goto fail;
+ }
+
+ memcpy(dst, tmp_dst, dstlen);
+ dst[dstlen] = 0;
+
+ output->data = (void *) dst;
+ output->size = dstlen;
+
+ ret = 0;
+ goto cleanup;
+
+ fail:
+ gnutls_free(dst);
+
+ cleanup:
+ gnutls_free(src);
+ free(tmp_dst);
+
+ return ret;
+}
+
+/* This is big-endian output only */
+int _gnutls_utf8_to_ucs2(const void *data, size_t size,
+ gnutls_datum_t * output)
+{
+ int ret;
+ size_t dstlen = 0;
+ uint16_t *tmp_dst = NULL;
+ uint8_t *dst = NULL;
+
+ if (size == 0)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ dstlen = 0;
+ tmp_dst = u8_to_u16(data, size, NULL, &dstlen);
+ if (tmp_dst == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ dstlen *= 2; /* convert to bytes */
+
+ dst = gnutls_malloc(dstlen+2);
+ if (dst == NULL) {
+ gnutls_assert();
+ ret = GNUTLS_E_MEMORY_ERROR;
+ goto fail;
+ }
+
+ /* convert to BE if needed */
+ change_u16_endianness(dst, (uint8_t*)tmp_dst, dstlen, 1);
+ dst[dstlen] = 0;
+ dst[dstlen+1] = 0;
+
+ output->data = (void *) dst;
+ output->size = dstlen;
+
+ ret = 0;
+ goto cleanup;
+
+ fail:
+ gnutls_free(dst);
+
+ cleanup:
+ free(tmp_dst);
+
+ return ret;
+}
+
#elif defined(HAVE_ICONV) || defined(HAVE_LIBICONV)
#include <iconv.h>