Blame winpr/libwinpr/crt/unicode.c

Packit Service fa4841
/**
Packit Service fa4841
 * WinPR: Windows Portable Runtime
Packit Service fa4841
 * Unicode Conversion (CRT)
Packit Service fa4841
 *
Packit Service fa4841
 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit Service fa4841
 *
Packit Service fa4841
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit Service fa4841
 * you may not use this file except in compliance with the License.
Packit Service fa4841
 * You may obtain a copy of the License at
Packit Service fa4841
 *
Packit Service fa4841
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit Service fa4841
 *
Packit Service fa4841
 * Unless required by applicable law or agreed to in writing, software
Packit Service fa4841
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit Service fa4841
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit Service fa4841
 * See the License for the specific language governing permissions and
Packit Service fa4841
 * limitations under the License.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
#ifdef HAVE_CONFIG_H
Packit Service fa4841
#include "config.h"
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
#include <errno.h>
Packit Service fa4841
#include <wctype.h>
Packit Service fa4841
Packit Service fa4841
#include <winpr/crt.h>
Packit Service fa4841
#include <winpr/error.h>
Packit Service fa4841
#include <winpr/print.h>
Packit Service fa4841
Packit Service fa4841
#ifndef _WIN32
Packit Service fa4841
Packit Service fa4841
#if defined(WITH_ICU)
Packit Service fa4841
#include <unicode/ucnv.h>
Packit Service fa4841
#include <unicode/ustring.h>
Packit Service fa4841
#else
Packit Service fa4841
#include "utf.h"
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
#include "../log.h"
Packit Service fa4841
#define TAG WINPR_TAG("unicode")
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Notes on cross-platform Unicode portability:
Packit Service fa4841
 *
Packit Service fa4841
 * Unicode has many possible Unicode Transformation Format (UTF) encodings,
Packit Service fa4841
 * where some of the most commonly used are UTF-8, UTF-16 and sometimes UTF-32.
Packit Service fa4841
 *
Packit Service fa4841
 * The number in the UTF encoding name (8, 16, 32) refers to the number of bits
Packit Service fa4841
 * per code unit. A code unit is the minimal bit combination that can represent
Packit Service fa4841
 * a unit of encoded text in the given encoding. For instance, UTF-8 encodes
Packit Service fa4841
 * the English alphabet using 8 bits (or one byte) each, just like in ASCII.
Packit Service fa4841
 *
Packit Service fa4841
 * However, the total number of code points (values in the Unicode codespace)
Packit Service fa4841
 * only fits completely within 32 bits. This means that for UTF-8 and UTF-16,
Packit Service fa4841
 * more than one code unit may be required to fully encode a specific value.
Packit Service fa4841
 * UTF-8 and UTF-16 are variable-width encodings, while UTF-32 is fixed-width.
Packit Service fa4841
 *
Packit Service fa4841
 * UTF-8 has the advantage of being backwards compatible with ASCII, and is
Packit Service fa4841
 * one of the most commonly used Unicode encoding.
Packit Service fa4841
 *
Packit Service fa4841
 * UTF-16 is used everywhere in the Windows API. The strategy employed by
Packit Service fa4841
 * Microsoft to provide backwards compatibility in their API was to create
Packit Service fa4841
 * an ANSI and a Unicode version of the same function, ending with A (ANSI)
Packit Service fa4841
 * and W (Wide character, or UTF-16 Unicode). In headers, the original
Packit Service fa4841
 * function name is replaced by a macro that defines to either the ANSI
Packit Service fa4841
 * or Unicode version based on the definition of the _UNICODE macro.
Packit Service fa4841
 *
Packit Service fa4841
 * UTF-32 has the advantage of being fixed width, but wastes a lot of space
Packit Service fa4841
 * for English text (4x more than UTF-8, 2x more than UTF-16).
Packit Service fa4841
 *
Packit Service fa4841
 * In C, wide character strings are often defined with the wchar_t type.
Packit Service fa4841
 * Many functions are provided to deal with those wide character strings,
Packit Service fa4841
 * such as wcslen (strlen equivalent) or wprintf (printf equivalent).
Packit Service fa4841
 *
Packit Service fa4841
 * This may lead to some confusion, since many of these functions exist
Packit Service fa4841
 * on both Windows and Linux, but they are *not* the same!
Packit Service fa4841
 *
Packit Service fa4841
 * This sample hello world is a good example:
Packit Service fa4841
 *
Packit Service fa4841
 * #include <wchar.h>
Packit Service fa4841
 *
Packit Service fa4841
 * wchar_t hello[] = L"Hello, World!\n";
Packit Service fa4841
 *
Packit Service fa4841
 * int main(int argc, char** argv)
Packit Service fa4841
 * {
Packit Service fa4841
 * 	wprintf(hello);
Packit Service fa4841
 * 	wprintf(L"sizeof(wchar_t): %d\n", sizeof(wchar_t));
Packit Service fa4841
 * 	return 0;
Packit Service fa4841
 * }
Packit Service fa4841
 *
Packit Service fa4841
 * There is a reason why the sample prints the size of the wchar_t type:
Packit Service fa4841
 * On Windows, wchar_t is two bytes (UTF-16), while on most other systems
Packit Service fa4841
 * it is 4 bytes (UTF-32). This means that if you write code on Windows,
Packit Service fa4841
 * use L"" to define a string which is meant to be UTF-16 and not UTF-32,
Packit Service fa4841
 * you will have a little surprise when trying to port your code to Linux.
Packit Service fa4841
 *
Packit Service fa4841
 * Since the Windows API uses UTF-16, not UTF-32, WinPR defines the WCHAR
Packit Service fa4841
 * type to always be 2-bytes long and uses it instead of wchar_t. Do not
Packit Service fa4841
 * ever use wchar_t with WinPR unless you know what you are doing.
Packit Service fa4841
 *
Packit Service fa4841
 * As for L"", it is unfortunately unusable in a portable way, unless a
Packit Service fa4841
 * special option is passed to GCC to define wchar_t as being two bytes.
Packit Service fa4841
 * For string constants that must be UTF-16, it is a pain, but they can
Packit Service fa4841
 * be defined in a portable way like this:
Packit Service fa4841
 *
Packit Service fa4841
 * WCHAR hello[] = { 'H','e','l','l','o','\0' };
Packit Service fa4841
 *
Packit Service fa4841
 * Such strings cannot be passed to native functions like wcslen(), which
Packit Service fa4841
 * may expect a different wchar_t size. For this reason, WinPR provides
Packit Service fa4841
 * _wcslen, which expects UTF-16 WCHAR strings on all platforms.
Packit Service fa4841
 *
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
/*
Packit Service fa4841
 * Conversion to Unicode (UTF-16)
Packit Service fa4841
 * MultiByteToWideChar: http://msdn.microsoft.com/en-us/library/windows/desktop/dd319072/
Packit Service fa4841
 *
Packit Service fa4841
 * cbMultiByte is an input size in bytes (BYTE)
Packit Service fa4841
 * cchWideChar is an output size in wide characters (WCHAR)
Packit Service fa4841
 *
Packit Service fa4841
 * Null-terminated UTF-8 strings:
Packit Service fa4841
 *
Packit Service fa4841
 * cchWideChar *cannot* be assumed to be cbMultiByte since UTF-8 is variable-width!
Packit Service fa4841
 *
Packit Service fa4841
 * Instead, obtain the required cchWideChar output size like this:
Packit Service fa4841
 * cchWideChar = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR) lpMultiByteStr, -1, NULL, 0);
Packit Service fa4841
 *
Packit Service fa4841
 * A value of -1 for cbMultiByte indicates that the input string is null-terminated,
Packit Service fa4841
 * and the null terminator *will* be processed. The size returned by MultiByteToWideChar
Packit Service fa4841
 * will therefore include the null terminator. Equivalent behavior can be obtained by
Packit Service fa4841
 * computing the length in bytes of the input buffer, including the null terminator:
Packit Service fa4841
 *
Packit Service fa4841
 * cbMultiByte = strlen((char*) lpMultiByteStr) + 1;
Packit Service fa4841
 *
Packit Service fa4841
 * An output buffer of the proper size can then be allocated:
Packit Service fa4841
 *
Packit Service fa4841
 * lpWideCharStr = (LPWSTR) malloc(cchWideChar * sizeof(WCHAR));
Packit Service fa4841
 *
Packit Service fa4841
 * Since cchWideChar is an output size in wide characters, the actual buffer size is:
Packit Service fa4841
 * (cchWideChar * sizeof(WCHAR)) or (cchWideChar * 2)
Packit Service fa4841
 *
Packit Service fa4841
 * Finally, perform the conversion:
Packit Service fa4841
 *
Packit Service fa4841
 * cchWideChar = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR) lpMultiByteStr, -1, lpWideCharStr,
Packit Service fa4841
 * cchWideChar);
Packit Service fa4841
 *
Packit Service fa4841
 * The value returned by MultiByteToWideChar corresponds to the number of wide characters written
Packit Service fa4841
 * to the output buffer, and should match the value obtained on the first call to
Packit Service fa4841
 * MultiByteToWideChar.
Packit Service fa4841
 *
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
int MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte,
Packit Service fa4841
                        LPWSTR lpWideCharStr, int cchWideChar)
Packit Service fa4841
{
Packit Service fa4841
	LPWSTR targetStart;
Packit Service fa4841
#if !defined(WITH_ICU)
Packit Service fa4841
	const BYTE* sourceStart;
Packit Service fa4841
	int length;
Packit Service fa4841
	ConversionResult result;
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
	/* If cbMultiByte is 0, the function fails */
Packit Service fa4841
Packit Service fa4841
	if ((cbMultiByte == 0) || (cbMultiByte < -1))
Packit Service fa4841
		return 0;
Packit Service fa4841
Packit Service fa4841
	/* If cbMultiByte is -1, the string is null-terminated */
Packit Service fa4841
Packit Service fa4841
	if (cbMultiByte == -1)
Packit Service fa4841
	{
Packit Service fa4841
		size_t len = strnlen((const char*)lpMultiByteStr, INT32_MAX);
Packit Service fa4841
		if (len >= INT32_MAX)
Packit Service fa4841
			return 0;
Packit Service fa4841
		cbMultiByte = (int)len + 1;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	/*
Packit Service fa4841
	 * if cchWideChar is 0, the function returns the required buffer size
Packit Service fa4841
	 * in characters for lpWideCharStr and makes no use of the output parameter itself.
Packit Service fa4841
	 */
Packit Service fa4841
#if defined(WITH_ICU)
Packit Service fa4841
	{
Packit Service fa4841
		UErrorCode error;
Packit Service fa4841
		int32_t targetLength;
Packit Service fa4841
		int32_t targetCapacity;
Packit Service fa4841
Packit Service fa4841
		switch (CodePage)
Packit Service fa4841
		{
Packit Service fa4841
			case CP_ACP:
Packit Service fa4841
			case CP_UTF8:
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			default:
Packit Service fa4841
				WLog_ERR(TAG, "Unsupported encoding %u", CodePage);
Packit Service fa4841
				return 0;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		targetStart = lpWideCharStr;
Packit Service fa4841
		targetCapacity = cchWideChar;
Packit Service fa4841
		error = U_ZERO_ERROR;
Packit Service fa4841
Packit Service fa4841
		if (cchWideChar == 0)
Packit Service fa4841
		{
Packit Service fa4841
			u_strFromUTF8(NULL, 0, &targetLength, lpMultiByteStr, cbMultiByte, &error);
Packit Service fa4841
			cchWideChar = targetLength;
Packit Service fa4841
		}
Packit Service fa4841
		else
Packit Service fa4841
		{
Packit Service fa4841
			u_strFromUTF8(targetStart, targetCapacity, &targetLength, lpMultiByteStr, cbMultiByte,
Packit Service fa4841
			              &error);
Packit Service fa4841
			cchWideChar = U_SUCCESS(error) ? targetLength : 0;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
#else
Packit Service fa4841
Packit Service fa4841
	if (cchWideChar == 0)
Packit Service fa4841
	{
Packit Service fa4841
		sourceStart = (const BYTE*)lpMultiByteStr;
Packit Service fa4841
		targetStart = (WCHAR*)NULL;
Packit Service fa4841
		result = ConvertUTF8toUTF16(&sourceStart, &sourceStart[cbMultiByte], &targetStart, NULL,
Packit Service fa4841
		                            strictConversion);
Packit Service fa4841
		length = targetStart - ((WCHAR*)NULL);
Packit Service fa4841
	}
Packit Service fa4841
	else
Packit Service fa4841
	{
Packit Service fa4841
		sourceStart = (const BYTE*)lpMultiByteStr;
Packit Service fa4841
		targetStart = lpWideCharStr;
Packit Service fa4841
		result = ConvertUTF8toUTF16(&sourceStart, &sourceStart[cbMultiByte], &targetStart,
Packit Service fa4841
		                            &targetStart[cchWideChar], strictConversion);
Packit Service fa4841
		length = targetStart - ((WCHAR*)lpWideCharStr);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	cchWideChar = (result == conversionOK) ? length : 0;
Packit Service fa4841
#endif
Packit Service fa4841
	return cchWideChar;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/*
Packit Service fa4841
 * Conversion from Unicode (UTF-16)
Packit Service fa4841
 * WideCharToMultiByte: http://msdn.microsoft.com/en-us/library/windows/desktop/dd374130/
Packit Service fa4841
 *
Packit Service fa4841
 * cchWideChar is an input size in wide characters (WCHAR)
Packit Service fa4841
 * cbMultiByte is an output size in bytes (BYTE)
Packit Service fa4841
 *
Packit Service fa4841
 * Null-terminated UTF-16 strings:
Packit Service fa4841
 *
Packit Service fa4841
 * cbMultiByte *cannot* be assumed to be cchWideChar since UTF-8 is variable-width!
Packit Service fa4841
 *
Packit Service fa4841
 * Instead, obtain the required cbMultiByte output size like this:
Packit Service fa4841
 * cbMultiByte = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR) lpWideCharStr, -1, NULL, 0, NULL, NULL);
Packit Service fa4841
 *
Packit Service fa4841
 * A value of -1 for cbMultiByte indicates that the input string is null-terminated,
Packit Service fa4841
 * and the null terminator *will* be processed. The size returned by WideCharToMultiByte
Packit Service fa4841
 * will therefore include the null terminator. Equivalent behavior can be obtained by
Packit Service fa4841
 * computing the length in bytes of the input buffer, including the null terminator:
Packit Service fa4841
 *
Packit Service fa4841
 * cchWideChar = _wcslen((WCHAR*) lpWideCharStr) + 1;
Packit Service fa4841
 *
Packit Service fa4841
 * An output buffer of the proper size can then be allocated:
Packit Service fa4841
 * lpMultiByteStr = (LPSTR) malloc(cbMultiByte);
Packit Service fa4841
 *
Packit Service fa4841
 * Since cbMultiByte is an output size in bytes, it is the same as the buffer size
Packit Service fa4841
 *
Packit Service fa4841
 * Finally, perform the conversion:
Packit Service fa4841
 *
Packit Service fa4841
 * cbMultiByte = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR) lpWideCharStr, -1, lpMultiByteStr,
Packit Service fa4841
 * cbMultiByte, NULL, NULL);
Packit Service fa4841
 *
Packit Service fa4841
 * The value returned by WideCharToMultiByte corresponds to the number of bytes written
Packit Service fa4841
 * to the output buffer, and should match the value obtained on the first call to
Packit Service fa4841
 * WideCharToMultiByte.
Packit Service fa4841
 *
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
int WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar,
Packit Service fa4841
                        LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar,
Packit Service fa4841
                        LPBOOL lpUsedDefaultChar)
Packit Service fa4841
{
Packit Service fa4841
#if !defined(WITH_ICU)
Packit Service fa4841
	int length;
Packit Service fa4841
	const WCHAR* sourceStart;
Packit Service fa4841
	ConversionResult result;
Packit Service fa4841
	BYTE* targetStart;
Packit Service fa4841
#else
Packit Service fa4841
	char* targetStart;
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
	/* If cchWideChar is 0, the function fails */
Packit Service fa4841
Packit Service fa4841
	if ((cchWideChar == 0) || (cchWideChar < -1))
Packit Service fa4841
		return 0;
Packit Service fa4841
Packit Service fa4841
	/* If cchWideChar is -1, the string is null-terminated */
Packit Service fa4841
Packit Service fa4841
	if (cchWideChar == -1)
Packit Service fa4841
	{
Packit Service fa4841
		size_t len = _wcslen(lpWideCharStr);
Packit Service fa4841
		if (len >= INT32_MAX)
Packit Service fa4841
			return 0;
Packit Service fa4841
		cchWideChar = (int)len + 1;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	/*
Packit Service fa4841
	 * if cbMultiByte is 0, the function returns the required buffer size
Packit Service fa4841
	 * in bytes for lpMultiByteStr and makes no use of the output parameter itself.
Packit Service fa4841
	 */
Packit Service fa4841
#if defined(WITH_ICU)
Packit Service fa4841
	{
Packit Service fa4841
		UErrorCode error;
Packit Service fa4841
		int32_t targetLength;
Packit Service fa4841
		int32_t targetCapacity;
Packit Service fa4841
Packit Service fa4841
		switch (CodePage)
Packit Service fa4841
		{
Packit Service fa4841
			case CP_ACP:
Packit Service fa4841
			case CP_UTF8:
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			default:
Packit Service fa4841
				WLog_ERR(TAG, "Unsupported encoding %u", CodePage);
Packit Service fa4841
				return 0;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		targetStart = lpMultiByteStr;
Packit Service fa4841
		targetCapacity = cbMultiByte;
Packit Service fa4841
		error = U_ZERO_ERROR;
Packit Service fa4841
Packit Service fa4841
		if (cbMultiByte == 0)
Packit Service fa4841
		{
Packit Service fa4841
			u_strToUTF8(NULL, 0, &targetLength, lpWideCharStr, cchWideChar, &error);
Packit Service fa4841
			cbMultiByte = targetLength;
Packit Service fa4841
		}
Packit Service fa4841
		else
Packit Service fa4841
		{
Packit Service fa4841
			u_strToUTF8(targetStart, targetCapacity, &targetLength, lpWideCharStr, cchWideChar,
Packit Service fa4841
			            &error);
Packit Service fa4841
			cbMultiByte = U_SUCCESS(error) ? targetLength : 0;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
#else
Packit Service fa4841
Packit Service fa4841
	if (cbMultiByte == 0)
Packit Service fa4841
	{
Packit Service fa4841
		sourceStart = (WCHAR*)lpWideCharStr;
Packit Service fa4841
		targetStart = (BYTE*)NULL;
Packit Service fa4841
		result = ConvertUTF16toUTF8(&sourceStart, &sourceStart[cchWideChar], &targetStart, NULL,
Packit Service fa4841
		                            strictConversion);
Packit Service fa4841
		length = targetStart - ((BYTE*)NULL);
Packit Service fa4841
	}
Packit Service fa4841
	else
Packit Service fa4841
	{
Packit Service fa4841
		sourceStart = (WCHAR*)lpWideCharStr;
Packit Service fa4841
		targetStart = (BYTE*)lpMultiByteStr;
Packit Service fa4841
		result = ConvertUTF16toUTF8(&sourceStart, &sourceStart[cchWideChar], &targetStart,
Packit Service fa4841
		                            &targetStart[cbMultiByte], strictConversion);
Packit Service fa4841
		length = targetStart - ((BYTE*)lpMultiByteStr);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	cbMultiByte = (result == conversionOK) ? length : 0;
Packit Service fa4841
#endif
Packit Service fa4841
	return cbMultiByte;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * ConvertToUnicode is a convenience wrapper for MultiByteToWideChar:
Packit Service fa4841
 *
Packit Service fa4841
 * If the lpWideCharStr parameter for the converted string points to NULL
Packit Service fa4841
 * or if the cchWideChar parameter is set to 0 this function will automatically
Packit Service fa4841
 * allocate the required memory which is guaranteed to be null-terminated
Packit Service fa4841
 * after the conversion, even if the source c string isn't.
Packit Service fa4841
 *
Packit Service fa4841
 * If the cbMultiByte parameter is set to -1 the passed lpMultiByteStr must
Packit Service fa4841
 * be null-terminated and the required length for the converted string will be
Packit Service fa4841
 * calculated accordingly.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
int ConvertToUnicode(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte,
Packit Service fa4841
                     LPWSTR* lpWideCharStr, int cchWideChar)
Packit Service fa4841
{
Packit Service fa4841
	int status;
Packit Service fa4841
	BOOL allocate = FALSE;
Packit Service fa4841
Packit Service fa4841
	if (!lpMultiByteStr)
Packit Service fa4841
		return 0;
Packit Service fa4841
Packit Service fa4841
	if (!lpWideCharStr)
Packit Service fa4841
		return 0;
Packit Service fa4841
Packit Service fa4841
	if (cbMultiByte == -1)
Packit Service fa4841
	{
Packit Service fa4841
		size_t len = strnlen(lpMultiByteStr, INT_MAX);
Packit Service fa4841
		if (len >= INT_MAX)
Packit Service fa4841
			return 0;
Packit Service fa4841
		cbMultiByte = (int)(len + 1);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (cchWideChar == 0)
Packit Service fa4841
	{
Packit Service fa4841
		cchWideChar = MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, NULL, 0);
Packit Service fa4841
		allocate = TRUE;
Packit Service fa4841
	}
Packit Service fa4841
	else if (!(*lpWideCharStr))
Packit Service fa4841
		allocate = TRUE;
Packit Service fa4841
Packit Service fa4841
	if (cchWideChar < 1)
Packit Service fa4841
		return 0;
Packit Service fa4841
Packit Service fa4841
	if (allocate)
Packit Service fa4841
	{
Packit Service fa4841
		*lpWideCharStr = (LPWSTR)calloc(cchWideChar + 1, sizeof(WCHAR));
Packit Service fa4841
Packit Service fa4841
		if (!(*lpWideCharStr))
Packit Service fa4841
		{
Packit Service fa4841
			// SetLastError(ERROR_INSUFFICIENT_BUFFER);
Packit Service fa4841
			return 0;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	status = MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, *lpWideCharStr,
Packit Service fa4841
	                             cchWideChar);
Packit Service fa4841
Packit Service fa4841
	if (status != cchWideChar)
Packit Service fa4841
	{
Packit Service fa4841
		if (allocate)
Packit Service fa4841
		{
Packit Service fa4841
			free(*lpWideCharStr);
Packit Service fa4841
			*lpWideCharStr = NULL;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		status = 0;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return status;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * ConvertFromUnicode is a convenience wrapper for WideCharToMultiByte:
Packit Service fa4841
 *
Packit Service fa4841
 * If the lpMultiByteStr parameter for the converted string points to NULL
Packit Service fa4841
 * or if the cbMultiByte parameter is set to 0 this function will automatically
Packit Service fa4841
 * allocate the required memory which is guaranteed to be null-terminated
Packit Service fa4841
 * after the conversion, even if the source unicode string isn't.
Packit Service fa4841
 *
Packit Service fa4841
 * If the cchWideChar parameter is set to -1 the passed lpWideCharStr must
Packit Service fa4841
 * be null-terminated and the required length for the converted string will be
Packit Service fa4841
 * calculated accordingly.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
int ConvertFromUnicode(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar,
Packit Service fa4841
                       LPSTR* lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar,
Packit Service fa4841
                       LPBOOL lpUsedDefaultChar)
Packit Service fa4841
{
Packit Service fa4841
	int status;
Packit Service fa4841
	BOOL allocate = FALSE;
Packit Service fa4841
Packit Service fa4841
	if (!lpWideCharStr)
Packit Service fa4841
		return 0;
Packit Service fa4841
Packit Service fa4841
	if (!lpMultiByteStr)
Packit Service fa4841
		return 0;
Packit Service fa4841
Packit Service fa4841
	if (cchWideChar == -1)
Packit Service fa4841
		cchWideChar = (int)(_wcslen(lpWideCharStr) + 1);
Packit Service fa4841
Packit Service fa4841
	if (cbMultiByte == 0)
Packit Service fa4841
	{
Packit Service fa4841
		cbMultiByte =
Packit Service fa4841
		    WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, NULL, 0, NULL, NULL);
Packit Service fa4841
		allocate = TRUE;
Packit Service fa4841
	}
Packit Service fa4841
	else if (!(*lpMultiByteStr))
Packit Service fa4841
		allocate = TRUE;
Packit Service fa4841
Packit Service fa4841
	if (cbMultiByte < 1)
Packit Service fa4841
		return 0;
Packit Service fa4841
Packit Service fa4841
	if (allocate)
Packit Service fa4841
	{
Packit Service fa4841
		*lpMultiByteStr = (LPSTR)calloc(1, cbMultiByte + 1);
Packit Service fa4841
Packit Service fa4841
		if (!(*lpMultiByteStr))
Packit Service fa4841
		{
Packit Service fa4841
			// SetLastError(ERROR_INSUFFICIENT_BUFFER);
Packit Service fa4841
			return 0;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	status = WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, *lpMultiByteStr,
Packit Service fa4841
	                             cbMultiByte, lpDefaultChar, lpUsedDefaultChar);
Packit Service fa4841
Packit Service fa4841
	if ((status != cbMultiByte) && allocate)
Packit Service fa4841
	{
Packit Service fa4841
		status = 0;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if ((status <= 0) && allocate)
Packit Service fa4841
	{
Packit Service fa4841
		free(*lpMultiByteStr);
Packit Service fa4841
		*lpMultiByteStr = NULL;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return status;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Swap Unicode byte order (UTF16LE <-> UTF16BE)
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
void ByteSwapUnicode(WCHAR* wstr, int length)
Packit Service fa4841
{
Packit Service fa4841
	WCHAR* end = &wstr[length];
Packit Service fa4841
Packit Service fa4841
	while (wstr < end)
Packit Service fa4841
	{
Packit Service fa4841
		*wstr = _byteswap_ushort(*wstr);
Packit Service fa4841
		wstr++;
Packit Service fa4841
	}
Packit Service fa4841
}