/*
 * PtokaX - hub server for Direct Connect peer to peer network.

 * Copyright (C) 2004-2022  Petr Kozelka, PPK at PtokaX dot org

 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3
 * as published by the Free Software Foundation.

 * This program 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 General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
#include "stdinc.h"
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
#include "TextConverter.h"
#ifdef FLYLINKDC_USE_DB
#if defined(_WITH_SQLITE)
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
#include "ServerManager.h"
#include "SettingManager.h"
#include "UdpDebug.h"
#include "utility.h"
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
TextConverter * TextConverter::m_Ptr = nullptr;
#ifdef _WIN32
static wchar_t wcTempBuf[2048];
#else
#ifndef ICONV_CONST
#if defined(__NetBSD__) || (defined(__sun) && defined(__SVR4))
#define ICONV_CONST const
#else
#define ICONV_CONST
#endif
#endif
#endif
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

TextConverter::TextConverter()
{
#ifndef _WIN32
	if (SettingManager::m_Ptr->m_sTexts[SETTXT_ENCODING] == NULL)
	{
		AppendLog("TextConverter failed to initialize - TextEncoding not set!");
		exit(EXIT_FAILURE);
	}

	m_iconvUtfCheck = iconv_open("utf-8", "utf-8");
	if (m_iconvUtfCheck == (iconv_t) - 1)
	{
		AppendLog("TextConverter iconv_open for m_iconvUtfCheck failed!");
		exit(EXIT_FAILURE);
	}

	m_iconvAsciiToUtf = iconv_open("utf-8//TRANSLIT//IGNORE", SettingManager::m_Ptr->m_sTexts[SETTXT_ENCODING]);
	if (m_iconvAsciiToUtf == (iconv_t) - 1)
	{
		AppendLog("TextConverter iconv_open for m_iconvAsciiToUtf failed!");
		exit(EXIT_FAILURE);
	}
#endif
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

TextConverter::~TextConverter()
{
#ifndef _WIN32
	iconv_close(m_iconvUtfCheck);
	iconv_close(m_iconvAsciiToUtf);
#endif
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

#ifdef _WIN32
bool TextConverter::CheckUtf8Validity(const char * sInput, const uint8_t ui8InputLen, char * /*sOutput*/, const uint8_t /*ui8OutputSize*/)
{
	if (::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, sInput, ui8InputLen, NULL, 0) == 0)
	{
		return false;
#else
bool TextConverter::CheckUtf8Validity(const char * sInput, const uint8_t ui8InputLen, char * sOutput, const uint8_t ui8OutputSize)
{
	const char * sInBuf = sInput;
	size_t szInbufLeft = ui8InputLen;

	char * sOutBuf = sOutput;
	size_t szOutbufLeft = ui8OutputSize - 1;

	size_t szRet = iconv(m_iconvUtfCheck, (ICONV_CONST char**)&sInBuf, &szInbufLeft, &sOutBuf, &szOutbufLeft);
	if (szRet == (size_t) - 1)
	{
		return false;
#endif
	}
	else
	{
		return true;
	}
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

size_t TextConverter::CheckUtf8AndConvert(const char * sInput, const uint8_t ui8InputLen, char * sOutput, const uint8_t ui8OutputSize)
{
#ifdef _WIN32
	if (CheckUtf8Validity(sInput, ui8InputLen, sOutput, ui8OutputSize) == true)
	{
		memcpy(sOutput, sInput, ui8InputLen);
		sOutput[ui8InputLen] = '\0';

		return ui8InputLen;
	}

	int iMtoWRegLen = MultiByteToWideChar(CP_ACP, 0, sInput, ui8InputLen, NULL, 0);
	if (iMtoWRegLen == 0)
	{
		sOutput[0] = '\0';
		return 0;
	}

	wchar_t * wcTemp =  wcTempBuf;
	if (iMtoWRegLen > 2048)
	{
		wcTemp = (wchar_t *)malloc(iMtoWRegLen * sizeof(wchar_t));
		if (wcTemp == NULL)
		{
			sOutput[0] = '\0';
			return 0;
		}
	}

	if (::MultiByteToWideChar(CP_ACP, 0, sInput, ui8InputLen, wcTemp, iMtoWRegLen) == 0)
	{
		if (wcTemp != wcTempBuf)
		{
			free(wcTemp);
		}

		sOutput[0] = '\0';
		return 0;
	}

	int iWtoMRegLen = ::WideCharToMultiByte(CP_UTF8, 0, wcTemp, iMtoWRegLen, NULL, 0, NULL, NULL);
	if (iWtoMRegLen == 0)
	{
		if (wcTemp != wcTempBuf)
		{
			free(wcTemp);
		}
		sOutput[0] = '\0';
		return 0;
	}

	if (iWtoMRegLen > (ui8OutputSize - 1))
	{
		iWtoMRegLen = ::WideCharToMultiByte(CP_UTF8, 0, wcTemp, --iMtoWRegLen, NULL, 0, NULL, NULL);

		while (iWtoMRegLen > (ui8OutputSize - 1) && iMtoWRegLen > 0)
		{
			iWtoMRegLen = ::WideCharToMultiByte(CP_UTF8, 0, wcTemp, --iMtoWRegLen, NULL, 0, NULL, NULL);
		}

		if (iMtoWRegLen == 0)
		{
			if (wcTemp != wcTempBuf)
			{
				free(wcTemp);
			}

			sOutput[0] = '\0';
			return 0;
		}
	}

	if (::WideCharToMultiByte(CP_UTF8, 0, wcTemp, iMtoWRegLen, sOutput, iWtoMRegLen, NULL, NULL) == 0)
	{
		if (wcTemp != wcTempBuf)
		{
			free(wcTemp);
		}

		sOutput[0] = '\0';
		return 0;
	}

	if (wcTemp != wcTempBuf)
	{
		free(wcTemp);
	}

	sOutput[iWtoMRegLen] = '\0';
	return iWtoMRegLen;
#else
	if (CheckUtf8Validity(sInput, ui8InputLen, sOutput, ui8OutputSize) == true)
	{
		sOutput[ui8InputLen] = '\0';
		return ui8InputLen;
	}

	const char * sInBuf = sInput;
	size_t szInbufLeft = ui8InputLen;

	char * sOutBuf = sOutput;
	size_t szOutbufLeft = ui8OutputSize - 1;

	size_t szRet = iconv(m_iconvAsciiToUtf, (ICONV_CONST char**)&sInBuf, &szInbufLeft, &sOutBuf, &szOutbufLeft);
	if (szRet == (size_t) - 1)
	{
		if (errno == E2BIG)
		{
			string sMsg = "[LOG] TextConverter::DoIconv iconv E2BIG for param: " + string(sInput, ui8InputLen);
			UdpDebug::m_Ptr->Broadcast(sMsg.c_str(), sMsg.size());
		}
		else if (errno == EILSEQ)
		{
			string sMsg = "[LOG] TextConverter::DoIconv iconv EILSEQ for param: " + string(sInput, ui8InputLen);
			UdpDebug::m_Ptr->Broadcast(sMsg.c_str(), sMsg.size());
		}
		else if (errno == EINVAL)
		{
			string sMsg = "[LOG] TextConverter::DoIconv iconv EINVAL for param: " + string(sInput, ui8InputLen);
			UdpDebug::m_Ptr->Broadcast(sMsg.c_str(), sMsg.size());
		}
		sOutput[0] = '\0';
		return 0;
	}

	sOutput[(ui8OutputSize - szOutbufLeft) - 1] = '\0';
	return (ui8OutputSize - szOutbufLeft) - 1;
#endif
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
#endif // _WITH_SQLITE
#endif // FLYLINKDC_USE_DB

V1042 This file is marked with copyleft license, which requires you to open the derived source code.