//
// Unicode.h
//
// Library: Data/ODBC
// Package: ODBC
// Module:  Unicode
//
// Definition of Unicode_WIN32.
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier:	BSL-1.0
//


#ifndef Data_ODBC_Unicode_WIN32_INCLUDED
#define Data_ODBC_Unicode_WIN32_INCLUDED

#include "Poco/Buffer.h"
#include "Poco/UnicodeConverter.h"
#include <sql.h>
#include <sqltypes.h>
#include <string>

namespace Poco {
namespace Data {
namespace ODBC {


inline void makeUTF16(SQLCHAR* pSQLChar, SQLINTEGER length, std::wstring& target)
	/// Utility function for conversion from UTF-8 to UTF-16
{
	int len = length;
	if (SQL_NTS == len)
		len = (int) std::strlen((const char *) pSQLChar);

	UnicodeConverter::toUTF16((const char *) pSQLChar, len, target);
}


inline void makeUTF8(Poco::Buffer<wchar_t>& buffer, SQLINTEGER length, SQLPOINTER pTarget, SQLINTEGER targetLength)
	/// Utility function for conversion from UTF-16 to UTF-8. Length is in bytes.
{
	// Some ODBC drivers (notably IBM Informix) may report a returned
	// string length larger than the allocated wide-char buffer, or
	// return non-positive lengths. Handle these defensively instead
	// of throwing, to avoid breaking metadata retrieval for drivers
	// with non-conformant length reporting.
	//
	// Note: this function handles metadata strings (column names,
	// diagnostics, driver info), not row data. The driver has already
	// written into the buffer, so clamping to the actual buffer size
	// converts exactly what is available — this is the only viable
	// approach when the reported length is unreliable.
	if (length <= 0)
	{
		std::memset(pTarget, 0, targetLength);
		return;
	}
	if (length > static_cast<SQLINTEGER>(buffer.sizeBytes()))
		length = static_cast<SQLINTEGER>(buffer.sizeBytes());
	// Ensure length is aligned to wchar_t boundary for safe conversion
	length -= length % sizeof(wchar_t);

	length /= sizeof(wchar_t);
	std::string result;
	UnicodeConverter::toUTF8(buffer.begin(), length, result);

	std::memset(pTarget, 0, targetLength);
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable:4996) // deprecation warnings
#endif
	std::strncpy((char*) pTarget, result.c_str(), result.size() < targetLength ? result.size() : targetLength);
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
}


} } } // namespace Poco::Data::ODBC


#endif // Data_ODBC_Unicode_WIN32_INCLUDED
