/*
* 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;
}