/* * Copyright (C) 2010-2016 Free Software Foundation, Inc. * Copyright (C) 2015-2016 Red Hat, Inc. * * Author: Nikos Mavrogiannopoulos * * This file is part of GnuTLS. * * The GnuTLS is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see * */ #include #include #include "gnutls_int.h" #include "errors.h" #include #include #include #include #include #include #include "num.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); } } int _gnutls_ucs2_to_utf8(const void *data, size_t size, gnutls_datum_t * output, unsigned be) { int ret; size_t dstlen; void *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; } int _gnutls_utf8_to_ucs2(const void *data, size_t size, gnutls_datum_t * output, unsigned be) { int ret; size_t dstlen, nrm_size = 0, tmp_size = 0; uint16_t *tmp_dst = NULL; uint16_t *nrm_dst = NULL; uint8_t *dst = NULL; if (size == 0) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); tmp_dst = u8_to_u16(data, size, NULL, &tmp_size); if (tmp_dst == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); nrm_dst = u16_normalize(UNINORM_NFC, tmp_dst, tmp_size, NULL, &nrm_size); if (nrm_dst == NULL) { ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); goto fail; } dstlen = nrm_size * 2; /* convert to bytes */ dst = gnutls_malloc(dstlen+2); if (dst == NULL) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto fail; } /* convert to BE */ change_u16_endianness(dst, (uint8_t*)tmp_dst, dstlen, be); 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); free(nrm_dst); return ret; }