Merge branch 'dev' of https://github.com/Microsoft/msphpsql into dev
This commit is contained in:
commit
7d45079f0f
33
CHANGELOG.md
33
CHANGELOG.md
|
@ -3,6 +3,39 @@ All notable changes to this project will be documented in this file.
|
|||
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
|
||||
## 5.5.0-preview - 2018-12-07
|
||||
Updated PECL release packages. Here is the list of updates:
|
||||
|
||||
### Added
|
||||
- Added support for PHP 7.3.0
|
||||
- Added support for Linux Ubuntu 18.10 and mac OS Mojave
|
||||
- Feature Request [#415](https://github.com/Microsoft/msphpsql/pull/886) - new options at connection and statement levels for both drivers for formatting decimal values in the fetched results
|
||||
|
||||
### Fixed
|
||||
- Pull Request [#854](https://github.com/Microsoft/msphpsql/pull/854) - Clear Azure Key Vault data after connection attributes are successfully set or when exception is thrown
|
||||
- Pull Request [#855](https://github.com/Microsoft/msphpsql/pull/855) - Improved performance by saving meta data before fetching and skipping unnecessary conversions for numeric data
|
||||
- Pull Request [#865](https://github.com/Microsoft/msphpsql/pull/865) - Corrected the way SQLPutData and SQLParamData are used when sending stream data to the server
|
||||
- Pull Request [#878](https://github.com/Microsoft/msphpsql/pull/878) - Modified the config files to enable Spectre Mitigations for PHP 7.1 (see related Request [#836](https://github.com/Microsoft/msphpsql/pull/836))
|
||||
- Pull Request [#891](https://github.com/Microsoft/msphpsql/pull/891) - Improved performance of Unicode conversions
|
||||
- Pull Request [#892](https://github.com/Microsoft/msphpsql/pull/892) - Removed warning messages while compiling extensions
|
||||
|
||||
### Limitations
|
||||
- No support for inout / output params when using sql_variant type
|
||||
- No support for inout / output params when formatting decimal values
|
||||
- In Linux and macOS, setlocale() only takes effect if it is invoked before the first connection. Attempting to set the locale after connecting will not work
|
||||
- Always Encrypted requires [MS ODBC Driver 17+](https://docs.microsoft.com/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server)
|
||||
- Only Windows Certificate Store and Azure Key Vault are supported. Custom Keystores are not yet supported
|
||||
- Issue [#716](https://github.com/Microsoft/msphpsql/issues/716) - With Always Encrypted enabled, named parameters in subqueries are not supported
|
||||
- [Always Encrypted limitations](https://docs.microsoft.com/sql/connect/php/using-always-encrypted-php-drivers#limitations-of-the-php-drivers-when-using-always-encrypted)
|
||||
|
||||
### Known Issues
|
||||
- Connection pooling on Linux or macOS is not recommended with [unixODBC](http://www.unixodbc.org/) < 2.3.7
|
||||
- When pooling is enabled in Linux or macOS
|
||||
- unixODBC <= 2.3.4 (Linux and macOS) might not return proper diagnostic information, such as error messages, warnings and informative messages
|
||||
- due to this unixODBC bug, fetch large data (such as xml, binary) as streams as a workaround. See the examples [here](https://github.com/Microsoft/msphpsql/wiki/Features#pooling)
|
||||
- With ColumnEncryption enabled, calling stored procedures with XML parameters does not work (Issue [#674](https://github.com/Microsoft/msphpsql/issues/674))
|
||||
- With ColumnEncryption enabled, fetching varbinary(max), varchar(max) or nvarchar(max) may fail with [ODBC Driver 17.3 CTP](https://blogs.msdn.microsoft.com/sqlnativeclient/2018/09/24/odbc-driver-17-3-preview-for-sql-server-released/)
|
||||
|
||||
## 5.4.0-preview - 2018-09-24
|
||||
Updated PECL release packages. Here is the list of updates:
|
||||
|
||||
|
|
|
@ -1886,10 +1886,13 @@ bool convert_input_param_to_utf16( _In_ zval* input_param_z, _Inout_ zval* conve
|
|||
return true;
|
||||
}
|
||||
|
||||
// if the parameter is an input parameter, calc the size of the necessary buffer from the length of the string
|
||||
#ifndef _WIN32
|
||||
wchar_size = SystemLocale::ToUtf16Strict( CP_UTF8, reinterpret_cast<LPCSTR>( buffer ), static_cast<int>( buffer_len ), NULL, 0 );
|
||||
// Declare wchar_size to be the largest possible number of UTF-16 characters after
|
||||
// conversion, to avoid the performance penalty of calling ToUtf16
|
||||
wchar_size = buffer_len;
|
||||
#else
|
||||
// Calculate the size of the necessary buffer from the length of the string -
|
||||
// no performance penalty because MultiByteToWidechar is highly optimised
|
||||
wchar_size = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, reinterpret_cast<LPCSTR>( buffer ), static_cast<int>( buffer_len ), NULL, 0 );
|
||||
#endif // !_WIN32
|
||||
|
||||
|
@ -1901,14 +1904,15 @@ bool convert_input_param_to_utf16( _In_ zval* input_param_z, _Inout_ zval* conve
|
|||
wbuffer = reinterpret_cast<SQLWCHAR*>( sqlsrv_malloc( (wchar_size + 1) * sizeof( SQLWCHAR ) ));
|
||||
// convert the utf-8 string to a wchar string in the new buffer
|
||||
#ifndef _WIN32
|
||||
int r = SystemLocale::ToUtf16Strict( CP_UTF8, reinterpret_cast<LPCSTR>( buffer ), static_cast<int>( buffer_len ), wbuffer, wchar_size );
|
||||
int rc = SystemLocale::ToUtf16Strict( CP_UTF8, reinterpret_cast<LPCSTR>( buffer ), static_cast<int>( buffer_len ), wbuffer, wchar_size );
|
||||
#else
|
||||
int r = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, reinterpret_cast<LPCSTR>( buffer ), static_cast<int>( buffer_len ), wbuffer, wchar_size );
|
||||
int rc = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, reinterpret_cast<LPCSTR>( buffer ), static_cast<int>( buffer_len ), wbuffer, wchar_size );
|
||||
#endif // !_WIN32
|
||||
// if there was a problem converting the string, then free the memory and return false
|
||||
if( r == 0 ) {
|
||||
if( rc == 0 ) {
|
||||
return false;
|
||||
}
|
||||
wchar_size = rc;
|
||||
|
||||
// null terminate the string, set the size within the zval, and return success
|
||||
wbuffer[ wchar_size ] = L'\0';
|
||||
|
|
|
@ -127,10 +127,13 @@ bool convert_string_from_utf16( _In_ SQLSRV_ENCODING encoding, _In_reads_bytes_(
|
|||
flags = WC_ERR_INVALID_CHARS;
|
||||
}
|
||||
|
||||
// calculate the number of characters needed
|
||||
#ifndef _WIN32
|
||||
cchOutLen = SystemLocale::FromUtf16Strict( encoding, inString, cchInLen, NULL, 0 );
|
||||
// Allocate enough space to hold the largest possible number of bytes for UTF-8 conversion
|
||||
// instead of calling FromUtf16, for performance reasons
|
||||
cchOutLen = 4*cchInLen;
|
||||
#else
|
||||
// Calculate the number of output bytes required - no performance hit here because
|
||||
// WideCharToMultiByte is highly optimised
|
||||
cchOutLen = WideCharToMultiByte( encoding, flags,
|
||||
inString, cchInLen,
|
||||
NULL, 0, NULL, NULL );
|
||||
|
@ -142,9 +145,10 @@ bool convert_string_from_utf16( _In_ SQLSRV_ENCODING encoding, _In_reads_bytes_(
|
|||
|
||||
// Create a buffer to fit the encoded string
|
||||
char* newString = reinterpret_cast<char*>( sqlsrv_malloc( cchOutLen + 1 /* NULL char*/ ));
|
||||
memset(newString, '\0', cchOutLen+1);
|
||||
|
||||
#ifndef _WIN32
|
||||
int rc = SystemLocale::FromUtf16( encoding, inString, cchInLen, newString, static_cast<int>(cchOutLen));
|
||||
int rc = SystemLocale::FromUtf16Strict( encoding, inString, cchInLen, newString, static_cast<int>(cchOutLen));
|
||||
#else
|
||||
int rc = WideCharToMultiByte( encoding, flags, inString, cchInLen, newString, static_cast<int>(cchOutLen), NULL, NULL );
|
||||
#endif // !_WIN32
|
||||
|
@ -153,9 +157,13 @@ bool convert_string_from_utf16( _In_ SQLSRV_ENCODING encoding, _In_reads_bytes_(
|
|||
sqlsrv_free( newString );
|
||||
return false;
|
||||
}
|
||||
char* newString2 = reinterpret_cast<char*>( sqlsrv_malloc( rc + 1 /* NULL char*/ ));
|
||||
memset(newString2, '\0', rc+1);
|
||||
memcpy_s(newString2, rc, newString, rc);
|
||||
sqlsrv_free( newString );
|
||||
|
||||
*outString = newString;
|
||||
newString[cchOutLen] = '\0'; // null terminate the encoded string
|
||||
*outString = newString2;
|
||||
cchOutLen = rc;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -261,6 +261,8 @@ class EncodingConverter
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
//if a shift sequence is encountered, we need to advance output buffer
|
||||
iconv_ret = iconv( m_pCvtCache->GetIConv(), NULL, NULL, &dest.m_pBytes, &dest.m_nBytesLeft );
|
||||
}
|
||||
|
||||
return cchDest - (dest.m_nBytesLeft / sizeof(DestType));
|
||||
|
|
|
@ -169,8 +169,14 @@ public:
|
|||
static size_t FromUtf16Strict(UINT destCodePage, const WCHAR * src, SSIZE_T cchSrc,
|
||||
__out_ecount_opt(cchDest) char * dest, size_t cchDest,
|
||||
bool * pHasDataLoss = NULL, DWORD * pErrorCode = NULL);
|
||||
// CP1252 to UTF16 conversion which does not involve iconv
|
||||
static size_t CP1252ToUtf16( const char *src, SSIZE_T cchSrc, WCHAR *dest, size_t cchDest, DWORD *pErrorCode );
|
||||
|
||||
|
||||
// UTF8/16 conversion which does not involve iconv
|
||||
static size_t Utf8To16( const char *src, SSIZE_T cchSrc, WCHAR *dest, size_t cchDest, DWORD *pErrorCode );
|
||||
static size_t Utf8From16( const WCHAR *src, SSIZE_T cchSrc, char *dest, size_t cchDest, DWORD *pErrorCode );
|
||||
static size_t Utf8To16Strict( const char *src, SSIZE_T cchSrc, WCHAR *dest, size_t cchDest, DWORD *pErrorCode );
|
||||
static size_t Utf8From16Strict( const WCHAR *src, SSIZE_T cchSrc, char *dest, size_t cchDest, DWORD *pErrorCode );
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Public Member Functions
|
||||
|
|
|
@ -336,9 +336,300 @@ const SystemLocale & SystemLocale::Singleton()
|
|||
return s_Default;
|
||||
}
|
||||
|
||||
|
||||
// Convert CP1252 to UTF-16 without requiring iconv or taking a lock.
|
||||
// This is trivial because, except for the 80-9F range, CP1252 bytes
|
||||
// directly map to the corresponding UTF-16 codepoint.
|
||||
size_t SystemLocale::CP1252ToUtf16( const char *src, SSIZE_T cchSrc, WCHAR *dest, size_t cchDest, DWORD *pErrorCode )
|
||||
{
|
||||
const static WCHAR s_1252Map[] =
|
||||
{
|
||||
0x20AC, 0x003F, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x003F, 0x017D, 0x003F,
|
||||
0x003F, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x003F, 0x017E, 0x0178
|
||||
};
|
||||
const unsigned char *usrc = reinterpret_cast<const unsigned char*>(src);
|
||||
const unsigned char *srcEnd = usrc + cchSrc;
|
||||
const WCHAR *destEnd = dest + cchDest;
|
||||
|
||||
while(usrc < srcEnd && dest < destEnd)
|
||||
{
|
||||
DWORD ucode = *usrc++;
|
||||
*dest++ = (ucode <= 127 || ucode >= 160) ? ucode : s_1252Map[ucode - 128];
|
||||
}
|
||||
pErrorCode && (*pErrorCode = (dest == destEnd && usrc != srcEnd) ? ERROR_INSUFFICIENT_BUFFER : ERROR_SUCCESS);
|
||||
return cchDest - (destEnd - dest);
|
||||
}
|
||||
|
||||
// Convert UTF-8 to UTF-16 without requiring iconv or taking a lock.
|
||||
// 0abcdefg -> 0abcdefg 00000000
|
||||
// 110abcde 10fghijk -> defghijk 00000abc
|
||||
// 1110abcd 10efghij 10klmnop -> ijklmnop abcdefgh
|
||||
// 11110abc 10defghi 10jklmno 10pqrstu -> cdfghijk 110110ab nopqrstu 11011lm
|
||||
size_t SystemLocale::Utf8To16( const char *src, SSIZE_T cchSrc, WCHAR *dest, size_t cchDest, DWORD *pErrorCode )
|
||||
{
|
||||
const unsigned char *usrc = reinterpret_cast<const unsigned char*>(src);
|
||||
const unsigned char *srcEnd = usrc + cchSrc;
|
||||
const WCHAR *destEnd = dest + cchDest;
|
||||
DWORD dummyError;
|
||||
if (!pErrorCode)
|
||||
{
|
||||
pErrorCode = &dummyError;
|
||||
}
|
||||
*pErrorCode = 0;
|
||||
|
||||
while(usrc < srcEnd && dest < destEnd)
|
||||
{
|
||||
DWORD ucode = *usrc++;
|
||||
if(ucode <= 127) // Most common case for ASCII
|
||||
{
|
||||
*dest++ = ucode;
|
||||
}
|
||||
else if(ucode < 0xC0) // unexpected trailing byte 10xxxxxx
|
||||
{
|
||||
goto Invalid;
|
||||
}
|
||||
else if(ucode < 0xE0) // 110abcde 10fghijk
|
||||
{
|
||||
if (usrc >= srcEnd || *usrc < 0x80 || *usrc > 0xBF ||
|
||||
(*dest = (ucode & 0x1F)<<6 | (*usrc++ & 0x3F)) < 0x80)
|
||||
{
|
||||
*dest = 0xFFFD;
|
||||
}
|
||||
dest++;
|
||||
}
|
||||
else if(ucode < 0xF0) // 1110abcd 10efghij 10klmnop
|
||||
{
|
||||
if (usrc >= srcEnd)
|
||||
{
|
||||
goto Invalid;
|
||||
}
|
||||
DWORD c1 = *usrc;
|
||||
if (c1 < 0x80 || c1 > 0xBF)
|
||||
{
|
||||
goto Invalid;
|
||||
}
|
||||
usrc++;
|
||||
if (usrc >= srcEnd)
|
||||
{
|
||||
goto Invalid;
|
||||
}
|
||||
DWORD c2 = *usrc;
|
||||
if (c2 < 0x80 || c2 > 0xBF)
|
||||
{
|
||||
goto Invalid;
|
||||
}
|
||||
usrc++;
|
||||
ucode = (ucode&15)<<12 | (c1&0x3F)<<6 | (c2&0x3F);
|
||||
if (ucode < 0x800 || ucode >= 0xD800 && ucode <= 0xDFFF)
|
||||
{
|
||||
goto Invalid;
|
||||
}
|
||||
*dest++ = ucode;
|
||||
}
|
||||
else if(ucode < 0xF8) // 11110abc 10defghi 10jklmno 10pqrstu
|
||||
{
|
||||
if (usrc >= srcEnd)
|
||||
{
|
||||
goto Invalid;
|
||||
}
|
||||
DWORD c1 = *usrc;
|
||||
if (c1 < 0x80 || c1 > 0xBF)
|
||||
{
|
||||
goto Invalid;
|
||||
}
|
||||
usrc++;
|
||||
if (usrc >= srcEnd)
|
||||
{
|
||||
goto Invalid;
|
||||
}
|
||||
DWORD c2 = *usrc;
|
||||
if (c2 < 0x80 || c2 > 0xBF)
|
||||
{
|
||||
goto Invalid;
|
||||
}
|
||||
usrc++;
|
||||
if (usrc >= srcEnd)
|
||||
{
|
||||
goto Invalid;
|
||||
}
|
||||
DWORD c3 = *usrc;
|
||||
if (c3 < 0x80 || c3 > 0xBF)
|
||||
{
|
||||
goto Invalid;
|
||||
}
|
||||
usrc++;
|
||||
ucode = (ucode&7)<<18 | (c1&0x3F)<<12 | (c2&0x3F)<<6 | (c3&0x3F);
|
||||
|
||||
if (ucode < 0x10000 // overlong encoding
|
||||
|| ucode > 0x10FFFF // exceeds Unicode range
|
||||
|| ucode >= 0xD800 && ucode <= 0xDFFF) // surrogate pairs
|
||||
{
|
||||
goto Invalid;
|
||||
}
|
||||
if (dest >= destEnd - 1)
|
||||
{
|
||||
*pErrorCode = ERROR_INSUFFICIENT_BUFFER;
|
||||
return cchDest - (destEnd - dest);
|
||||
}
|
||||
ucode -= 0x10000;
|
||||
// Lead surrogate
|
||||
*dest++ = 0xD800 + (ucode >> 10);
|
||||
// Trail surrogate
|
||||
*dest++ = 0xDC00 + (ucode & 0x3FF);
|
||||
}
|
||||
else // invalid
|
||||
{
|
||||
Invalid:
|
||||
*dest++ = 0xFFFD;
|
||||
}
|
||||
}
|
||||
if (!*pErrorCode)
|
||||
{
|
||||
*pErrorCode = (dest == destEnd && usrc != srcEnd) ? ERROR_INSUFFICIENT_BUFFER : ERROR_SUCCESS;
|
||||
}
|
||||
return cchDest - (destEnd - dest);
|
||||
}
|
||||
|
||||
size_t SystemLocale::Utf8To16Strict( const char *src, SSIZE_T cchSrc, WCHAR *dest, size_t cchDest, DWORD *pErrorCode )
|
||||
{
|
||||
const unsigned char *usrc = reinterpret_cast<const unsigned char*>(src);
|
||||
const unsigned char *srcEnd = usrc + cchSrc;
|
||||
const WCHAR *destEnd = dest + cchDest;
|
||||
DWORD dummyError;
|
||||
if (!pErrorCode)
|
||||
{
|
||||
pErrorCode = &dummyError;
|
||||
}
|
||||
*pErrorCode = 0;
|
||||
|
||||
while(usrc < srcEnd && dest < destEnd)
|
||||
{
|
||||
DWORD ucode = *usrc++;
|
||||
if(ucode <= 127) // Most common case for ASCII
|
||||
{
|
||||
*dest++ = ucode;
|
||||
}
|
||||
else if(ucode < 0xC0) // unexpected trailing byte 10xxxxxx
|
||||
{
|
||||
goto Invalid;
|
||||
}
|
||||
else if(ucode < 0xE0) // 110abcde 10fghijk
|
||||
{
|
||||
if (usrc >= srcEnd || *usrc < 0x80 || *usrc > 0xBF ||
|
||||
(*dest = (ucode & 0x1F)<<6 | (*usrc++ & 0x3F)) < 0x80)
|
||||
{
|
||||
goto Invalid;
|
||||
}
|
||||
dest++;
|
||||
}
|
||||
else if(ucode < 0xF0) // 1110abcd 10efghij 10klmnop
|
||||
{
|
||||
if (usrc >= srcEnd)
|
||||
{
|
||||
goto Invalid;
|
||||
}
|
||||
DWORD c1 = *usrc;
|
||||
if (c1 < 0x80 || c1 > 0xBF)
|
||||
{
|
||||
goto Invalid;
|
||||
}
|
||||
usrc++;
|
||||
if (usrc >= srcEnd)
|
||||
{
|
||||
goto Invalid;
|
||||
}
|
||||
DWORD c2 = *usrc;
|
||||
if (c2 < 0x80 || c2 > 0xBF)
|
||||
{
|
||||
goto Invalid;
|
||||
}
|
||||
usrc++;
|
||||
ucode = (ucode&15)<<12 | (c1&0x3F)<<6 | (c2&0x3F);
|
||||
if (ucode < 0x800 || ucode >= 0xD800 && ucode <= 0xDFFF)
|
||||
{
|
||||
goto Invalid;
|
||||
}
|
||||
*dest++ = ucode;
|
||||
}
|
||||
else if(ucode < 0xF8) // 11110abc 10defghi 10jklmno 10pqrstu
|
||||
{
|
||||
if (usrc >= srcEnd)
|
||||
{
|
||||
goto Invalid;
|
||||
}
|
||||
DWORD c1 = *usrc;
|
||||
if (c1 < 0x80 || c1 > 0xBF)
|
||||
{
|
||||
goto Invalid;
|
||||
}
|
||||
usrc++;
|
||||
if (usrc >= srcEnd)
|
||||
{
|
||||
goto Invalid;
|
||||
}
|
||||
DWORD c2 = *usrc;
|
||||
if (c2 < 0x80 || c2 > 0xBF)
|
||||
{
|
||||
goto Invalid;
|
||||
}
|
||||
usrc++;
|
||||
if (usrc >= srcEnd)
|
||||
{
|
||||
goto Invalid;
|
||||
}
|
||||
DWORD c3 = *usrc;
|
||||
if (c3 < 0x80 || c3 > 0xBF)
|
||||
{
|
||||
goto Invalid;
|
||||
}
|
||||
usrc++;
|
||||
ucode = (ucode&7)<<18 | (c1&0x3F)<<12 | (c2&0x3F)<<6 | (c3&0x3F);
|
||||
|
||||
if (ucode < 0x10000 // overlong encoding
|
||||
|| ucode > 0x10FFFF // exceeds Unicode range
|
||||
|| ucode >= 0xD800 && ucode <= 0xDFFF) // surrogate pairs
|
||||
{
|
||||
goto Invalid;
|
||||
}
|
||||
if (dest >= destEnd - 1)
|
||||
{
|
||||
*pErrorCode = ERROR_INSUFFICIENT_BUFFER;
|
||||
return cchDest - (destEnd - dest);
|
||||
}
|
||||
ucode -= 0x10000;
|
||||
// Lead surrogate
|
||||
*dest++ = 0xD800 + (ucode >> 10);
|
||||
// Trail surrogate
|
||||
*dest++ = 0xDC00 + (ucode & 0x3FF);
|
||||
}
|
||||
else // invalid
|
||||
{
|
||||
Invalid:
|
||||
*pErrorCode = ERROR_NO_UNICODE_TRANSLATION;
|
||||
return 0 ;
|
||||
}
|
||||
}
|
||||
if (!*pErrorCode)
|
||||
{
|
||||
*pErrorCode = (dest == destEnd && usrc != srcEnd) ? ERROR_INSUFFICIENT_BUFFER : ERROR_SUCCESS;
|
||||
}
|
||||
return cchDest - (destEnd - dest);
|
||||
}
|
||||
|
||||
size_t SystemLocale::ToUtf16( UINT srcCodePage, const char * src, SSIZE_T cchSrc, WCHAR * dest, size_t cchDest, DWORD * pErrorCode )
|
||||
{
|
||||
srcCodePage = ExpandSpecialCP( srcCodePage );
|
||||
if ( dest )
|
||||
{
|
||||
if ( srcCodePage == CP_UTF8 )
|
||||
{
|
||||
return SystemLocale::Utf8To16( src, cchSrc < 0 ? (1+strlen(src)) : cchSrc, dest, cchDest, pErrorCode );
|
||||
}
|
||||
else if ( srcCodePage == 1252 )
|
||||
{
|
||||
return SystemLocale::CP1252ToUtf16( src, cchSrc < 0 ? (1+strlen(src)) : cchSrc, dest, cchDest, pErrorCode );
|
||||
}
|
||||
}
|
||||
EncodingConverter cvt( CP_UTF16, srcCodePage );
|
||||
if ( !cvt.Initialize() )
|
||||
{
|
||||
|
@ -354,6 +645,17 @@ size_t SystemLocale::ToUtf16( UINT srcCodePage, const char * src, SSIZE_T cchSrc
|
|||
size_t SystemLocale::ToUtf16Strict( UINT srcCodePage, const char * src, SSIZE_T cchSrc, WCHAR * dest, size_t cchDest, DWORD * pErrorCode )
|
||||
{
|
||||
srcCodePage = ExpandSpecialCP( srcCodePage );
|
||||
if ( dest )
|
||||
{
|
||||
if ( srcCodePage == CP_UTF8 )
|
||||
{
|
||||
return SystemLocale::Utf8To16Strict( src, cchSrc < 0 ? (1+strlen(src)) : cchSrc, dest, cchDest, pErrorCode );
|
||||
}
|
||||
else if ( srcCodePage == 1252 )
|
||||
{
|
||||
return SystemLocale::CP1252ToUtf16( src, cchSrc < 0 ? (1+strlen(src)) : cchSrc, dest, cchDest, pErrorCode );
|
||||
}
|
||||
}
|
||||
EncodingConverter cvt( CP_UTF16, srcCodePage );
|
||||
if ( !cvt.Initialize() )
|
||||
{
|
||||
|
@ -366,9 +668,282 @@ size_t SystemLocale::ToUtf16Strict( UINT srcCodePage, const char * src, SSIZE_T
|
|||
return cvt.Convert( dest, cchDest, src, cchSrcActual, true, &hasLoss, pErrorCode );
|
||||
}
|
||||
|
||||
size_t SystemLocale::Utf8From16( const WCHAR *src, SSIZE_T cchSrc, char *dest, size_t cchDest, DWORD *pErrorCode )
|
||||
{
|
||||
const WCHAR *srcEnd = src + cchSrc;
|
||||
char *destEnd = dest + cchDest;
|
||||
DWORD dummyError;
|
||||
if (!pErrorCode)
|
||||
{
|
||||
pErrorCode = &dummyError;
|
||||
}
|
||||
*pErrorCode = 0;
|
||||
|
||||
// null dest is a special mode to calculate the output size required.
|
||||
if (!dest)
|
||||
{
|
||||
size_t cbOut = 0;
|
||||
while (src < srcEnd)
|
||||
{
|
||||
DWORD wch = *src++;
|
||||
if (wch < 128) // most common case.
|
||||
{
|
||||
cbOut++;
|
||||
}
|
||||
else if (wch < 0x800) // 127 to 2047: 2 bytes
|
||||
{
|
||||
cbOut += 2;
|
||||
}
|
||||
else if (wch < 0xD800 || wch > 0xDFFF) // 2048 to 55295 and 57344 to 65535: 3 bytes
|
||||
{
|
||||
cbOut += 3;
|
||||
}
|
||||
else if (wch < 0xDC00) // 65536 to end of Unicode: 4 bytes
|
||||
{
|
||||
if (src >= srcEnd)
|
||||
{
|
||||
cbOut += 3; // lone surrogate at end
|
||||
}
|
||||
else if (*src < 0xDC00 || *src > 0xDFFF)
|
||||
{
|
||||
cbOut += 3; // low surrogate not followed by high
|
||||
}
|
||||
else
|
||||
{
|
||||
cbOut += 4;
|
||||
}
|
||||
}
|
||||
else // unexpected trail surrogate
|
||||
{
|
||||
cbOut += 3;
|
||||
}
|
||||
}
|
||||
return cbOut;
|
||||
}
|
||||
while ( src < srcEnd && dest < destEnd )
|
||||
{
|
||||
DWORD wch = *src++;
|
||||
if (wch < 128) // most common case.
|
||||
{
|
||||
*dest++ = wch;
|
||||
}
|
||||
else if (wch < 0x800) // 127 to 2047: 2 bytes
|
||||
{
|
||||
if (destEnd - dest < 2)
|
||||
{
|
||||
*pErrorCode = ERROR_INSUFFICIENT_BUFFER;
|
||||
return 0;
|
||||
}
|
||||
*dest++ = 0xC0 | (wch >> 6);
|
||||
*dest++ = 0x80 | (wch & 0x3F);
|
||||
}
|
||||
else if (wch < 0xD800 || wch > 0xDFFF) // 2048 to 55295 and 57344 to 65535: 3 bytes
|
||||
{
|
||||
if (destEnd - dest < 3)
|
||||
{
|
||||
*pErrorCode = ERROR_INSUFFICIENT_BUFFER;
|
||||
return 0;
|
||||
}
|
||||
*dest++ = 0xE0 | (wch >> 12);
|
||||
*dest++ = 0x80 | (wch >> 6)&0x3F;
|
||||
*dest++ = 0x80 | (wch &0x3F);
|
||||
}
|
||||
else if (wch < 0xDC00) // 65536 to end of Unicode: 4 bytes
|
||||
{
|
||||
if (src >= srcEnd)
|
||||
{
|
||||
*pErrorCode = ERROR_NO_UNICODE_TRANSLATION; // lone surrogate at end
|
||||
if (destEnd - dest < 3)
|
||||
{
|
||||
*pErrorCode = ERROR_INSUFFICIENT_BUFFER;
|
||||
return 0;
|
||||
}
|
||||
*dest++ = 0xEF;
|
||||
*dest++ = 0xBF;
|
||||
*dest++ = 0xBD;
|
||||
continue;
|
||||
}
|
||||
if (*src < 0xDC00 || *src > 0xDFFF)
|
||||
{
|
||||
// low surrogate not followed by high
|
||||
if (destEnd - dest < 3)
|
||||
{
|
||||
*pErrorCode = ERROR_INSUFFICIENT_BUFFER;
|
||||
return 0;
|
||||
}
|
||||
*dest++ = 0xEF;
|
||||
*dest++ = 0xBF;
|
||||
*dest++ = 0xBD;
|
||||
continue;
|
||||
}
|
||||
wch = 0x10000 + ((wch - 0xD800)<<10) + *src++ - 0xDC00;
|
||||
if (destEnd - dest < 4)
|
||||
{
|
||||
*pErrorCode = ERROR_INSUFFICIENT_BUFFER;
|
||||
return 0;
|
||||
}
|
||||
*dest++ = 0xF0 | (wch >> 18);
|
||||
*dest++ = 0x80 | (wch >>12)&0x3F;
|
||||
*dest++ = 0x80 | (wch >> 6)&0x3F;
|
||||
*dest++ = 0x80 | wch&0x3F;
|
||||
}
|
||||
else // unexpected trail surrogate
|
||||
{
|
||||
*pErrorCode = ERROR_NO_UNICODE_TRANSLATION; // lone surrogate at end
|
||||
if (destEnd - dest < 3)
|
||||
{
|
||||
*pErrorCode = ERROR_INSUFFICIENT_BUFFER;
|
||||
return 0;
|
||||
}
|
||||
*dest++ = 0xEF;
|
||||
*dest++ = 0xBF;
|
||||
*dest++ = 0xBD;
|
||||
}
|
||||
}
|
||||
if (!*pErrorCode)
|
||||
{
|
||||
*pErrorCode = (dest == destEnd && src != srcEnd) ? ERROR_INSUFFICIENT_BUFFER : ERROR_SUCCESS;
|
||||
}
|
||||
return *pErrorCode == ERROR_INSUFFICIENT_BUFFER ? 0 : cchDest - (destEnd - dest);
|
||||
}
|
||||
|
||||
size_t SystemLocale::Utf8From16Strict( const WCHAR *src, SSIZE_T cchSrc, char *dest, size_t cchDest, DWORD *pErrorCode )
|
||||
{
|
||||
const WCHAR *srcEnd = src + cchSrc;
|
||||
char *destEnd = dest + cchDest;
|
||||
DWORD dummyError;
|
||||
if (!pErrorCode)
|
||||
{
|
||||
pErrorCode = &dummyError;
|
||||
}
|
||||
*pErrorCode = 0;
|
||||
|
||||
// null dest is a special mode to calculate the output size required.
|
||||
if (!dest)
|
||||
{
|
||||
size_t cbOut = 0;
|
||||
while (src < srcEnd)
|
||||
{
|
||||
DWORD wch = *src++;
|
||||
if (wch < 128) // most common case.
|
||||
{
|
||||
cbOut++;
|
||||
}
|
||||
else if (wch < 0x800) // 127 to 2047: 2 bytes
|
||||
{
|
||||
cbOut += 2;
|
||||
}
|
||||
else if (wch < 0xD800 || wch > 0xDFFF) // 2048 to 55295 and 57344 to 65535: 3 bytes
|
||||
{
|
||||
cbOut += 3;
|
||||
}
|
||||
else if (wch < 0xDC00) // 65536 to end of Unicode: 4 bytes
|
||||
{
|
||||
if (src >= srcEnd)
|
||||
{
|
||||
cbOut += 3; // lone surrogate at end
|
||||
}
|
||||
else if (*src < 0xDC00 || *src > 0xDFFF)
|
||||
{
|
||||
cbOut += 3; // low surrogate not followed by high
|
||||
}
|
||||
else
|
||||
{
|
||||
cbOut += 4;
|
||||
}
|
||||
}
|
||||
else // unexpected trail surrogate
|
||||
{
|
||||
cbOut += 3;
|
||||
}
|
||||
}
|
||||
return cbOut;
|
||||
}
|
||||
while ( src < srcEnd && dest < destEnd )
|
||||
{
|
||||
DWORD wch = *src++;
|
||||
if (wch < 128) // most common case.
|
||||
{
|
||||
*dest++ = wch;
|
||||
}
|
||||
else if (wch < 0x800) // 127 to 2047: 2 bytes
|
||||
{
|
||||
if (destEnd - dest < 2)
|
||||
{
|
||||
*pErrorCode = ERROR_INSUFFICIENT_BUFFER;
|
||||
return 0;
|
||||
}
|
||||
*dest++ = 0xC0 | (wch >> 6);
|
||||
*dest++ = 0x80 | (wch & 0x3F);
|
||||
}
|
||||
else if (wch < 0xD800 || wch > 0xDFFF) // 2048 to 55295 and 57344 to 65535: 3 bytes
|
||||
{
|
||||
if (destEnd - dest < 3)
|
||||
{
|
||||
*pErrorCode = ERROR_INSUFFICIENT_BUFFER;
|
||||
return 0;
|
||||
}
|
||||
*dest++ = 0xE0 | (wch >> 12);
|
||||
*dest++ = 0x80 | (wch >> 6)&0x3F;
|
||||
*dest++ = 0x80 | (wch &0x3F);
|
||||
}
|
||||
else if (wch < 0xDC00) // 65536 to end of Unicode: 4 bytes
|
||||
{
|
||||
if (src >= srcEnd)
|
||||
{
|
||||
*pErrorCode = ERROR_NO_UNICODE_TRANSLATION; // lone surrogate at end
|
||||
if (destEnd - dest < 3)
|
||||
{
|
||||
*pErrorCode = ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
if (*src < 0xDC00 || *src > 0xDFFF)
|
||||
{
|
||||
*pErrorCode = ERROR_NO_UNICODE_TRANSLATION; // low surrogate not followed by high
|
||||
if (destEnd - dest < 3)
|
||||
{
|
||||
*pErrorCode = ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
wch = 0x10000 + ((wch - 0xD800)<<10) + *src++ - 0xDC00;
|
||||
if (destEnd - dest < 4)
|
||||
{
|
||||
*pErrorCode = ERROR_INSUFFICIENT_BUFFER;
|
||||
return 0;
|
||||
}
|
||||
*dest++ = 0xF0 | (wch >> 18);
|
||||
*dest++ = 0x80 | (wch >>12)&0x3F;
|
||||
*dest++ = 0x80 | (wch >> 6)&0x3F;
|
||||
*dest++ = 0x80 | wch&0x3F;
|
||||
}
|
||||
else // unexpected trail surrogate
|
||||
{
|
||||
*pErrorCode = ERROR_NO_UNICODE_TRANSLATION; // lone surrogate at end
|
||||
if (destEnd - dest < 3)
|
||||
{
|
||||
*pErrorCode = ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (!*pErrorCode)
|
||||
{
|
||||
*pErrorCode = (dest == destEnd && src != srcEnd) ? ERROR_INSUFFICIENT_BUFFER : ERROR_SUCCESS;
|
||||
}
|
||||
return *pErrorCode == ERROR_INSUFFICIENT_BUFFER ? 0 : cchDest - (destEnd - dest);
|
||||
}
|
||||
|
||||
size_t SystemLocale::FromUtf16( UINT destCodePage, const WCHAR * src, SSIZE_T cchSrc, char * dest, size_t cchDest, bool * pHasDataLoss, DWORD * pErrorCode )
|
||||
{
|
||||
destCodePage = ExpandSpecialCP( destCodePage );
|
||||
if ( destCodePage == CP_UTF8 )
|
||||
{
|
||||
pHasDataLoss && (*pHasDataLoss = 0);
|
||||
return SystemLocale::Utf8From16( src, cchSrc < 0 ? 1+mplat_wcslen(src) : cchSrc, dest, cchDest, pErrorCode );
|
||||
}
|
||||
EncodingConverter cvt( destCodePage, CP_UTF16 );
|
||||
if ( !cvt.Initialize() )
|
||||
{
|
||||
|
@ -384,6 +959,11 @@ size_t SystemLocale::FromUtf16( UINT destCodePage, const WCHAR * src, SSIZE_T cc
|
|||
size_t SystemLocale::FromUtf16Strict(UINT destCodePage, const WCHAR * src, SSIZE_T cchSrc, char * dest, size_t cchDest, bool * pHasDataLoss, DWORD * pErrorCode)
|
||||
{
|
||||
destCodePage = ExpandSpecialCP(destCodePage);
|
||||
if ( destCodePage == CP_UTF8 )
|
||||
{
|
||||
pHasDataLoss && (*pHasDataLoss = 0);
|
||||
return SystemLocale::Utf8From16Strict( src, cchSrc < 0 ? 1+mplat_wcslen(src) : cchSrc, dest, cchDest, pErrorCode );
|
||||
}
|
||||
EncodingConverter cvt(destCodePage, CP_UTF16);
|
||||
if (!cvt.Initialize())
|
||||
{
|
||||
|
|
|
@ -48,7 +48,7 @@ function createTestTable($conn)
|
|||
$column = "col_$i";
|
||||
$dataType = 'money';
|
||||
|
||||
array_push($colMeta, new AE\ColumnMeta($dataType, $column));
|
||||
array_push($colMeta, new AE\ColumnMeta($dataType, $column, null, true, true));
|
||||
}
|
||||
AE\createTable($conn, $tableName, $colMeta);
|
||||
|
||||
|
|
Loading…
Reference in a new issue