summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2016-11-08 15:24:26 +0100
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2016-11-20 17:31:49 +0100
commit10241198c0e35e59dcb59c8a725639684a7416d3 (patch)
tree60b44f345a454279fc60e82bf0619cadbbf4ec58
parent2d34f67f2c45d259744570042a0fd78739617328 (diff)
downloadgnutls-10241198c0e35e59dcb59c8a725639684a7416d3.tar.gz
Use libunistring when present instead of iconv()
That allows us to rely to a single provider for unicode functionality.
-rw-r--r--configure.ac30
-rw-r--r--lib/gnutls.pc.in2
-rw-r--r--lib/system/iconv.c153
3 files changed, 157 insertions, 28 deletions
diff --git a/configure.ac b/configure.ac
index 1960c5c2bd..121caba477 100644
--- a/configure.ac
+++ b/configure.ac
@@ -293,11 +293,6 @@ AM_CONDITIONAL(HAVE_SECCOMP_TESTS, test "$seccomp_tests" = "yes")
AC_LIB_HAVE_LINKFLAGS(seccomp,, [#include <seccomp.h>
], [seccomp_init(0);])
-AC_LIB_HAVE_LINKFLAGS(unistring,, [#include <uninorm.h>
-], [u8_normalize(0, 0, 0, 0, 0);])
-
-AM_CONDITIONAL(HAVE_LIBUNISTRING, test "$HAVE_LIBUNISTRING" = "yes")
-
# check for libcrypto - used in test programs
AC_LIB_HAVE_LINKFLAGS(crypto,, [#include <openssl/evp.h>
], [EVP_CIPHER_CTX_init(NULL);])
@@ -329,22 +324,32 @@ if test "$ac_cv_func_clock_gettime" != "yes";then
gnutls_needs_librt=yes
fi
+AC_LIB_HAVE_LINKFLAGS(unistring,, [#include <uninorm.h>], [u8_normalize(0, 0, 0, 0, 0);])
+
ac_have_unicode=no
-if test "$ac_cv_func_iconv" != "yes";then
- AC_LIB_HAVE_LINKFLAGS(iconv,, [#include <iconv.h>], [iconv (0, 0, 0, 0, 0);])
- if test "$HAVE_LIBICONV" = "yes";then
- ac_have_unicode=yes
- fi
-else
+if test "$HAVE_LIBUNISTRING" = "yes";then
ac_have_unicode=yes
+ ac_have_unistring=yes
+else
+ if test "$ac_cv_func_iconv" != "yes";then
+ AC_LIB_HAVE_LINKFLAGS(iconv,, [#include <iconv.h>], [iconv (0, 0, 0, 0, 0);])
+ fi
+
+ if test "$ac_cv_func_iconv" = "yes" || test "$HAVE_LIBICONV" = "yes";then
+ ac_have_unicode="partial (iconv)"
+ else
+ ac_have_unicode=no
+ fi
fi
if test "$ac_have_unicode" != "yes";then
if test "$have_win" = "yes";then
- ac_have_unicode=yes
+ ac_have_unicode="partial (winapi)"
fi
fi
+AM_CONDITIONAL(HAVE_LIBUNISTRING, test "$ac_have_unistring" = "yes")
+
dnl Note that g*l_INIT are run after we check for library capabilities,
dnl to prevent issues from caching lib dependencies. See discussion
dnl in https://bugs.gentoo.org/show_bug.cgi?id=494940 and
@@ -496,6 +501,7 @@ else
*** libidn was not found. IDNA support will be disabled.
*** ]])
fi
+
else
with_libidn=no
fi
diff --git a/lib/gnutls.pc.in b/lib/gnutls.pc.in
index f1a41579f7..0372be63a0 100644
--- a/lib/gnutls.pc.in
+++ b/lib/gnutls.pc.in
@@ -19,6 +19,6 @@ Description: Transport Security Layer implementation for the GNU system
URL: http://www.gnutls.org/
Version: @VERSION@
Libs: -L${libdir} -lgnutls
-Libs.private: @LIBZ@ @LIBINTL@ @LIBSOCKET@ @LIBPTHREAD@ @LIBICONV@ @P11_KIT_LIBS@ @LIB_SELECT@ @TSS_LIBS@ @GMP_LIBS@
+Libs.private: @LIBZ@ @LIBINTL@ @LIBSOCKET@ @LIBPTHREAD@ @LIBICONV@ @P11_KIT_LIBS@ @LIB_SELECT@ @TSS_LIBS@ @GMP_LIBS@ @LIBUNISTRING@
@GNUTLS_REQUIRES_PRIVATE@
Cflags: -I${includedir}
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>