blob: 1f6c5c56aaf22888821d45b741eea2efbe0af1eb [file] [log] [blame]
/**********************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
********************************************************************/
/**************************************************************************
**************************************************************************/
//
// MODULE: NSKIEEE.cpp
//
//
// Purpose: Routines to convert between t16 float and ieee float.
//
// Compaq 64-bit float format :
// +--------------------------------------------------+
// |s| mantissa | exp |
// +--------------------------------------------------+
// 1 54 9
//
// Compaq 32-bit float format :
// +--------------------------------------+
// |s| mantissa | exp |
// +--------------------------------------+
// 1 22 9
//
// IEEE 64-bit float format :
// +--------------------------------------------------+
// |s| exp | mantissa |
// +--------------------------------------------------+
// 1 11 52
//
//IEEE 32-bit float format :
// +--------------------------------------+
// |s| exp | mantissa |
// +--------------------------------------+
// 1 8 23
//
// Compaq float exponent is expressed as an excessed-256 value
// (biased by 256).
// The exponent range is between -256 to +255.
//
// IEEE float exponent is also biased. The exponent bias is 1023
// for double (64 bits) format and 127 for single (32 bits) format.
//
//-----------------------------------------------------------------
#include <windows.h>
#include <sqltypes.h>
#include <sqlExt.h>
#include "sqlcli.h"
#include "NSKIEEE.h"
#include "DrvrSrvr.h"
#ifdef NSK_PLATFORM
#include "kfpconv.h"
#endif
#define IEEE_EXPONENT_BIAS 1023
#define T16_EXPONENT_BIAS 256
#define BIAS_DIFFERENCE 767 // 1023 - 256 = 767
#define IEEE_EXPONENT_BIAS_S 127 // single format
#define BIAS_DIFFERENCE_S -129 // 127 - 256 = -129
//----------------------------------------------------------------
// If the source length is not an even number, no swapping will
// be performed. No error is generated in this function.
// IN/OUT : source/target, IN : swap length
//----------------------------------------------------------------
void ODBC::byte_swap(BYTE *source, long source_len)
{
#ifndef NSK_PLATFORM
BYTE *target;
BYTE temp;
short i;
if (!(source_len % 2))
{
for (i = 1, target = source; i <= source_len /2; i++)
{
temp = source[i-1];
target[i-1] = source[source_len - i];
source[source_len -i] = temp;
}
}
#endif
} // byte_swap
// The following byte order inversion routines were written by Dale Rempert. They are
// specific to the 80x86 processors. Even though the external representation is little endian
// the internal representation is big endian. Here is how these routines work. Take a short
// in big endian say 0xCDAB. When read by the processor it "sees" the value 0xABCD. We rotate
// this value by 8 bits yealding 0xCDAB. Then written out to memory we get 0xABCD. For 4 & 8
// byte values I read two byes at a time and build one or two 4 byte "longs" then write out the
// longs. This minimizes the reads/writes to slower memory, and if the compiler is nice will
// keep the temps in registers. Though some compilers will not do this if a routine contains
// inline assembly statements.
// Note the only reasonable sizes for endian inversion are 2, 4, and 8 bytes.
// byte_swap a 16 bit field (i.e. 2 bytes)
void ODBC::byte_swap_2(BYTE *source)
{
#if defined(NSK_PLATFORM)
return;
#endif
#if defined(WIN32) && !defined(_WIN64)
unsigned short tmp;
tmp = *(unsigned short *)source;
_asm rol tmp,8
*(unsigned short *)source = tmp;
#endif
#if defined(_WIN64)
byte_swap(source,2);
#endif
}
// byte_swap a 32 bit field (i.e. 4 bytes)
void ODBC::byte_swap_4(BYTE *source)
{
#if defined(NSK_PLATFORM)
return;
#endif
#if defined(WIN32) && !defined(_WIN64)
unsigned long t32;
unsigned short t16;
t16 = *(unsigned short *)source;
_asm rol t16,8
t32 = ((unsigned long)t16) << 16;
t16 = *(short *)(source+2);
_asm rol t16,8
t32 |= (unsigned long)t16;
*(unsigned long *)source = t32;
#endif
#if defined(_WIN64)
byte_swap(source,4);
#endif
}
// byte_swap a 64 bit field (i.e. 8 bytes)
// 0x1122334455667788 => 0x8877665544332211
void ODBC::byte_swap_8(BYTE *source)
{
#if defined(NSK_PLATFORM)
return;
#endif
#if defined(WIN32) && !defined(_WIN64)
unsigned long t32a, t32b;
unsigned short t16;
t16 = *(unsigned short *)source; // 0x2211
_asm rol t16,8 // 0x1122
t32a = ((unsigned long)t16) << 16; // 0x11220000
t16 = *(unsigned short *)(source+2); // 0x4433
_asm rol t16,8 // 0x3344
t32a |= (unsigned long)t16; // 0x11223344
t16 = *(unsigned short *)(source+4); // 0x6655
_asm rol t16,8 // 0x5566
t32b = ((unsigned long)t16) << 16; // 0x55660000
t16 = *(unsigned short *)(source+6); // 0x8877
_asm rol t16,8 // 0x7788
t32b |= (unsigned long)t16; // 0x55667788
*(unsigned long *)source = t32b; // 0x88776655
*(unsigned long *)(source+4) = t32a; // 0x44332211
#endif
#if defined(_WIN64)
byte_swap(source,8);
#endif
}
// byte swap a string of chars in unicode UCS2 or any other chars in
// fixed two byte representation.
void ODBC::byte_swap_string(BYTE *source, long source_len)
{
#if !defined(NSK_PLATFORM)
unsigned short *target;
int i;
unsigned short tmp;
target = (unsigned short *)source;
for (i = source_len /2; i > 0; i--)
{
tmp = *target;
#if defined(WIN32) && !defined(_WIN64)
_asm rol tmp,8
#endif
#if defined(_WIN64)
byte_swap((BYTE*)&tmp,2);
#endif
*target++ = tmp;
}
#endif
} // byte_swap_string
//--------------------------------------------------------------------
// Convert T16 64-bit float to IEEE float.
// IN : T16 floating number, OUT: IEEE float
// For alignment reason, this is not declared as long long *.
//--------------------------------------------------------------------
short ODBC::conv_float64_to_ieee_d (BYTE *op)
{
unsigned int exp; // exponent
BYTE rop[8];
BYTE *exp1;
BYTE *exp2;
// Get exponent and sign.
exp = ((op[6] & 0x01) << 8) | op[7];
if (exp == 0)
return (STATUS_OK);
exp = exp + BIAS_DIFFERENCE; //1023 - 256
exp1 = (BYTE *)&exp;
exp2 = exp1 + 1;
rop[0] = (BYTE)((op[0] & 0x80) | (*exp2 << 4) | (*exp1 >> 4));
rop[1] = (BYTE)((*exp1 << 4) | ((op[0] & 0x7F) >> 3)); // RS has to remove the sign
rop[2] = (BYTE)((op[0] << 5) | (op[1] >> 3));
rop[3] = (BYTE)((op[1] << 5) | (op[2] >> 3));
rop[4] = (BYTE)((op[2] << 5) | (op[3] >> 3));
rop[5] = (BYTE)((op[3] << 5) | (op[4] >> 3));
rop[6] = (BYTE)((op[4] << 5) | (op[5] >> 3));
rop[7] = (BYTE)((op[5] << 5) | (op[6] >> 3));
byte_swap(rop, 8);
memcpy(op, rop, 8);
return (STATUS_OK);
} // conv_float64_to_ieee_d
//--------------------------------------------------------------------
// Convert IEEE float to T16 64-bit float.
//--------------------------------------------------------------------
short ODBC::conv_ieee_d_to_float64 (BYTE *op)
{
unsigned int exp; // exponent
BYTE rop[8];
BYTE *exp1;
BYTE *exp2;
byte_swap(op, 8);
// Get exponent and sign.
exp = (((op[0] & 0x7F) << 8 ) | (op[1] & 0xF0)) >> 4;
if (exp == 0)
return (STATUS_OK);
if ((int)exp < (1023 - 256))
return( STATUS_UNDERFLOW);
if ((int)exp > (1023 + 255))
return ( STATUS_OVERFLOW);
exp = exp - BIAS_DIFFERENCE; //1023 - 256
exp1 = (BYTE *)&exp;
exp2 = exp1 + 1;
rop[0] = (BYTE)((op[0] & 0x80) | ((op[1] & 0x0F) << 3) | ((op[2] & 0xE0) >> 5));
rop[1] = (BYTE)((op[2] << 3) | (op[3] >> 5));
rop[2] = (BYTE)((op[3] << 3) | (op[4] >> 5));
rop[3] = (BYTE)((op[4] << 3) | (op[5] >> 5));
rop[4] = (BYTE)((op[5] << 3) | (op[6] >> 5));
rop[5] = (BYTE)((op[6] << 3) | (op[7] >> 5));
rop[6] = (BYTE)((op[7] << 3) | (*exp2));
rop[7] = (BYTE)(*exp1);
memcpy(op, rop, 8);
return (STATUS_OK);
} // conv_ieee_d_to_float64
//--------------------------------------------------------------------
// Convert T16 32-bit float to IEEE float (single format)
// IN : T16 floating number, OUT: IEEE float ,single format.
//--------------------------------------------------------------------
short ODBC::conv_float32_to_ieee_s (BYTE *op )
{
unsigned int exp; // exponent
BYTE rop[4];
// Get exponent.
exp = ((op[2] & 0x01) << 8) | op[3];
if (exp == 0)
return (STATUS_OK);
// Check underflow or overflow, since Tandem has 9-bits exponents
// IEEE has 8-bits exponents.
if ( (int)exp < (127 - 256))
return ( STATUS_UNDERFLOW);
if ( (int)exp > (127 + 255))
return ( STATUS_OVERFLOW);
exp = exp + BIAS_DIFFERENCE_S; // 127 - 256
rop[0] = (BYTE)((op[0] & 0x80) | (exp >> 1));
rop[1] = (BYTE)(((exp & 0x01) << 7) | (op[0] & 0x7F));
rop[2] = op[1];
rop[3] = (BYTE)(op[2] & 0xFE);
byte_swap(rop, 4);
memcpy(op, rop, 4);
return (STATUS_OK);
} // conv_float32_to_ieee
//--------------------------------------------------------------------
// Convert IEEE float to T16 64-bit float.
//--------------------------------------------------------------------
short ODBC::conv_ieee_s_to_float32 (BYTE *op )
{
unsigned int exp; // exponent
BYTE rop[4];
byte_swap(op, 4);
// Get exponent.
exp = ((op[0] & 0x7F) << 1) | ((op[1] & 0x80) >> 7);
if (exp == 0)
return (STATUS_OK);
exp = exp - BIAS_DIFFERENCE_S; // 127 - 256
rop[0] = (BYTE)((op[0] & 0x80) | (op[1] & 0x7F));
rop[1] = (BYTE)(op[2]);
rop[2] = (BYTE)((op[3] & 0xFE) | (exp >> 8));
rop[3] = (BYTE)(exp);
memcpy(op, rop, 4);
return (STATUS_OK);
} // conv_ieee_s_to_float32
//--------------------------------------------------------------------
// Convert depending on datatype.
//--------------------------------------------------------------------
short ODBC::Datatype_Dependent_Swap(BYTE *source, long dataType, SQLINTEGER charSet,long source_len, BOOL tandem_ieee, SQLSMALLINT CDataType)
{
short rst = STATUS_OK;
switch (dataType)
{
case SQLTYPECODE_CHAR:
case SQLTYPECODE_INTERVAL:
//SQL_C_BINARY is specified, swap the data
if ((charSet == SQLCHARSETCODE_UCS2) && (CDataType == SQL_C_BINARY))
byte_swap_string(source, source_len);
break;
case SQLTYPECODE_VARCHAR_WITH_LENGTH:
case SQLTYPECODE_VARCHAR:
case SQLTYPECODE_VARCHAR_LONG:
if ((charSet == SQLCHARSETCODE_UCS2) && (CDataType != SQL_C_BINARY))
*(short*)source = 2 * (*(short *)source);
//SQL_C_BINARY is specified, swap the data
if ((charSet == SQLCHARSETCODE_UCS2) && (CDataType == SQL_C_BINARY))
byte_swap_string(source+2, *(short*)source);
byte_swap_2(source);
break;
case SQLTYPECODE_SMALLINT:
case SQLTYPECODE_SMALLINT_UNSIGNED:
byte_swap_2(source);
break;
case SQLTYPECODE_INTEGER:
case SQLTYPECODE_INTEGER_UNSIGNED:
byte_swap_4(source);
break;
case SQLTYPECODE_LARGEINT:
byte_swap_8(source);
break;
case SQLTYPECODE_IEEE_REAL:
byte_swap_4(source);
break;
case SQLTYPECODE_IEEE_FLOAT:
case SQLTYPECODE_IEEE_DOUBLE:
byte_swap_8(source);
break;
case SQLTYPECODE_DATETIME:
break;
case SQLTYPECODE_DECIMAL_UNSIGNED:
case SQLTYPECODE_DECIMAL:
case SQLTYPECODE_DECIMAL_LARGE_UNSIGNED: // Tandem extension
case SQLTYPECODE_DECIMAL_LARGE: // Tandem extension
break;
case SQLTYPECODE_NUMERIC: //2
case SQLTYPECODE_NUMERIC_UNSIGNED: //-201
byte_swap_bignum(source, source_len);
break;
default:
byte_swap(source, source_len);
break;
}
return (rst);
}
#ifdef NSK_PLATFORM
short ODBC::Datatype_Dependent_Convert(BYTE *source, long dataType, long source_len, BOOL tandem_ieee)
{
uint32 rst = NSK_FLOAT_OK;
return (rst);
}
#endif
void ODBC::SQLDatatype_Dependent_Swap(BYTE *source, long dataType, SQLINTEGER charSet, long dataLength, long DateTimeCode)
{
switch (dataType)
{
case SQLTYPECODE_INTERVAL:
break;
case SQLTYPECODE_CHAR:
if (charSet == SQLCHARSETCODE_UCS2)
byte_swap_string(source,dataLength);
break;
case SQLTYPECODE_VARCHAR_WITH_LENGTH:
case SQLTYPECODE_VARCHAR:
case SQLTYPECODE_VARCHAR_LONG:
byte_swap_2(source);
if (charSet == SQLCHARSETCODE_UCS2)
byte_swap_string(source+2,*(short *)source);
break;
case SQLTYPECODE_SMALLINT:
case SQLTYPECODE_SMALLINT_UNSIGNED:
byte_swap_2(source);
break;
case SQLTYPECODE_INTEGER:
case SQLTYPECODE_INTEGER_UNSIGNED:
byte_swap_4(source);
break;
case SQLTYPECODE_LARGEINT:
byte_swap_8(source);
break;
case SQLTYPECODE_IEEE_REAL:
byte_swap_4(source);
break;
case SQLTYPECODE_IEEE_FLOAT:
case SQLTYPECODE_IEEE_DOUBLE:
byte_swap_8(source);
break;
case SQLTYPECODE_DATETIME:
switch (DateTimeCode)
{
case SQLDTCODE_DATE:
byte_swap((BYTE *)&((DATE_TYPES *)source)->year, 2);
break;
case SQLDTCODE_TIME:
if (dataLength == 7)
byte_swap((BYTE *)&((TIME_TYPES *)source)->fraction, 4);
break;
case SQLDTCODE_TIMESTAMP:
byte_swap((BYTE *)&((TIMESTAMP_TYPES *)source)->year, 2);
if (dataLength == 11)
byte_swap((BYTE *)&((TIMESTAMP_TYPES *)source)->fraction, 4);
break;
}
break;
case SQLTYPECODE_DECIMAL_UNSIGNED:
case SQLTYPECODE_DECIMAL:
case SQLTYPECODE_DECIMAL_LARGE_UNSIGNED: // Tandem extension
case SQLTYPECODE_DECIMAL_LARGE: // Tandem extension
break;
case SQLTYPECODE_NUMERIC: //2
case SQLTYPECODE_NUMERIC_UNSIGNED: //-201
byte_swap_bignum(source, dataLength);
break;
default:
break;
}
}
#ifdef NSK_PLATFORM
short ODBC::SQLDatatype_Dependent_Convert(BYTE *source, long dataType, long DateTimeCode, BOOL tandem_ieee)
{
uint32 rst = NSK_FLOAT_OK;
return (rst);
}
#endif
long ODBC::dataLength(SQLSMALLINT SQLDataType, SQLINTEGER SQLOctetLength, SQLINTEGER SQLCharset, unsigned char* buffer)
{
long allocLength = 0;
switch (SQLDataType)
{
case SQLTYPECODE_CHAR:
case SQLTYPECODE_BIT:
case SQLTYPECODE_VARCHAR:
case SQLTYPECODE_INTERVAL:
allocLength = SQLOctetLength;
break;
case SQLTYPECODE_VARCHAR_WITH_LENGTH:
case SQLTYPECODE_VARCHAR_LONG:
case SQLTYPECODE_BITVAR:
allocLength = *(USHORT *)buffer + 3;
break;
case SQLTYPECODE_SMALLINT:
case SQLTYPECODE_SMALLINT_UNSIGNED:
case SQLTYPECODE_INTEGER:
case SQLTYPECODE_INTEGER_UNSIGNED:
case SQLTYPECODE_LARGEINT:
case SQLTYPECODE_IEEE_REAL:
case SQLTYPECODE_IEEE_FLOAT:
case SQLTYPECODE_IEEE_DOUBLE:
case SQLTYPECODE_DATETIME:
case SQLTYPECODE_DECIMAL_UNSIGNED:
case SQLTYPECODE_DECIMAL:
case SQLTYPECODE_DECIMAL_LARGE_UNSIGNED: // Tandem extension
case SQLTYPECODE_DECIMAL_LARGE: // Tandem extension
default:
allocLength = SQLOctetLength;
break;
}
return allocLength;
}
long ODBC::dataLength(SQLSMALLINT SQLDataType, SQLINTEGER SQLOctetLength, SQLINTEGER SQLCharset, unsigned char* buffer, BOOL out)
{
long allocLength = 0;
switch (SQLDataType)
{
case SQLTYPECODE_CHAR:
case SQLTYPECODE_BIT:
case SQLTYPECODE_VARCHAR:
case SQLTYPECODE_INTERVAL:
allocLength = SQLOctetLength;
break;
case SQLTYPECODE_VARCHAR_WITH_LENGTH:
case SQLTYPECODE_VARCHAR_LONG:
case SQLTYPECODE_BITVAR:
if (out == FALSE)
allocLength = *(USHORT *)buffer + 3;
else
{
short length;
length = *(USHORT *)buffer;
#ifndef NSK_PLATFORM
byte_swap_2((unsigned char*)&length);
#endif
allocLength = length + 2;
}
break;
case SQLTYPECODE_SMALLINT:
case SQLTYPECODE_SMALLINT_UNSIGNED:
case SQLTYPECODE_INTEGER:
case SQLTYPECODE_INTEGER_UNSIGNED:
case SQLTYPECODE_LARGEINT:
case SQLTYPECODE_IEEE_REAL:
case SQLTYPECODE_IEEE_FLOAT:
case SQLTYPECODE_IEEE_DOUBLE:
case SQLTYPECODE_DATETIME:
case SQLTYPECODE_DECIMAL_UNSIGNED:
case SQLTYPECODE_DECIMAL:
case SQLTYPECODE_DECIMAL_LARGE_UNSIGNED: // Tandem extension
case SQLTYPECODE_DECIMAL_LARGE: // Tandem extension
default:
allocLength = SQLOctetLength;
break;
}
return allocLength;
}
long ODBC::dataLengthFetchRowset(SQLSMALLINT SQLDataType, SQLINTEGER SQLOctetLength, SQLINTEGER maxRowLen, SQLINTEGER SQLCharset, unsigned char* buffer)
{
long allocLength = 0;
long maxRowLength = maxRowLen;
switch (SQLDataType)
{
case SQLTYPECODE_VARCHAR_WITH_LENGTH:
case SQLTYPECODE_VARCHAR_LONG:
case SQLTYPECODE_BITVAR:
allocLength = *(USHORT *)buffer + 2;
break;
case SQLTYPECODE_CHAR:
case SQLTYPECODE_BIT:
case SQLTYPECODE_VARCHAR:
allocLength = SQLOctetLength - 1;
if (maxRowLength > 0)
allocLength = (allocLength>maxRowLength)?maxRowLength:allocLength;
break;
default:
allocLength = SQLOctetLength;
break;
}
return allocLength;
}
long ODBC::dataLengthFetchPerf(SQLSMALLINT SQLDataType, SQLINTEGER SQLOctetLength, SQLINTEGER maxRowLen, SQLINTEGER SQLCharset, unsigned char* buffer)
{
long allocLength = 0;
long maxRowLength = maxRowLen;
//
// For UCS2 data, the count always keeps octet unicode length. Total data length = count + sizeof(short) + 1 (null terminator)
//
switch (SQLDataType)
{
case SQLTYPECODE_VARCHAR_WITH_LENGTH:
case SQLTYPECODE_VARCHAR_LONG:
case SQLTYPECODE_BITVAR:
allocLength = *(USHORT *)buffer + 3;
break;
case SQLTYPECODE_CHAR:
case SQLTYPECODE_BIT:
case SQLTYPECODE_VARCHAR:
allocLength = SQLOctetLength;
if (maxRowLength > 0)
allocLength = (allocLength>maxRowLength)?maxRowLength + 1:allocLength;
break;
default:
allocLength = SQLOctetLength;
break;
}
return allocLength;
}
long ODBC::adjustIndexForBulkFetch(SQLSMALLINT SQLDataType, long index)
{
long totalLength = index;
switch (SQLDataType)
{
case SQLTYPECODE_VARCHAR_WITH_LENGTH:
case SQLTYPECODE_VARCHAR_LONG:
totalLength = ((totalLength + 2 - 1) >> 1) << 1;
break;
case SQLTYPECODE_SMALLINT:
case SQLTYPECODE_SMALLINT_UNSIGNED:
totalLength = ((totalLength + 2 - 1) >> 1) << 1;
break;
case SQLTYPECODE_INTEGER:
case SQLTYPECODE_INTEGER_UNSIGNED:
totalLength = ((totalLength + 4 - 1) >> 2) << 2;
break;
case SQLTYPECODE_LARGEINT:
case SQLTYPECODE_IEEE_REAL:
case SQLTYPECODE_IEEE_FLOAT:
case SQLTYPECODE_IEEE_DOUBLE:
case SQLTYPECODE_DATETIME:
totalLength = ((totalLength + 8 - 1) >> 3) << 3;
break;
case SQLTYPECODE_DECIMAL_UNSIGNED:
case SQLTYPECODE_DECIMAL:
case SQLTYPECODE_DECIMAL_LARGE_UNSIGNED: // Tandem extension
case SQLTYPECODE_DECIMAL_LARGE: // Tandem extension
case SQLTYPECODE_INTERVAL: // Treating as CHAR
break;
default:
break;
}
return totalLength;
}
short ODBC::convertFromUCS2(BYTE *source, long dataType, SQLINTEGER charSet, long octetLength)
{
// return values:
// 0 = success,
// -1 = translation failed,
// -2 = translation passed but at least one char was replaced with the default substitution char.
// MAXCHARLEN needs to be big enough to hold the largest multibyte char string.
#ifndef NSK_PLATFORM
#define MAXCHARLEN 8000
char Dest[MAXCHARLEN];
short srcSz;
int rc;
bool DefaultCharRequired;
LPBOOL PtrDefaultCharRequired = (LPBOOL)&DefaultCharRequired;
if (charSet != SQLCHARSETCODE_UCS2) return 0; /* only need to translate unicode data */
switch (dataType)
{
case SQLTYPECODE_CHAR:
case SQLTYPECODE_VARCHAR:
rc = WideCharToMultiByte(CP_ACP,0,
(LPCWSTR)source, octetLength/2,
Dest, MAXCHARLEN,
NULL,PtrDefaultCharRequired);
if (rc != 0)
{
memcpy(source, Dest, rc);
source[rc] = 0;
}
else return -1;
break;
case SQLTYPECODE_VARCHAR_WITH_LENGTH:
case SQLTYPECODE_VARCHAR_LONG:
srcSz = (*(short *)source) / 2;
rc = WideCharToMultiByte(CP_ACP,0,
(LPCWSTR)(source+2),srcSz,
Dest, MAXCHARLEN,
NULL,PtrDefaultCharRequired);
if (rc != 0)
{
//
// in the count field we always keep unicode octet length - we need that to calculate position
// of the next column.
// *(short*)source = rc;
memcpy(source + 2, Dest, rc);
source[rc + 2] = 0;
}
else return -1;
break;
}
return (DefaultCharRequired == true) ? -2 : 0;
#else
return 0;
#endif
}
short ODBC::convertToUCS2(BYTE *source, long dataType, SQLINTEGER charSet, short srcLength, long octetLength)
{
// return values:
// 0 = success,
// -1 = translation failed,
int rc = 0;
// MAXCHARLEN needs to be big enough to hold the largest multibyte char string.
#ifndef NSK_PLATFORM
#define MAXCHARLEN 8000
char Dest[MAXCHARLEN];
if (charSet != SQLCHARSETCODE_UCS2) return 0; /* only need to translate unicode data */
switch (dataType)
{
case SQLTYPECODE_CHAR:
case SQLTYPECODE_VARCHAR:
rc = MultiByteToWideChar(CP_ACP,0,
(const char*)source, octetLength/2,
(LPWSTR)Dest, MAXCHARLEN);
if (rc != 0)
{
if (rc < octetLength/2)
{
rc = MultiByteToWideChar(CP_ACP,0,
(const char*)source, octetLength/2 + (octetLength/2 - rc),
(LPWSTR)Dest, MAXCHARLEN);
}
memcpy(source, Dest, octetLength);
source[octetLength] = 0;
byte_swap_string(source, octetLength);
}
else return -1;
break;
case SQLTYPECODE_VARCHAR_WITH_LENGTH:
case SQLTYPECODE_VARCHAR_LONG:
rc = MultiByteToWideChar(CP_ACP,0,
(const char*)source, srcLength,
(LPWSTR)Dest, MAXCHARLEN);
if (rc != 0)
{
if (rc < srcLength)
{
memcpy(source , Dest, 2 * rc);
source[2 * rc] = 0;
byte_swap_string(source, 2 * rc);
}
else
{
memcpy(source , Dest, 2 * srcLength);
source[2 * srcLength] = 0;
byte_swap_string(source, 2 * srcLength);
}
}
else return -1;
break;
}
#endif
return rc; //sap
}
void ODBC::byte_swap_bignum(BYTE *source, long source_len)
{
#if !defined (NSK_PLATFORM) || !defined (BIGE)
unsigned short *target;
int i;
unsigned short *tmp;
target = (unsigned short *)source;
for (i = source_len /2; i > 0; i--)
{
tmp = target;
if (*tmp != 0 && *tmp != 0xFFFF)
{
union
{
char c[2];
unsigned short j;
} u;
char hold;
u.j = *tmp;
hold = u.c[0];
u.c[0] = u.c[1];
u.c[1] = hold;
*tmp = u.j;
}
*target++ = *tmp;
}
#endif
}