Blame lib/str-iconv.c

Packit 549fdc
/*
Packit 549fdc
 * Copyright (C) 2010-2016 Free Software Foundation, Inc.
Packit 549fdc
 * Copyright (C) 2015-2016 Red Hat, Inc.
Packit 549fdc
 *
Packit 549fdc
 * Author: Nikos Mavrogiannopoulos
Packit 549fdc
 *
Packit 549fdc
 * This file is part of GnuTLS.
Packit 549fdc
 *
Packit 549fdc
 * The GnuTLS is free software; you can redistribute it and/or
Packit 549fdc
 * modify it under the terms of the GNU Lesser General Public License
Packit 549fdc
 * as published by the Free Software Foundation; either version 2.1 of
Packit 549fdc
 * the License, or (at your option) any later version.
Packit 549fdc
 *
Packit 549fdc
 * This library is distributed in the hope that it will be useful, but
Packit 549fdc
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 549fdc
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 549fdc
 * Lesser General Public License for more details.
Packit 549fdc
 *
Packit 549fdc
 * You should have received a copy of the GNU Lesser General Public License
Packit 549fdc
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
Packit 549fdc
 *
Packit 549fdc
 */
Packit 549fdc
Packit 549fdc
#include <config.h>
Packit 549fdc
#include <system.h>
Packit 549fdc
#include "gnutls_int.h"
Packit 549fdc
#include "errors.h"
Packit 549fdc
Packit 549fdc
#include <sys/socket.h>
Packit 549fdc
#include <errno.h>
Packit 549fdc
#include <sys/stat.h>
Packit 549fdc
#include <sys/types.h>
Packit 549fdc
#include <unistr.h>
Packit 549fdc
#include <uninorm.h>
Packit 549fdc
#include "num.h"
Packit 549fdc
Packit 549fdc
static void change_u16_endianness(uint8_t *dst, const uint8_t *src, unsigned size, unsigned be)
Packit 549fdc
{
Packit 549fdc
	unsigned convert = 0;
Packit 549fdc
	unsigned i;
Packit 549fdc
	uint8_t tmp;
Packit 549fdc
Packit 549fdc
#ifdef WORDS_BIGENDIAN
Packit 549fdc
	if (!be)
Packit 549fdc
		convert = 1;
Packit 549fdc
#else
Packit 549fdc
	if (be)
Packit 549fdc
		convert = 1;
Packit 549fdc
#endif
Packit 549fdc
Packit 549fdc
	/* convert to LE */
Packit 549fdc
	if (convert) {
Packit 549fdc
		for (i = 0; i < size; i += 2) {
Packit 549fdc
			tmp = src[i];
Packit 549fdc
			dst[i] = src[1 + i];
Packit 549fdc
			dst[1 + i] = tmp;
Packit 549fdc
		}
Packit 549fdc
	} else {
Packit 549fdc
		if (dst != src)
Packit 549fdc
			memcpy(dst, src, size);
Packit 549fdc
	}
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
int _gnutls_ucs2_to_utf8(const void *data, size_t size,
Packit 549fdc
			 gnutls_datum_t * output, unsigned be)
Packit 549fdc
{
Packit 549fdc
	int ret;
Packit 549fdc
	size_t dstlen;
Packit 549fdc
	void *src;
Packit 549fdc
	uint8_t *tmp_dst = NULL;
Packit 549fdc
	uint8_t *dst = NULL;
Packit 549fdc
Packit 549fdc
	if (size > 2 && ((uint8_t *) data)[size-1] == 0 && ((uint8_t *) data)[size-2] == 0) {
Packit 549fdc
		size -= 2;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	if (size == 0)
Packit 549fdc
		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
Packit 549fdc
Packit 549fdc
	src = gnutls_malloc(size+2);
Packit 549fdc
	if (src == NULL)
Packit 549fdc
		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
Packit 549fdc
Packit 549fdc
	/* convert to LE if needed */
Packit 549fdc
	change_u16_endianness(src, data, size, be);
Packit 549fdc
Packit 549fdc
	dstlen = 0;
Packit 549fdc
	tmp_dst = u16_to_u8((uint16_t*)src, size/2, NULL, &dstlen);
Packit 549fdc
	if (tmp_dst == NULL) {
Packit 549fdc
		ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
Packit 549fdc
		goto fail;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	dst = gnutls_malloc(dstlen+1);
Packit 549fdc
	if (dst == NULL) {
Packit 549fdc
		gnutls_assert();
Packit 549fdc
		ret = GNUTLS_E_MEMORY_ERROR;
Packit 549fdc
		goto fail;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	memcpy(dst, tmp_dst, dstlen);
Packit 549fdc
	dst[dstlen] = 0;
Packit 549fdc
Packit 549fdc
	output->data = (void *) dst;
Packit 549fdc
	output->size = dstlen;
Packit 549fdc
Packit 549fdc
	ret = 0;
Packit 549fdc
	goto cleanup;
Packit 549fdc
Packit 549fdc
 fail:
Packit 549fdc
	gnutls_free(dst);
Packit 549fdc
Packit 549fdc
 cleanup:
Packit 549fdc
	gnutls_free(src);
Packit 549fdc
	free(tmp_dst);
Packit 549fdc
Packit 549fdc
	return ret;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
/* This is big-endian output only */
Packit 549fdc
int _gnutls_utf8_to_ucs2(const void *data, size_t size,
Packit 549fdc
			 gnutls_datum_t * output)
Packit 549fdc
{
Packit 549fdc
	int ret;
Packit 549fdc
	size_t dstlen, nrm_size = 0, tmp_size = 0;
Packit 549fdc
	uint16_t *tmp_dst = NULL;
Packit 549fdc
	uint16_t *nrm_dst = NULL;
Packit 549fdc
	uint8_t *dst = NULL;
Packit 549fdc
Packit 549fdc
	if (size == 0)
Packit 549fdc
		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
Packit 549fdc
Packit 549fdc
	tmp_dst = u8_to_u16(data, size, NULL, &tmp_size);
Packit 549fdc
	if (tmp_dst == NULL)
Packit 549fdc
		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
Packit 549fdc
Packit 549fdc
	nrm_dst = u16_normalize(UNINORM_NFC, tmp_dst, tmp_size, NULL, &nrm_size);
Packit 549fdc
	if (nrm_dst == NULL) {
Packit 549fdc
		ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
Packit 549fdc
		goto fail;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	dstlen = nrm_size * 2; /* convert to bytes */
Packit 549fdc
Packit 549fdc
	dst = gnutls_malloc(dstlen+2);
Packit 549fdc
	if (dst == NULL) {
Packit 549fdc
		gnutls_assert();
Packit 549fdc
		ret = GNUTLS_E_MEMORY_ERROR;
Packit 549fdc
		goto fail;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	/* convert to BE */
Packit 549fdc
	change_u16_endianness(dst, (uint8_t*)tmp_dst, dstlen, 1);
Packit 549fdc
	dst[dstlen] = 0;
Packit 549fdc
	dst[dstlen+1] = 0;
Packit 549fdc
Packit 549fdc
	output->data = (void *) dst;
Packit 549fdc
	output->size = dstlen;
Packit 549fdc
Packit 549fdc
	ret = 0;
Packit 549fdc
	goto cleanup;
Packit 549fdc
Packit 549fdc
 fail:
Packit 549fdc
	gnutls_free(dst);
Packit 549fdc
Packit 549fdc
 cleanup:
Packit 549fdc
	free(tmp_dst);
Packit 549fdc
	free(nrm_dst);
Packit 549fdc
Packit 549fdc
	return ret;
Packit 549fdc
}
Packit 549fdc