/*
 Copyright (C) 2010 Kuri-Applications

 UString.cpp - implementations of _StringW
 */

#include "stdafx.h"
#include "UString.h"

#include "Convert.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#define _fmalloc     malloc
#define _frealloc    realloc
#define _ffree       free
#define _fmemcpy     memcpy
#define _fmemmove    memmove

// in unicode.cpp
LPWSTR __stdcall UniLoadStringW(HINSTANCE hInstance, UINT uID);

///////////////////////////////////////////////////////////////////////////////

DWORD WINAPI _AnsiLen(LPCSTR lpszString)
{
	if (!lpszString)
		return 0;
	DWORD n = 0;
	while (*lpszString++)
		n++;
	return n;
}

DWORD WINAPI _UnicodeLen(LPCUWSTR lpszString)
{
	if (!lpszString)
		return 0;
	DWORD n = 0;
	while (*lpszString++)
		n++;
	return n;
}

DWORD WINAPI _AnsiLen(LPCUWSTR lpszString, DWORD uLength, UINT uCodePage = CP_ACP)
{
	DWORD n;
	if (!lpszString)
		return 0;
#ifdef _WIN64
	LPWSTR lpw;
	if (uLength == 0xFFFFFFFF)
		uLength = _UnicodeLen(lpszString);
	lpw = (LPWSTR) malloc(sizeof(WCHAR) * uLength);
	memcpy(lpw, lpszString, sizeof(WCHAR) * uLength);
	n = ::WideCharToMultiByte(uCodePage, 0, lpw, uLength, NULL, 0, NULL, NULL);
	free(lpw);
#else
	if (uLength == 0xFFFFFFFF)
		n = ::WideCharToMultiByte(uCodePage, 0, lpszString, 0xFFFFFFFF, NULL, 0, NULL, NULL) - 1;
	else
		n = ::WideCharToMultiByte(uCodePage, 0, lpszString, uLength, NULL, 0, NULL, NULL);
#endif
	return n;
}

DWORD WINAPI _UnicodeLen(LPCSTR lpszString, DWORD uLength, UINT uCodePage = CP_ACP)
{
	DWORD n;
	if (!lpszString)
		return 0;
	if (uLength == 0xFFFFFFFF)
		n = ::MultiByteToWideChar(uCodePage, 0, lpszString, 0xFFFFFFFF, NULL, 0) - 1;
	else
		n = ::MultiByteToWideChar(uCodePage, 0, lpszString, uLength, NULL, 0);
	return n;
}

DWORD WINAPI _AnsiFromUnicode(LPSTR lpszBuffer, DWORD nBufLen, LPCUWSTR lpszString, DWORD nLen, UINT uCodePage = CP_ACP)
{
#ifdef _WIN64
	LPWSTR lpw;
	lpw = (LPWSTR) malloc(sizeof(WCHAR) * nLen);
	memcpy(lpw, lpszString, sizeof(WCHAR) * nLen);
	DWORD n = ::WideCharToMultiByte(uCodePage, 0, lpw, (int) nLen, lpszBuffer, (int) nBufLen, NULL, NULL);
	free(lpw);
	return n;
#else
	return ::WideCharToMultiByte(uCodePage, 0, lpszString, (int) nLen, lpszBuffer, (int) nBufLen, NULL, NULL);
#endif
}

DWORD WINAPI _UnicodeFromAnsi(LPWSTR lpszBuffer, DWORD nBufLen, LPCSTR lpszString, DWORD nLen, UINT uCodePage = CP_ACP)
{
	return ::MultiByteToWideChar(uCodePage, 0, lpszString, (int) nLen, lpszBuffer, (int) nBufLen);
}

LPSTR WINAPI _AnsiFromUnicode2(LPCUWSTR lpszString, DWORD nLen, DWORD* puLen = NULL, UINT uCodePage = CP_ACP)
{
	DWORD uLen = _AnsiLen(lpszString, nLen) + 1;
	LPSTR lpstr = (LPSTR) ::_fmalloc(sizeof(CHAR) * uLen);
	_AnsiFromUnicode(lpstr, uLen, lpszString, nLen, uCodePage);
	if (puLen)
		*puLen = uLen - 1;
	lpstr[uLen - 1] = 0;
	return lpstr;
}

LPWSTR WINAPI _UnicodeFromAnsi2(LPCSTR lpszString, DWORD nLen, DWORD* puLen = NULL, UINT uCodePage = CP_ACP)
{
	DWORD uLen = _UnicodeLen(lpszString, nLen) + 1;
	LPWSTR lpwstr = (LPWSTR) ::_fmalloc(sizeof(WCHAR) * uLen);
	_UnicodeFromAnsi(lpwstr, uLen, lpszString, nLen, uCodePage);
	if (puLen)
		*puLen = uLen - 1;
	lpwstr[uLen - 1] = 0;
	return lpwstr;
}

///////////////////////////////////////////////////////////////////////////////

typedef struct _StringBufferW
{
	#define STRING_BUFFERW_SIGNATURE  0x4fa872eu
	DWORD dwSig;
	DWORD uLength;
	DWORD uMaxLength;
	LPWSTR data() const
		{ return (LPWSTR) (this + 1); }
	bool IsValidSignature() const
		{ return dwSig == STRING_BUFFERW_SIGNATURE; }
} STRING_BUFFERW, FAR* LPSTRING_BUFFERW;

LPWSTR WINAPI AllocStringBuffer(LPWSTR lpszBuffer)
{
	if (!lpszBuffer)
		return NULL;
	LPSTRING_BUFFERW pbufBase = ((LPSTRING_BUFFERW) lpszBuffer) - 1;
	if (!pbufBase->IsValidSignature())
		return NULL;
	LPSTRING_BUFFERW pbuf = (LPSTRING_BUFFERW) _fmalloc(sizeof(STRING_BUFFERW) + sizeof(wchar_t) * (pbufBase->uLength + 1));
	if (!pbuf)
		return NULL;
	pbuf->dwSig = STRING_BUFFERW_SIGNATURE;
	pbuf->uLength = pbuf->uMaxLength = pbufBase->uLength;
	_fmemcpy(pbuf->data(), lpszBuffer, (pbufBase->uLength + 1) * sizeof(wchar_t));
	return pbuf->data();
}

LPWSTR WINAPI AllocString(LPCUWSTR lpszString)
{
	DWORD uLength = _UnicodeLen(lpszString);
	LPSTRING_BUFFERW pbuf = (LPSTRING_BUFFERW) _fmalloc(sizeof(STRING_BUFFERW) + sizeof(wchar_t) * (uLength + 1));
	if (!pbuf)
		return NULL;
	pbuf->dwSig = STRING_BUFFERW_SIGNATURE;
	pbuf->uLength = pbuf->uMaxLength = uLength;
	_fmemcpy(pbuf->data(), lpszString, uLength * sizeof(wchar_t));
	pbuf->data()[uLength] = 0;
	return pbuf->data();
}

LPWSTR WINAPI ReAllocString(LPWSTR lpBuf, LPCUWSTR lpszString)
{
	DWORD uLength = _UnicodeLen(lpszString);
	LPSTRING_BUFFERW pbuf = ((LPSTRING_BUFFERW) lpBuf) - 1;
	if (!pbuf->IsValidSignature())
		return NULL;
	if (pbuf->uMaxLength < uLength)
	{
		pbuf = (LPSTRING_BUFFERW) _frealloc(pbuf, sizeof(STRING_BUFFERW) + sizeof(wchar_t) * (uLength + 1));
		if (!pbuf)
			return NULL;
		pbuf->uMaxLength = uLength;
	}
	pbuf->uLength = uLength;
	_fmemcpy(pbuf->data(), lpszString, uLength * sizeof(wchar_t));
	pbuf->data()[uLength] = 0;
	return pbuf->data();
}

LPWSTR WINAPI AllocStringLen(LPCUWSTR lpszString, DWORD nLen)
{
	DWORD uLength = nLen;
	LPSTRING_BUFFERW pbuf = (LPSTRING_BUFFERW) _fmalloc(sizeof(STRING_BUFFERW) + sizeof(wchar_t) * (uLength + 1));
	if (!pbuf)
		return NULL;
	pbuf->dwSig = STRING_BUFFERW_SIGNATURE;
	pbuf->uLength = pbuf->uMaxLength = uLength;
	if (lpszString)
		_fmemcpy(pbuf->data(), lpszString, uLength * sizeof(wchar_t));
	else
		pbuf->data()[0] = 0;
	pbuf->data()[uLength] = 0;
	return pbuf->data();
}

LPWSTR WINAPI ReAllocStringLen(LPWSTR lpBuf, LPCUWSTR lpszString, DWORD nLen)
{
	DWORD uLength = nLen;
	LPSTRING_BUFFERW pbuf = ((LPSTRING_BUFFERW) lpBuf) - 1;
	if (!pbuf->IsValidSignature())
		return NULL;
	if (pbuf->uMaxLength < uLength)
	{
		pbuf = (LPSTRING_BUFFERW) _frealloc(pbuf, sizeof(STRING_BUFFERW) + sizeof(wchar_t) * (uLength + 1));
		if (!pbuf)
			return NULL;
		pbuf->uMaxLength = uLength;
	}
	pbuf->uLength = uLength;
	_fmemcpy(pbuf->data(), lpszString, uLength* sizeof(wchar_t));
	pbuf->data()[uLength] = 0;
	return pbuf->data();
}

LPWSTR WINAPI AllocStringA(LPCSTR lpszString, UINT uCodePage = CP_ACP)
{
	DWORD uAnsiLength = _AnsiLen(lpszString);
	DWORD uUniLength = _UnicodeLen(lpszString, uAnsiLength) + 1;
	LPSTRING_BUFFERW pbuf = (LPSTRING_BUFFERW) _fmalloc(sizeof(STRING_BUFFERW) + sizeof(wchar_t) * uUniLength);
	if (!pbuf)
		return NULL;
	pbuf->dwSig = STRING_BUFFERW_SIGNATURE;
	pbuf->uLength = pbuf->uMaxLength = uUniLength - 1;
	_UnicodeFromAnsi(pbuf->data(), uUniLength, lpszString, uAnsiLength, uCodePage);
	pbuf->data()[uUniLength - 1] = 0;
	return pbuf->data();
}

LPWSTR WINAPI ReAllocStringA(LPWSTR lpBuf, LPCSTR lpszString, UINT uCodePage = CP_ACP)
{
	DWORD uAnsiLength = _AnsiLen(lpszString);
	DWORD uUniLength = _UnicodeLen(lpszString, uAnsiLength) + 1;
	LPSTRING_BUFFERW pbuf = ((LPSTRING_BUFFERW) lpBuf) - 1;
	if (!pbuf->IsValidSignature())
		return NULL;
	if (pbuf->uMaxLength < uUniLength - 1)
	{
		pbuf = (LPSTRING_BUFFERW) _frealloc(pbuf, sizeof(STRING_BUFFERW) + sizeof(wchar_t) * uUniLength);
		if (!pbuf)
			return NULL;
		pbuf->uMaxLength = uUniLength - 1;
	}
	pbuf->uLength = uUniLength - 1;
	_UnicodeFromAnsi(pbuf->data(), uUniLength, lpszString, uAnsiLength, uCodePage);
	pbuf->data()[uUniLength - 1] = 0;
	return pbuf->data();
}

LPWSTR WINAPI AllocStringLenA(LPCSTR lpszString, DWORD nLen, UINT uCodePage = CP_ACP)
{
	DWORD uAnsiLength = nLen;
	DWORD uUniLength = _UnicodeLen(lpszString, uAnsiLength) + 1;
	LPSTRING_BUFFERW pbuf = (LPSTRING_BUFFERW) _fmalloc(sizeof(STRING_BUFFERW) + sizeof(wchar_t) * uUniLength);
	if (!pbuf)
		return NULL;
	LPWSTR lp = pbuf->data();
	pbuf->dwSig = STRING_BUFFERW_SIGNATURE;
	pbuf->uLength = pbuf->uMaxLength = uUniLength - 1;
	_UnicodeFromAnsi(lp, uUniLength, lpszString, uAnsiLength, uCodePage);
	lp[uUniLength - 1] = 0;
	return lp;
}

LPWSTR WINAPI ReAllocStringLenA(LPWSTR lpBuf, LPCSTR lpszString, DWORD nLen, UINT uCodePage = CP_ACP)
{
	DWORD uAnsiLength = nLen;
	DWORD uUniLength = _UnicodeLen(lpszString, uAnsiLength) + 1;
	LPSTRING_BUFFERW pbuf = ((LPSTRING_BUFFERW) lpBuf) - 1;
	if (!pbuf->IsValidSignature())
		return NULL;
	if (pbuf->uMaxLength < uUniLength - 1)
	{
		pbuf = (LPSTRING_BUFFERW) _frealloc(pbuf, sizeof(STRING_BUFFERW) + sizeof(wchar_t) * uUniLength);
		if (!pbuf)
			return NULL;
		pbuf->uMaxLength = uUniLength - 1;
	}
	LPWSTR lp = pbuf->data();
	pbuf->uLength = uUniLength - 1;
	_UnicodeFromAnsi(lp, uUniLength, lpszString, uAnsiLength, uCodePage);
	lp[uUniLength - 1] = 0;
	return lp;
}

DWORD WINAPI GetStringLen(LPWSTR lpBuf)
{
	LPSTRING_BUFFERW pbuf = ((LPSTRING_BUFFERW) lpBuf) - 1;
	if (!pbuf->IsValidSignature())
		return 0;
	return pbuf->uLength;
}

LPWSTR WINAPI JoinString(LPWSTR lpbuf, LPCUWSTR lpszString)
{
	if (!lpbuf)
		return AllocString(lpszString);
	LPSTRING_BUFFERW pbuf = ((LPSTRING_BUFFERW) lpbuf) - 1;
	if (!pbuf->IsValidSignature())
		return NULL;
	DWORD uOldLength = pbuf->uLength;
	DWORD uLength = _UnicodeLen(lpszString);
	DWORD uNewLength = pbuf->uLength + uLength + 1;
	if (pbuf->uMaxLength < uNewLength - 1)
	{
		pbuf = (LPSTRING_BUFFERW) _frealloc(pbuf, sizeof(STRING_BUFFERW) + sizeof(wchar_t) * uNewLength);
		if (!pbuf)
			return NULL;
		pbuf->uMaxLength = uNewLength - 1;
	}
	pbuf->uLength = uNewLength - 1;
	_fmemcpy(pbuf->data() + uOldLength, lpszString, uLength * sizeof(wchar_t));
	pbuf->data()[uNewLength - 1] = 0;
	return pbuf->data();
}

LPWSTR WINAPI JoinStringLen(LPWSTR lpbuf, LPCUWSTR lpszString, DWORD uLen)
{
	if (!lpbuf)
		return AllocStringLen(lpszString, uLen);
	LPSTRING_BUFFERW pbuf = ((LPSTRING_BUFFERW) lpbuf) - 1;
	if (!pbuf->IsValidSignature())
		return NULL;
	DWORD uOldLength = pbuf->uLength;
	DWORD uLength = uLen;
	DWORD uNewLength = pbuf->uLength + uLength + 1;
	if (pbuf->uMaxLength < uNewLength - 1)
	{
		pbuf = (LPSTRING_BUFFERW) _frealloc(pbuf, sizeof(STRING_BUFFERW) + sizeof(wchar_t) * uNewLength);
		if (!pbuf)
			return NULL;
		pbuf->uMaxLength = uNewLength - 1;
	}
	pbuf->uLength = uNewLength - 1;
	_fmemcpy(pbuf->data() + uOldLength, lpszString, uLength * sizeof(wchar_t));
	pbuf->data()[uNewLength - 1] = 0;
	return pbuf->data();
}

LPWSTR WINAPI JoinStringA(LPWSTR lpbuf, LPCSTR lpszString, UINT uCodePage = CP_ACP)
{
	if (!lpbuf)
		return AllocStringA(lpszString);
	LPSTRING_BUFFERW pbuf = ((LPSTRING_BUFFERW) lpbuf) - 1;
	if (!pbuf->IsValidSignature())
		return NULL;
	DWORD uOldLength = pbuf->uLength;
	DWORD uAnsiLength = _AnsiLen(lpszString);
	DWORD uUniLength = _UnicodeLen(lpszString, uAnsiLength) + 1;
	DWORD uNewLength = pbuf->uLength + uUniLength;
	if (pbuf->uMaxLength < uNewLength - 1)
	{
		pbuf = (LPSTRING_BUFFERW) _frealloc(pbuf, sizeof(STRING_BUFFERW) + sizeof(wchar_t) * uNewLength);
		if (!pbuf)
			return NULL;
		pbuf->uMaxLength = uNewLength - 1;
	}
	pbuf->uLength = uNewLength - 1;
	_UnicodeFromAnsi(pbuf->data() + uOldLength, uUniLength, lpszString, uAnsiLength, uCodePage);
	pbuf->data()[uNewLength - 1] = 0;
	return pbuf->data();
}

LPWSTR WINAPI JoinStringLenA(LPWSTR lpbuf, LPCSTR lpszString, DWORD uLen, UINT uCodePage = CP_ACP)
{
	if (!lpbuf)
		return AllocStringLenA(lpszString, uLen);
	LPSTRING_BUFFERW pbuf = ((LPSTRING_BUFFERW) lpbuf) - 1;
	if (!pbuf->IsValidSignature())
		return NULL;
	DWORD uOldLength = pbuf->uLength;
	DWORD uAnsiLength = uLen;
	DWORD uUniLength = _UnicodeLen(lpszString, uAnsiLength) + 1;
	DWORD uNewLength = pbuf->uLength + uUniLength;
	if (pbuf->uMaxLength < uNewLength - 1)
	{
		pbuf = (LPSTRING_BUFFERW) _frealloc(pbuf, sizeof(STRING_BUFFERW) + sizeof(wchar_t) * uNewLength);
		if (!pbuf)
			return NULL;
		pbuf->uMaxLength = uNewLength - 1;
	}
	pbuf->uLength = uNewLength - 1;
	LPWSTR lp = pbuf->data();
	_UnicodeFromAnsi(lp + uOldLength, uUniLength, lpszString, uAnsiLength, uCodePage);
	lp[uNewLength - 1] = 0;
	return lp;
}

LPWSTR WINAPI JoinStringBuffer(LPWSTR lpbuf, LPWSTR lpszSource)
{
	if (!lpbuf)
		return AllocStringBuffer(lpszSource);
	else if (!lpszSource)
		return AllocStringBuffer(lpbuf);
	LPSTRING_BUFFERW pbuf = ((LPSTRING_BUFFERW) lpbuf) - 1;
	if (!pbuf->IsValidSignature())
		return NULL;
	LPSTRING_BUFFERW pbufSrc = ((LPSTRING_BUFFERW) lpszSource) - 1;
	if (!pbufSrc->IsValidSignature())
		return NULL;
	DWORD uOldLength = pbuf->uLength;
	DWORD uLength = pbufSrc->uLength + 1;
	DWORD uNewLength = pbuf->uLength + uLength;
	if (pbuf->uMaxLength < uNewLength - 1)
	{
		pbuf = (LPSTRING_BUFFERW) _frealloc(pbuf, sizeof(STRING_BUFFERW) + sizeof(wchar_t) * uNewLength);
		if (!pbuf)
			return NULL;
		pbuf->uMaxLength = uNewLength - 1;
	}
	pbuf->uLength = uNewLength - 1;
	_fmemcpy(pbuf->data() + uOldLength, lpszSource, uLength * sizeof(wchar_t));
	pbuf->data()[uNewLength - 1] = 0;
	return pbuf->data();
}

LPWSTR WINAPI ExpandStringLen(LPWSTR lpBuf, DWORD nLen)
{
	if (!lpBuf)
		return AllocStringLen(NULL, nLen);
	DWORD uLength = nLen;
	LPSTRING_BUFFERW pbuf = ((LPSTRING_BUFFERW) lpBuf) - 1;
	if (!pbuf->IsValidSignature())
		return NULL;
	if (pbuf->uMaxLength < uLength)
	{
		pbuf = (LPSTRING_BUFFERW) _frealloc(pbuf, sizeof(STRING_BUFFERW) + sizeof(wchar_t) * (uLength + 1));
		if (!pbuf)
			return NULL;
		pbuf->uMaxLength = uLength;
	}
	pbuf->uLength = uLength;
	return pbuf->data();
}

LPWSTR WINAPI SetStringLen(LPWSTR lpBuf, DWORD nLen)
{
	if (!lpBuf)
	{
		if (nLen == 0xFFFFFFFF)
			return NULL;
		return AllocStringLen(NULL, nLen);
	}
	DWORD uLength = nLen != 0xFFFFFFFF ? nLen : _UnicodeLen(lpBuf);
	LPSTRING_BUFFERW pbuf = ((LPSTRING_BUFFERW) lpBuf) - 1;
	if (!pbuf->IsValidSignature())
		return NULL;
	if (pbuf->uMaxLength < uLength)
	{
		pbuf = (LPSTRING_BUFFERW) _frealloc(pbuf, sizeof(STRING_BUFFERW) + sizeof(wchar_t) * (uLength + 1));
		if (!pbuf)
			return NULL;
		pbuf->uMaxLength = uLength;
	}
	pbuf->data()[uLength] = 0;
	while (pbuf->uLength > uLength)
	{
		pbuf->uLength--;
		pbuf->data()[pbuf->uLength] = 0;
	}
	pbuf->uLength = uLength;
	return pbuf->data();
}

void WINAPI FreeStringBuffer(LPWSTR lpbuf)
{
	if (!lpbuf)
		return;
	LPSTRING_BUFFERW pbuf = ((LPSTRING_BUFFERW) lpbuf) - 1;
	if (!pbuf->IsValidSignature())
		return;
	_ffree(pbuf);
}

/////////////////////////////////////////////////////////////////////////////

_StringW::_StringW()
	: m_lpszData(NULL), m_lpszLast(NULL), m_uCodePage(CP_ACP)
{
}

_StringW::_StringW(LPCUWSTR lpszString)
	: m_lpszData(NULL), m_lpszLast(NULL), m_uCodePage(CP_ACP)
{
	if (HIWORD(lpszString))
		m_lpszData = AllocString(lpszString);
	else if (lpszString)
		LoadString(LOWORD(lpszString));
	else
		m_lpszData = NULL;
}

_StringW::_StringW(LPCSTR lpszString, UINT uCodePage)
	: m_lpszData(NULL), m_lpszLast(NULL)
{
	if (HIWORD(lpszString))
		m_lpszData = AllocStringA(lpszString, uCodePage);
	else if (lpszString)
		LoadString(LOWORD(lpszString));
	else
		m_lpszData = NULL;
}

_StringW::_StringW(const _StringW& _string)
	: m_lpszLast(NULL), m_uCodePage(_string.m_uCodePage)
{
	if (!_string.IsEmpty())
		m_lpszData = AllocStringBuffer(_string.m_lpszData);
	else
		m_lpszData = NULL;
}

_StringW::_StringW(wchar_t wch, DWORD nCount)
	: m_lpszLast(NULL), m_uCodePage(CP_ACP)
{
	if (nCount > 0)
	{
		wchar_t* pch = (wchar_t*) malloc(sizeof(wchar_t) * (nCount + 1));
		for (DWORD n = 0; n < nCount; n++)
			pch[n] = wch;
		pch[nCount] = 0;
		m_lpszData = AllocStringLen(pch, nCount);
		free(pch);
	}
	else
		m_lpszData = NULL;
}

_StringW::_StringW(char ch, DWORD nCount, UINT uCodePage)
	: m_lpszLast(NULL), m_uCodePage(uCodePage)
{
	if (nCount > 0)
	{
		char* pch = (char*) malloc(sizeof(char) * (nCount + 1));
		for (DWORD n = 0; n < nCount; n++)
			pch[n] = ch;
		pch[nCount] = 0;
		m_lpszData = AllocStringLenA(pch, nCount, uCodePage);
		free(pch);
	}
	else
		m_lpszData = NULL;
}

const _StringW& _StringW::operator = (LPCUWSTR lpszString)
{
	Empty();
	if (lpszString)
		m_lpszData = AllocString(lpszString);
	return *this;
}

const _StringW& _StringW::operator = (LPCSTR lpszString)
{
	Empty();
	if (lpszString)
		m_lpszData = AllocStringA(lpszString, m_uCodePage);
	return *this;
}

const _StringW& _StringW::operator = (const _StringW& _string)
{
	Empty();
	if (!_string.IsEmpty())
		m_lpszData = AllocStringBuffer(_string.m_lpszData);
	m_uCodePage = _string.m_uCodePage;
	return *this;
}

_StringW _StringW::operator + (LPCUWSTR lpszString) const
{
	if (!lpszString)
		return *this;
	_StringW str;
	LPWSTR lp = AllocStringBuffer(m_lpszData);
	if (!lp)
		return str;
	str.m_lpszData = JoinString(lp, lpszString);
	if (!str.m_lpszData)
	{
		FreeStringBuffer(lp);
		return str;
	}
	return str;
}

_StringW _StringW::operator + (LPCSTR lpszString) const
{
	if (!lpszString)
		return *this;
	_StringW str;
	LPWSTR lp = AllocStringBuffer(m_lpszData);
	if (!lp)
		return str;
	str.m_lpszData = JoinStringA(lp, lpszString, m_uCodePage);
	if (!str.m_lpszData)
	{
		FreeStringBuffer(lp);
		return str;
	}
	return str;
}

_StringW _StringW::operator + (const _StringW& _string) const
{
	if (_string.IsEmpty())
		return *this;
	_StringW str;
	LPWSTR lp = AllocStringBuffer(m_lpszData);
	if (!lp)
		return str;
	if (_string.m_lpszData)
		str.m_lpszData = JoinStringBuffer(lp, _string.m_lpszData);
	else
		str.m_lpszData = lp;
	if (!str.m_lpszData)
	{
		FreeStringBuffer(lp);
		return str;
	}
	return str;
}

_StringW _StringW::operator + (wchar_t ch) const
{
	_StringW str;
	LPWSTR lp = AllocStringBuffer(m_lpszData);
	if (!lp)
		return str;
	str.m_lpszData = JoinStringLen(lp, &ch, 1);
	if (!str.m_lpszData)
	{
		FreeStringBuffer(lp);
		return str;
	}
	return str;
}

_StringW _StringW::operator + (char ch) const
{
	_StringW str;
	LPWSTR lp = AllocStringBuffer(m_lpszData);
	if (!lp)
		return str;
	str.m_lpszData = JoinStringLenA(lp, &ch, 1, m_uCodePage);
	if (!str.m_lpszData)
	{
		FreeStringBuffer(lp);
		return str;
	}
	return str;
}

_StringW _StringW::operator & (LPCUWSTR lpszString) const
{
	if (!lpszString)
		return *this;
	_StringW str;
	LPWSTR lp = AllocStringBuffer(m_lpszData);
	if (!lp)
		return str;
	str.m_lpszData = JoinString(lp, lpszString);
	if (!str.m_lpszData)
	{
		FreeStringBuffer(lp);
		return str;
	}
	return str;
}

_StringW _StringW::operator & (LPCSTR lpszString) const
{
	if (!lpszString)
		return *this;
	_StringW str;
	LPWSTR lp = AllocStringBuffer(m_lpszData);
	if (!lp)
		return str;
	str.m_lpszData = JoinStringA(lp, lpszString, m_uCodePage);
	if (!str.m_lpszData)
	{
		FreeStringBuffer(lp);
		return str;
	}
	return str;
}

_StringW _StringW::operator & (const _StringW& _string) const
{
	if (_string.IsEmpty())
		return *this;
	_StringW str;
	LPWSTR lp = AllocStringBuffer(m_lpszData);
	if (!lp)
		return str;
	if (_string.m_lpszData)
		str.m_lpszData = JoinStringBuffer(lp, _string.m_lpszData);
	else
		str.m_lpszData = lp;
	if (!str.m_lpszData)
	{
		FreeStringBuffer(lp);
		return str;
	}
	return str;
}

_StringW _StringW::operator & (wchar_t ch) const
{
	_StringW str;
	LPWSTR lp = AllocStringBuffer(m_lpszData);
	if (!lp)
		return str;
	str.m_lpszData = JoinStringLen(lp, &ch, 1);
	if (!str.m_lpszData)
	{
		FreeStringBuffer(lp);
		return str;
	}
	return str;
}

_StringW _StringW::operator & (char ch) const
{
	_StringW str;
	LPWSTR lp = AllocStringBuffer(m_lpszData);
	if (!lp)
		return str;
	str.m_lpszData = JoinStringLenA(lp, &ch, 1, m_uCodePage);
	if (!str.m_lpszData)
	{
		FreeStringBuffer(lp);
		return str;
	}
	return str;
}

const _StringW& _StringW::operator += (LPCUWSTR lpszString)
{
	if (!lpszString)
		return *this;
	LPWSTR lpszData = JoinString(m_lpszData, lpszString);
	if (!lpszData)
		return *this;
	m_lpszData = lpszData;
	return *this;
}

const _StringW& _StringW::operator += (LPCSTR lpszString)
{
	if (!lpszString)
		return *this;
	LPWSTR lpszData = JoinStringA(m_lpszData, lpszString, m_uCodePage);
	if (!lpszData)
		return *this;
	m_lpszData = lpszData;
	return *this;
}

const _StringW& _StringW::operator += (const _StringW& _string)
{
	if (_string.IsEmpty())
		return *this;
	LPWSTR lpszData = JoinStringBuffer(m_lpszData, _string.m_lpszData);
	if (!lpszData)
		return *this;
	m_lpszData = lpszData;
	return *this;
}

const _StringW& _StringW::operator += (wchar_t ch)
{
	AppendChar(ch);
	return *this;
}

const _StringW& _StringW::operator += (char ch)
{
	//LPSTR lpszData = JoinStringLenA(m_lpszData, &ch, 1, m_uCodePage);
	//if (!lpszData)
	//	return *this;
	//m_lpszData = lpszData;
	AppendChar(ch);
	return *this;
}
//

const _StringW& _StringW::operator &= (LPCUWSTR lpszString)
{
	if (!lpszString)
		return *this;
	LPWSTR lpszData = JoinString(m_lpszData, lpszString);
	if (!lpszData)
		return *this;
	m_lpszData = lpszData;
	return *this;
}

const _StringW& _StringW::operator &= (LPCSTR lpszString)
{
	if (!lpszString)
		return *this;
	LPWSTR lpszData = JoinStringA(m_lpszData, lpszString, m_uCodePage);
	if (!lpszData)
		return *this;
	m_lpszData = lpszData;
	return *this;
}

const _StringW& _StringW::operator &= (const _StringW& _string)
{
	if (_string.IsEmpty())
		return *this;
	LPWSTR lpszData = JoinStringBuffer(m_lpszData, _string.m_lpszData);
	if (!lpszData)
		return *this;
	m_lpszData = lpszData;
	return *this;
}

const _StringW& _StringW::operator &= (wchar_t ch)
{
	//LPSTR lpszData = JoinStringLen(m_lpszData, &ch, 1);
	//if (!lpszData)
	//	return *this;
	//m_lpszData = lpszData;
	AppendChar(ch);
	return *this;
}

const _StringW& _StringW::operator &= (char ch)
{
	//LPSTR lpszData = JoinStringLenW(m_lpszData, &ch, 1, m_uCodePage);
	//if (!lpszData)
	//	return *this;
	//m_lpszData = lpszData;
	AppendChar(ch);
	return *this;
}

_StringW::operator LPCWSTR() const
{
	return m_lpszData;
}

_StringW::operator LPSTR()
{
	if (!m_lpszData)
		return NULL;
	if (m_lpszLast)
	{
		LPDWORD pu = ((LPDWORD) m_lpszLast) - 1;
		LPDWORD pdw = ((LPDWORD) pu) - 1;
		if (*pdw != STRING_BUFFERW_SIGNATURE)
			_ffree(m_lpszLast);
		else
			_ffree(pdw);
	}
	return m_lpszLast = _AnsiFromUnicode2(m_lpszData, (int) GetStringLen(m_lpszData), NULL, m_uCodePage);
}

wchar_t _StringW::operator [] (DWORD uIndex) const
{
	return m_lpszData[uIndex];
}

wchar_t& _StringW::operator [] (DWORD uIndex)
{
	return m_lpszData[uIndex];
}

_StringW::~_StringW()
{
	Empty();
}

void _StringW::Empty()
{
	if (m_lpszLast)
	{
		LPDWORD pu = ((LPDWORD) m_lpszLast) - 1;
		LPDWORD pdw = ((LPDWORD) pu) - 1;
		if (*pdw != STRING_BUFFERW_SIGNATURE)
			_ffree(m_lpszLast);
		else
			_ffree(pdw);
	}
	m_lpszLast = NULL;
	if (m_lpszData)
		FreeStringBuffer(m_lpszData);
	m_lpszData = NULL;
}

DWORD _StringW::GetLength() const
{
	if (!m_lpszData)
		return 0;
	return GetStringLen(m_lpszData);
}

DWORD _StringW::GetLengthA() const
{
	if (!m_lpszData)
		return 0;
	return _AnsiLen(m_lpszData, GetStringLen(m_lpszData), m_uCodePage);
}

LPWSTR _StringW::GetBuffer(DWORD uLength)
{
	if (uLength > GetLength())
	{
		LPWSTR lp = ExpandStringLen(m_lpszData, uLength);
		if (!lp)
			return NULL;
		m_lpszData = lp;
	}
	return m_lpszData;
}

void _StringW::ReleaseBuffer(DWORD uNewLength)
{
	LPWSTR lp = SetStringLen(m_lpszData, uNewLength);
	if (lp)
		m_lpszData = lp;
}

BOOL _StringW::IsEmpty() const
{
	if (!m_lpszData)
		return TRUE;
	return GetLength() == 0;
}

void _StringW::SetString(LPCUWSTR lpszString, DWORD uLength)
{
	register LPWSTR lpb = NULL;
	if (lpszString)
		lpb = AllocStringLen(lpszString, uLength);
	Empty();
	m_lpszData = lpb;
}

void _StringW::SetString(LPCSTR lpszString, DWORD uLength)
{
	register LPWSTR lpb = NULL;
	if (lpszString)
		lpb = AllocStringLenA(lpszString, uLength, m_uCodePage);
	Empty();
	m_lpszData = lpb;
}

void _StringW::SetString(const _StringW& strData, DWORD uLength)
{
	Empty();
	if (uLength == 0xFFFFFFFF)
		uLength = strData.GetLength();
	if (!strData.IsEmpty())
		m_lpszData = AllocStringLen(strData, uLength);
	m_uCodePage = strData.m_uCodePage;
}

LPSTR _StringW::GetBufferA(DWORD uLength)
{
	DWORD u = m_lpszData ? _AnsiLen(m_lpszData, GetLength()) : 0;
	if (!uLength || uLength < u)
		uLength = u;
	if (uLength == 0)
		return NULL;
	LPDWORD pu, pdw;
	if (m_lpszLast)
	{
		pu = ((LPDWORD) m_lpszLast) - 1;
		pdw = ((LPDWORD) pu) - 1;
		if (*pdw == STRING_BUFFERW_SIGNATURE)
		{
			if (*pu >= uLength)
				return m_lpszLast;
		}
		else
			pdw = (LPDWORD) m_lpszLast;
		pdw = (LPDWORD) _frealloc(pdw, sizeof(DWORD) + sizeof(DWORD) + sizeof(char) * (uLength + 1));
		*pdw = STRING_BUFFERW_SIGNATURE;
		m_lpszLast = NULL;
	}
	else
	{
		pdw = (LPDWORD) _fmalloc(sizeof(DWORD) + sizeof(DWORD) + sizeof(char) * (uLength + 1));
		*pdw = STRING_BUFFERW_SIGNATURE;
	}
	pu = (LPDWORD) (pdw + 1);
	*pu = uLength;
	LPSTR lp = (LPSTR) (pu + 1);
	if (m_lpszData)
		_AnsiFromUnicode(lp, uLength + 1, m_lpszData, GetLength(), m_uCodePage);
	lp[u] = 0;
	Empty();
	m_lpszLast = lp;
	return lp;
}

void _StringW::ReleaseBufferA(BOOL bSetLength, DWORD uNewLength)
{
	if (!m_lpszLast)
		return;
	DWORD uLength;
	LPDWORD pu = ((LPDWORD) m_lpszLast) - 1;
	LPDWORD pdw = ((LPDWORD) pu) - 1;
	if (*pdw != STRING_BUFFERW_SIGNATURE)
		return;
	uLength = *pu;
	if (bSetLength)
	{
		if (uNewLength == 0xFFFFFFFF)
			uLength = _AnsiLen(m_lpszLast);
		else if (uNewLength < uLength)
			uLength = uNewLength;
	}
	if (m_lpszData)
		FreeStringBuffer(m_lpszData);
	m_lpszData = AllocStringLenA(m_lpszLast, uLength, m_uCodePage);
	_ffree(pdw);
	m_lpszLast = NULL;
}

BOOL _StringW::LoadString(UINT uID)
{
	LPWSTR lpw;
	lpw = UniLoadStringW(NULL, uID);
	if (!lpw)
		return FALSE;
	operator = (lpw);
	free(lpw);
	return TRUE;
}


DWORD _StringW::AppendChar(wchar_t wch)
{
	DWORD uLength = GetLength();
	LPWSTR lp = ExpandStringLen(m_lpszData, uLength + 1);
	if (!lp)
		return 0xFFFFFFFF;
	m_lpszData = lp;
	lp[uLength] = wch;
	lp[uLength + 1] = 0;
	return uLength + 1;
}

DWORD _StringW::AppendChar(char ch)
{
	LPSTR lp;
	DWORD uUniLen;
	DWORD uAnsiLen;
	uUniLen = GetLength();
	if (!uUniLen)
	{
		char szBuffer[2];
		szBuffer[0] = ch;
		szBuffer[1] = 0;
		if (m_lpszData)
			Empty();
		m_lpszData = AllocStringLenA(szBuffer, 1, m_uCodePage);
		return 1;
	}
	uAnsiLen = _AnsiLen(m_lpszData, uUniLen);
	uAnsiLen++;
	lp = (LPSTR) malloc(sizeof(char) * (uAnsiLen + 1));
	_AnsiFromUnicode(lp, uAnsiLen, m_lpszData, (int) (uUniLen + 1), m_uCodePage);
	lp[uAnsiLen - 1] = ch;
	lp[uAnsiLen] = 0;
	Empty();
	m_lpszData = AllocStringLenA(lp, uUniLen, m_uCodePage);
	free(lp);
	return uAnsiLen;
}

DWORD _StringW::AppendString(LPCUWSTR lpszString, DWORD uLength)
{
	if (!lpszString)
		return 0xFFFFFFFF;
	LPWSTR lpszData = JoinStringLen(m_lpszData, lpszString, uLength);
	if (!lpszData)
		return 0xFFFFFFFF;
	m_lpszData = lpszData;
	return GetStringLen(m_lpszData);
}

DWORD _StringW::AppendString(LPCSTR lpszString, DWORD uLength)
{
	if (!lpszString)
		return 0xFFFFFFFF;
	LPWSTR lpszData = JoinStringLenA(m_lpszData, lpszString, uLength, m_uCodePage);
	if (!lpszData)
		return 0xFFFFFFFF;
	m_lpszData = lpszData;
	return _AnsiLen(m_lpszData, GetStringLen(m_lpszData), m_uCodePage);
}

DWORD _StringW::AppendString(const _StringW& _string)
{
	if (_string.IsEmpty())
		return 0xFFFFFFFF;
	LPWSTR lpszData = JoinStringBuffer(m_lpszData, _string.m_lpszData);
	if (!lpszData)
		return 0xFFFFFFFF;
	m_lpszData = lpszData;
	return GetStringLen(m_lpszData);
}

DWORD _StringW::InsertChar(wchar_t wch, DWORD uPos)
{
	DWORD uLength = GetLength();
	if (uPos > uLength)
		return 0xFFFFFFFF;
	LPWSTR lp = ExpandStringLen(m_lpszData, uLength + 1);
	if (!lp)
		return 0xFFFFFFFF;
	m_lpszData = lp;
	_fmemmove(lp + uPos + 1, lp + uPos, (size_t)(sizeof(wchar_t) * (uLength - uPos + 1)));
	lp[uPos] = wch;
	return uPos + 1;
}

DWORD _StringW::InsertChar(char ch, DWORD uPos)
{
	LPSTR lp;
	DWORD uUniLen;
	DWORD uAnsiLen;
	uUniLen = GetLength();
	if (!uUniLen)
	{
		char szBuffer[2];
		szBuffer[0] = ch;
		szBuffer[1] = 0;
		if (m_lpszData)
			Empty();
		m_lpszData = AllocStringLenA(szBuffer, 1, m_uCodePage);
		return 1;
	}
	uAnsiLen = _AnsiLen(m_lpszData, uUniLen);
	if (uPos > uAnsiLen)
		return 0xFFFFFFFF;
	uAnsiLen++;
	lp = (LPSTR) malloc(sizeof(char) * (uAnsiLen + 1));
	_AnsiFromUnicode(lp, uAnsiLen, m_lpszData, (uUniLen + 1), m_uCodePage);
	memmove(lp + uPos + 1, lp + uPos, (size_t)(sizeof(char) * (uAnsiLen - uPos /*+ 1*/)));
	lp[uPos] = ch;
	Empty();
	m_lpszData = AllocStringLenA(lp, uAnsiLen, m_uCodePage);
	free(lp);
	return uPos + 1;
}

DWORD _StringW::InsertString(LPCUWSTR lpszString, DWORD uPos, DWORD uStrLen)
{
	DWORD uLength = GetLength();
	if (uPos > uLength)
		return 0xFFFFFFFF;
	if (uStrLen == 0xFFFFFFFF)
		uStrLen = _UnicodeLen(lpszString);
	LPWSTR lp = ExpandStringLen(m_lpszData, uLength + uStrLen);
	if (!lp)
		return 0xFFFFFFFF;
	m_lpszData = lp;
	_fmemmove(lp + uPos + uStrLen, lp + uPos, (size_t)(sizeof(wchar_t) * (uLength - uPos + 1)));
	_fmemcpy(lp + uPos, lpszString, (size_t)(sizeof(wchar_t) * uStrLen));
	return uPos + uStrLen;
}

DWORD _StringW::InsertString(LPCSTR lpszString, DWORD uPos, DWORD uStrLen)
{
	LPSTR lp;
	DWORD uUniLen;
	DWORD uAnsiLen;
	uUniLen = GetLength();
	if (uStrLen == 0xFFFFFFFF)
		uStrLen = _AnsiLen(lpszString);
	if (!uUniLen)
	{
		if (m_lpszData)
			Empty();
		m_lpszData = AllocStringLenA(lpszString, uStrLen, m_uCodePage);
		return 1;
	}
	uAnsiLen = _AnsiLen(m_lpszData, uUniLen);
	if (uPos > uAnsiLen)
		return 0xFFFFFFFF;
	uUniLen++;
	lp = (LPSTR) malloc(sizeof(char) * (uAnsiLen + uStrLen));
	_AnsiFromUnicode(lp, uUniLen, m_lpszData, (uAnsiLen + 1), m_uCodePage);
	memmove(lp + uPos + uStrLen, lp + uPos, (size_t)(sizeof(char) * (uAnsiLen - uPos /*+ 1*/)));
	memcpy(lp + uPos, lpszString, (size_t)(sizeof(char) * uStrLen));
	Empty();
	m_lpszData = AllocStringLenA(lp, uAnsiLen + uStrLen - 1, m_uCodePage);
	free(lp);
	return uPos + 1;
}

DWORD _StringW::InsertString(const _StringW& strInsert, DWORD uPos)
{
	DWORD uStrLen = strInsert.GetLength();
	DWORD uLength = GetLength();
	if (uPos > uLength)
		return 0xFFFFFFFF;
	if (strInsert.IsEmpty())
		return uLength;
	LPWSTR lp = ExpandStringLen(m_lpszData, uLength + uStrLen);
	if (!lp)
		return 0xFFFFFFFF;
	m_lpszData = lp;
	_fmemmove(lp + uPos + uStrLen, lp + uPos, (size_t)(sizeof(wchar_t) * (uLength - uPos + 1)));
	_fmemcpy(lp + uPos, (LPCWSTR) strInsert, (size_t)(sizeof(wchar_t) * uStrLen));
	return uPos + uStrLen;
}

wchar_t _StringW::DeleteChar(DWORD uPos)
{
	LPSTRING_BUFFERW pbuf;
	if (!m_lpszData)
		return 0;
	pbuf = ((LPSTRING_BUFFERW) m_lpszData) - 1;
	if (!pbuf->IsValidSignature())
		return 0;
	if (uPos >= pbuf->uLength)
		return 0;
	wchar_t chRet = m_lpszData[uPos];
	if (pbuf->uLength == 1)
	{
		Empty();
		return chRet;
	}
	_fmemmove(m_lpszData + uPos, m_lpszData + uPos + 1, (size_t)(sizeof(wchar_t) * (pbuf->uLength - uPos)));
	pbuf->uLength--;
	return chRet;
}

bool _StringW::DeleteString(DWORD uStart, DWORD uLength)
{
	LPSTRING_BUFFERW pbuf;
	if (!m_lpszData)
		return false;
	pbuf = ((LPSTRING_BUFFERW) m_lpszData) - 1;
	if (!pbuf->IsValidSignature())
		return false;
	if (uStart + uLength > pbuf->uLength)
		return false;
	if (uStart == 0 && pbuf->uLength == uLength)
	{
		Empty();
		return true;
	}
	_fmemmove(m_lpszData + uStart, m_lpszData + uStart + uLength, (size_t)(sizeof(wchar_t) * (pbuf->uLength - uStart - uLength + 1)));
	pbuf->uLength -= uLength;
	return true;
}

/////////////////////////////////////////////////////////////////////////////

void __stdcall _FormatStringA(LPWSTR& lpszData, LPCSTR lpszFormat, va_list va, UINT uCodePage = CP_ACP)
{
	int n, nRet;
	LPSTR lp;

	n = 255;
	lp = (LPSTR) malloc(sizeof(CHAR) * 255);
	nRet = _vsnprintf(lp, n, lpszFormat, va);
	while (nRet < 0)
	{
		n += 255;
		lp = (LPSTR) realloc(lp, sizeof(CHAR) * n);
		nRet = _vsnprintf(lp, n, lpszFormat, va);
	}
	if (lpszData)
		lpszData = ReAllocStringLenA(lpszData, lp, nRet, uCodePage);
	else
		lpszData = AllocStringLenA(lp, nRet, uCodePage);
	free(lp);
}

void __stdcall _FormatStringW(LPWSTR& lpszData, LPCWSTR lpszFormat, va_list va)
{
	int n, nRet;
	LPWSTR lp;

	n = 255;
	lp = (LPWSTR) malloc(sizeof(WCHAR) * 255);
	nRet = _vsnwprintf(lp, n, lpszFormat, va);
	while (nRet < 0)
	{
		n += 255;
		lp = (LPWSTR) realloc(lp, sizeof(WCHAR) * n);
		nRet = _vsnwprintf(lp, n, lpszFormat, va);
	}
	if (lpszData)
		lpszData = ReAllocStringLen(lpszData, lp, nRet);
	else
		lpszData = AllocStringLen(lp, nRet);
	free(lp);
}

BOOL WINAPIV _StringW::Format(LPCSTR lpszString, ...)
{
	va_list va;
	va_start(va, lpszString);
	//Clear();
	//int nLen = _vscprintf(lpszString, va);
	//if (!nLen)
	//	return FALSE;
	//LPSTR lp = GetBuffer((DWORD) nLen);
	//nLen = _vsprintf(lp, lpszString, va);
	//ReleaseBuffer((DWORD) nLen);
	_FormatStringA(m_lpszData, lpszString, va, m_uCodePage);
	va_end(va);
	return TRUE;
}

BOOL WINAPIV _StringW::Format(LPCWSTR lpszString, ...)
{
	va_list va;
	va_start(va, lpszString);
	//Clear();
	//int nLen = _vscwprintf(lpszString, va);
	//if (!nLen)
	//	return FALSE;
	//LPWSTR lp = GetBufferW((DWORD) nLen);
	//nLen = _vswprintf(lp, lpszString, va);
	//ReleaseBufferW(TRUE, (DWORD) nLen);
	_FormatStringW(m_lpszData, lpszString, va);
	va_end(va);
	return TRUE;
}

BOOL WINAPIV _StringW::Format(const _StringW* pstrFormat, ...)
{
	va_list va;
	va_start(va, pstrFormat);
	//Clear();
	//int nLen = _vscprintf(lpszString, va);
	//if (!nLen)
	//	return FALSE;
	//LPSTR lp = GetBuffer((DWORD) nLen);
	//nLen = _vsprintf(lp, lpszString, va);
	//ReleaseBuffer((DWORD) nLen);
	_FormatStringW(m_lpszData, pstrFormat->m_lpszData, va);
	va_end(va);
	return TRUE;
}

BOOL WINAPIV _StringW::Format(UINT uID, ...)
{
	_StringW str(MAKEINTRESOURCE(uID));
	va_list va;
	va_start(va, uID);
	//Clear();
	//int nLen = _vscprintf((LPCSTR) str, va);
	//if (!nLen)
	//	return FALSE;
	//LPSTR lp = GetBuffer((DWORD) nLen);
	//nLen = _vsprintf(lp, (LPCSTR) str, va);
	//ReleaseBuffer((DWORD) nLen);
	_FormatStringW(m_lpszData, str, va);
	va_end(va);
	return TRUE;
}

int _StringW::Compare(LPCWSTR lpszString, bool bNoCase, DWORD uLength) const
{
	if (IsEmpty())
	{
		if (uLength == 0 || (uLength == 0xFFFFFFFF && (!lpszString || !*lpszString)))
			return 0;
		return 0xFFFFFFFF;
	}
	else if (bNoCase)
	{
		if (uLength == 0xFFFFFFFF)
			return (int) _wcsicmp(m_lpszData, lpszString);
		else
			return (int) _wcsnicmp(m_lpszData, lpszString, (size_t) uLength);
	}
	else
	{
		if (uLength == 0xFFFFFFFF)
			return (int) wcscmp(m_lpszData, lpszString);
		else
			return (int) wcsncmp(m_lpszData, lpszString, (size_t) uLength);
	}
}

int _StringW::Compare(LPCSTR lpszString, bool bNoCase, DWORD uLength) const
{
	if (IsEmpty())
	{
		if (uLength == 0 || (uLength == 0xFFFFFFFF && (!lpszString || !*lpszString)))
			return 0;
		return -1;
	}

	LPSTR lp = AllocAnsiString();
	int ret;
	if (bNoCase)
	{
		if (uLength == 0xFFFFFFFF)
			ret = (int) _stricmp(lp, lpszString);
		else
			ret = (int) _strnicmp(lp, lpszString, (size_t) uLength);
	}
	else
	{
		if (uLength == 0xFFFFFFFF)
			ret = (int) strcmp(lp, lpszString);
		else
			ret = (int) strncmp(lp, lpszString, (size_t) uLength);
	}
	free(lp);
	return ret;
}

int _StringW::Compare(const _StringW& strCompare, bool bNoCase) const
{
	DWORD uLength = strCompare.GetLength() + 1;
	if (IsEmpty())
	{
		if (strCompare.IsEmpty())
			return 0;
		return -1;
	}
	else if (strCompare.IsEmpty())
		return 1;
	else if (bNoCase)
	{
		if (uLength == 0xFFFFFFFF)
			return (int) _wcsicmp(m_lpszData, strCompare);
		else
			return (int) _wcsnicmp(m_lpszData, strCompare, (size_t) uLength);
	}
	else
	{
		if (uLength == 0xFFFFFFFF)
			return (int) wcscmp(m_lpszData, strCompare);
		else
			return (int) wcsncmp(m_lpszData, strCompare, (size_t) uLength);
	}
}

LPSTR _StringW::AllocAnsiString() const
{
	return _AnsiFromUnicode2(m_lpszData, (int) GetStringLen(m_lpszData), NULL, m_uCodePage);
}

UINT _StringW::GetCodePage() const
{
	return m_uCodePage;
}

void _StringW::SetCodePage(UINT uCodePage)
{
	m_uCodePage = uCodePage;
}

///////////////////////////////////////////////////////////////////////////////

void _StringW::SetUTF8String(LPCBYTE lpBuffer, DWORD dwByteLength)
{
	DWORD dwNewLength;
	LPWSTR lpw;
	Empty();
	dwNewLength = ::UTF8ToUnicode(lpBuffer, dwByteLength, NULL, 0);
	if (!dwNewLength)
		return;
	lpw = AllocStringLen(NULL, dwNewLength);
	::UTF8ToUnicode(lpBuffer, dwByteLength, lpw, dwNewLength + 1);
	m_lpszData = lpw;
}

LPCBYTE _StringW::AllocUTF8String(LPDWORD lpdwLength)
{
	LPBYTE lp;
	DWORD dwLength;

	if (IsEmpty())
		return NULL;

	dwLength = ::UnicodeToUTF8(m_lpszData, GetLength(), NULL, 0) + 1;
	lp = (LPBYTE) _fmalloc(sizeof(BYTE) * dwLength);
	::UnicodeToUTF8(m_lpszData, GetLength(), lp, dwLength);
	lp[dwLength - 1] = 0;
	m_lpszLast = (LPSTR) lp;
	if (lpdwLength)
		*lpdwLength = dwLength - 1;
	return (LPCBYTE) lp;
}
//
//LPBYTE _StringW::AllocUTF8StringC(LPDWORD lpdwLength) const
//{
//	LPBYTE lp;
//	DWORD dwLength;
//
//	if (IsEmpty())
//		return NULL;
//
//	dwLength = ::UnicodeToUTF8(m_lpszData, GetLength(), NULL, 0) + 1;
//	lp = (LPBYTE) _fmalloc(sizeof(BYTE) * dwLength);
//	::UnicodeToUTF8(m_lpszData, GetLength(), lp, dwLength);
//	lp[dwLength - 1] = 0;
//	if (lpdwLength)
//		*lpdwLength = dwLength - 1;
//	return (LPCBYTE) lp;
//}
