mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1035 lines
32 KiB
1035 lines
32 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1994 - 1999
|
|
//
|
|
// File: tblvarnt.hxx
|
|
//
|
|
// Contents: Helper class for PROPVARIANTs in tables
|
|
//
|
|
// Classes: CTableVariant - PROPVARIANT wrapper; adds useful methods
|
|
//
|
|
// History: 28 Jan 1994 AlanW Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma once
|
|
|
|
#include <tblalloc.hxx>
|
|
|
|
|
|
// A few useful defines and inline funcs.
|
|
|
|
#define BSTRLEN(bstrVal) *((ULONG *) bstrVal - 1)
|
|
|
|
inline BOOL IsLPWSTR(VARTYPE vt) { return VT_LPWSTR == vt;}
|
|
inline BOOL IsLPSTR(VARTYPE vt) { return VT_LPSTR == vt;}
|
|
|
|
inline BOOL IsVector(VARTYPE vt) { return 0 != ( vt & VT_VECTOR );}
|
|
inline BOOL IsArray(VARTYPE vt) { return 0 != ( vt & VT_ARRAY );}
|
|
inline BOOL IsVectorOrArray(VARTYPE vt)
|
|
{
|
|
return 0 != ( vt & (VT_VECTOR | VT_ARRAY));
|
|
}
|
|
|
|
inline BOOL StatusSuccess(DBSTATUS status)
|
|
{
|
|
return (status == DBSTATUS_S_OK ||
|
|
status == DBSTATUS_S_ISNULL ||
|
|
status == DBSTATUS_S_TRUNCATED ||
|
|
status == DBSTATUS_S_DEFAULT);
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Class: CTableVariant
|
|
//
|
|
// Purpose: Wraps PROPVARIANT struct, adding useful methods.
|
|
//
|
|
// Interface:
|
|
//
|
|
// Notes: Because the underlying base data *is* a variant, this
|
|
// class cannot have any non-static members (including
|
|
// a vtable).
|
|
//
|
|
// This class now deals only with PROPVARIANT. If conversion
|
|
// to other OLE-DB types or Automation variant types is needed,
|
|
// use COLEDBVaraint class (which derives from this class).
|
|
//
|
|
// The class is also used to extend the PROPVARIANT for use
|
|
// internally in tables. For internal storage, the
|
|
// PROPVARIANT.reserved2 field is used to store the total
|
|
// size of variable data pointed to by the variant.
|
|
// Also, the pointers within internal variants may
|
|
// be offsets to storage. There are three cases of
|
|
// the way offsets may be stored.
|
|
//
|
|
// The pointer inside the internal variant structure
|
|
// itself (to a vector, string, blob or UUID) is an
|
|
// offset based from the variable data allocator used
|
|
// to allocate the space.
|
|
//
|
|
// For vectors which contain pointers (e.g., vectors of
|
|
// strings), the pointers are stored as offsets based from
|
|
// the vector's address.
|
|
//
|
|
// For vectors of variants, the above two rules apply to
|
|
// each embedded variant. The rules apply recursively to
|
|
// embedded variants which are vectors of variant.
|
|
//
|
|
// Use of these rules permits the variable data of a variant
|
|
// to be treated as a unit and to be block copied from place
|
|
// to place without affecting the internally stored offsets.
|
|
//
|
|
// History: 21 Mar 1994 AlanW Created
|
|
// 09 Jan 1998 VikasMan Mofified the class to deal ONLY
|
|
// with PROPVARIANTs. Moved rest of
|
|
// the functionality in the
|
|
// COLEDBVaraiant class
|
|
// 01 Sep 1999 KLam Reinstated FixDataPointers used
|
|
// for Win64 Clients -> Win32 Servers
|
|
// 04 Nov 1999 KLam Added VarDataSize32
|
|
// for Win64 Servers -> Win32 Clients
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
class CTableVariant: public tagPROPVARIANT {
|
|
|
|
public:
|
|
//
|
|
// varntData is indexed by variant type, and gives the width,
|
|
// alignment constraints and other information for a scalar
|
|
// variant type.
|
|
//
|
|
struct VARNT_DATA {
|
|
USHORT width; // width in bytes of data
|
|
USHORT alignment; // required alignment of data
|
|
USHORT flags; // flags about variants
|
|
};
|
|
static const VARNT_DATA varntData[], varntExtData[];
|
|
static const unsigned cVarntData, cVarntExtData;
|
|
|
|
#ifdef _WIN64
|
|
static const VARNT_DATA varntData32[], varntExtData32[];
|
|
#endif
|
|
|
|
enum varntDataFlags {
|
|
CanBeVector = 1, // vector forms are permitted
|
|
ByRef = 2, // variant data has pointer to real data
|
|
CntRef = 4, // variant data has count followed by pointer
|
|
StoreDirect = 8, // variant form is indirect, store as fixed
|
|
MultiSize = 0x10, // used for chapters and bookmarks, for data
|
|
// like UI1 that is inline in client output
|
|
SimpleType = 0x20, // simple inline datatype, like VT_I4
|
|
OAType = 0x40, // valid type for automation VARIANT
|
|
};
|
|
|
|
static BOOL IsSimpleType( VARTYPE vtype )
|
|
{
|
|
const VARNT_DATA & rvarInfo = _FindVarType( vtype );
|
|
|
|
return ( 0 != ( rvarInfo.flags & SimpleType ) );
|
|
}
|
|
|
|
static BOOL IsSimpleOAType( VARTYPE vtype )
|
|
{
|
|
const VARNT_DATA & rvarInfo = _FindVarType( vtype );
|
|
|
|
return ( (SimpleType|OAType) == ( rvarInfo.flags & (SimpleType|OAType ) ) );
|
|
}
|
|
|
|
static BOOL CanBeVectorType( VARTYPE vtype )
|
|
{
|
|
const VARNT_DATA & rvarInfo = _FindVarType( vtype );
|
|
|
|
return ( 0 != ( rvarInfo.flags & CanBeVector ) );
|
|
}
|
|
|
|
// NOTE: in NT5, VARIANT can include additional types. This operates on
|
|
// the traditional types so old clients can understand the variants
|
|
// we produce.
|
|
static BOOL IsOAType( VARTYPE vtype )
|
|
{
|
|
const VARNT_DATA & rvarInfo = _FindVarType( vtype );
|
|
|
|
return ( 0 != ( rvarInfo.flags & OAType ) );
|
|
}
|
|
|
|
static BOOL IsByRef( VARTYPE vtype )
|
|
{
|
|
const VARNT_DATA & rvarInfo = _FindVarType( vtype );
|
|
return ( 0 != ( rvarInfo.flags & ByRef ) );
|
|
}
|
|
|
|
//
|
|
// Return information about a variant's base type
|
|
//
|
|
static void VartypeInfo(VARTYPE vtype, USHORT& rcbWidth,
|
|
USHORT& rcbAlign, USHORT& rgfFlags) {
|
|
const VARNT_DATA& rvarInfo = _FindVarType(vtype);
|
|
|
|
rcbWidth = rvarInfo.width;
|
|
rcbAlign = rvarInfo.alignment;
|
|
rgfFlags = rvarInfo.flags;
|
|
|
|
if (vtype & VT_VECTOR) {
|
|
rgfFlags |= CntRef;
|
|
}
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Check if a type is stored in-line in a table row.
|
|
//
|
|
static BOOL TableIsStoredInline( USHORT fFlags, VARTYPE vtype )
|
|
{
|
|
if (vtype & (VT_ARRAY | VT_VECTOR | VT_BYREF) ||
|
|
vtype == VT_VARIANT ||
|
|
(fFlags & (CntRef | ByRef) && ! (fFlags & StoreDirect)))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void Free(BYTE * pbData,
|
|
VARTYPE vtData,
|
|
PVarAllocator & rPool);
|
|
|
|
//
|
|
// Return TRUE iff the variant's type is valid for a property.
|
|
//
|
|
BOOL IsValidType(void) const
|
|
{
|
|
// NOTE: we don't expect VT_BYREF in our stored variants
|
|
if ( (vt & ~(VT_TYPEMASK | VT_VECTOR | VT_ARRAY)) != 0 ||
|
|
(vt & (VT_VECTOR | VT_ARRAY)) == (VT_VECTOR | VT_ARRAY) )
|
|
return FALSE;
|
|
|
|
const VARNT_DATA& rvarInfo = _FindVarType(vt);
|
|
|
|
if (vt & VT_VECTOR)
|
|
return ((rvarInfo.flags & CanBeVector) == CanBeVector);
|
|
|
|
if (vt & VT_ARRAY)
|
|
return ((rvarInfo.flags & (OAType|CanBeVector)) != 0);
|
|
|
|
return rvarInfo.width != 0;
|
|
}
|
|
|
|
//
|
|
// Return TRUE iff the variant contains a pointer at offset 8
|
|
//
|
|
BOOL VariantPointerInFirstWord (void) const
|
|
{
|
|
return ( (vt & (VT_ARRAY | VT_BYREF)) != 0 ||
|
|
( (vt & VT_VECTOR) == 0 &&
|
|
(_FindVarType(vt).flags & ByRef) == ByRef) );
|
|
// return ((vt == VT_CLSID) ||
|
|
// (vt == VT_LPWSTR) ||
|
|
// (vt == VT_LPSTR) ||
|
|
// (vt == VT_BSTR) ||
|
|
// (vt == VT_CF) ||
|
|
// (vt == VT_STREAM) ||
|
|
// (vt == VT_STREAMED_OBJECT) ||
|
|
// (vt == VT_STORAGE) ||
|
|
// (vt == VT_STORED_OBJECT));
|
|
}
|
|
|
|
//
|
|
// Return TRUE iff the variant contains a pointer at offset 0xC
|
|
//
|
|
BOOL VariantPointerInSecondWord (void) const
|
|
{
|
|
return ( (vt & VT_VECTOR) == VT_VECTOR ||
|
|
( (vt & (VT_ARRAY | VT_BYREF)) == 0 &&
|
|
(_FindVarType(vt).flags & CntRef) == CntRef) );
|
|
}
|
|
|
|
//
|
|
// Copy data stored outside the variant structure itself
|
|
//
|
|
|
|
void Copy( CTableVariant* pvarntDest,
|
|
PVarAllocator &rVarAllocator,
|
|
USHORT cbDest,
|
|
BYTE* pbBias = 0) const;
|
|
|
|
void OffsetsToPointers(PVarAllocator &rPool)
|
|
{
|
|
if ( VariantPointerInFirstWord() )
|
|
pszVal = (LPSTR) rPool.OffsetToPointer((ULONG_PTR) pszVal);
|
|
else if ( VariantPointerInSecondWord() )
|
|
blob.pBlobData = (BYTE *) rPool.OffsetToPointer((ULONG_PTR) blob.pBlobData);
|
|
}
|
|
|
|
DBSTATUS CopyOrCoerce( BYTE * pbDest,
|
|
DBLENGTH cbDest,
|
|
VARTYPE vtDest,
|
|
DBLENGTH & rcbDstLen,
|
|
PVarAllocator & rVarAllocator) const;
|
|
|
|
//
|
|
// Compute variable data size
|
|
//
|
|
ULONG VarDataSize (void) const;
|
|
|
|
#ifdef _WIN64
|
|
//
|
|
// Convert offsets to pointers in variable data (32server->64client)
|
|
//
|
|
void FixDataPointers( BYTE* pbBias, CFixedVarAllocator *pAlloc );
|
|
|
|
//
|
|
// Compute variable data size for 32 bit
|
|
//
|
|
ULONG VarDataSize32 ( BYTE *pbBase,
|
|
ULONG_PTR ulpOffset ) const;
|
|
|
|
//
|
|
// Compute the size of a safearray for 32 bit
|
|
//
|
|
static ULONG SaComputeSize32 ( VARTYPE vt,
|
|
SAFEARRAY & saSrc,
|
|
BYTE *pbBase,
|
|
ULONG_PTR ulpOffset );
|
|
|
|
//
|
|
// Return information about a variant's base type
|
|
//
|
|
static void VartypeInfo32( VARTYPE vtype, USHORT& rcbWidth,
|
|
USHORT& rcbAlign, USHORT& rgfFlags) {
|
|
const VARNT_DATA& rvarInfo = _FindVarType32(vtype);
|
|
|
|
rcbWidth = rvarInfo.width;
|
|
rcbAlign = rvarInfo.alignment;
|
|
rgfFlags = rvarInfo.flags;
|
|
|
|
if (vtype & VT_VECTOR) {
|
|
rgfFlags |= CntRef;
|
|
}
|
|
return;
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
// Initialize a variant from base parts
|
|
//
|
|
void Init( VARTYPE vt,
|
|
BYTE* pbData = 0,
|
|
ULONG cbData = 0);
|
|
|
|
protected:
|
|
enum { ulCoercionCodePage = CP_ACP };
|
|
|
|
DBSTATUS _StoreString(BYTE * pbDstBuf,
|
|
DBLENGTH cbDstBuf,
|
|
VARTYPE vtDst,
|
|
DBLENGTH & rcbDstLen,
|
|
PVarAllocator & rPool) const;
|
|
|
|
DBSTATUS _StoreDecimal(DECIMAL * pDecimal,
|
|
LONG lElem = 0) const;
|
|
|
|
DBSTATUS _StoreInteger(VARTYPE vtDst,
|
|
BYTE * pbDstBuf,
|
|
LONG lElem = 0) const;
|
|
DBSTATUS _StoreIntegerUnSignedToSigned( VARTYPE vtDst,
|
|
BYTE * pbDstBuf,
|
|
LONG lElem = 0) const;
|
|
DBSTATUS _StoreIntegerSignedToSigned( VARTYPE vtDst,
|
|
BYTE * pbDstBuf,
|
|
LONG lElem = 0) const;
|
|
DBSTATUS _StoreIntegerUnSignedToUnSigned(VARTYPE vtDst,
|
|
BYTE * pbDstBuf,
|
|
LONG lElem = 0) const;
|
|
DBSTATUS _StoreIntegerSignedToUnSigned( VARTYPE vtDst,
|
|
BYTE * pbDstBuf,
|
|
LONG lElem = 0) const;
|
|
|
|
private:
|
|
void SetDataSize (ULONG cbVarData);
|
|
void ResetDataSize ();
|
|
|
|
VOID * CopyData( PVarAllocator &rVarAllocator,
|
|
USHORT cbDest,
|
|
BYTE* pbBias = 0) const;
|
|
|
|
static const USHORT _wInternalSig;
|
|
inline BOOL _IsInternalVariant( void ) const;
|
|
static inline const VARNT_DATA& _FindVarType( VARTYPE vt );
|
|
|
|
#ifdef _WIN64
|
|
static inline const VARNT_DATA& _FindVarType32( VARTYPE vt );
|
|
#endif
|
|
|
|
DBSTATUS _GetUL8Value(ULONGLONG * ul8Value, LONG lElem = 0L) const;
|
|
DBSTATUS _GetL8Value(LONGLONG * l8Value, LONG lElem = 0L ) const;
|
|
|
|
};
|
|
|
|
const USHORT minExtVariantType = 128;
|
|
|
|
#ifdef _WIN64
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CTableVariant::_FindVarType32, inline private
|
|
//
|
|
// Synopsis: Return a 32 bit description of a variant given its type
|
|
//
|
|
// Arguments: [vt] - the variant type to be looked up
|
|
//
|
|
// Returns: VARNT_DATA& - a reference to the variant type information
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
inline const CTableVariant::VARNT_DATA& CTableVariant::_FindVarType32(
|
|
VARTYPE vtype
|
|
) {
|
|
USHORT vtBase = vtype & VT_TYPEMASK;
|
|
|
|
if (vtBase < cVarntData)
|
|
{
|
|
return varntData32[vtBase];
|
|
}
|
|
else if (vtBase >= minExtVariantType &&
|
|
vtBase < minExtVariantType + cVarntExtData)
|
|
{
|
|
return varntExtData32[ vtBase - minExtVariantType ];
|
|
}
|
|
else
|
|
{
|
|
return varntData32[0]; // return ref. to VT_EMPTY info
|
|
}
|
|
}
|
|
|
|
#endif // _WIN64
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CTableVariant::_FindVarType, inline private
|
|
//
|
|
// Synopsis: Return a description of a variant given its type
|
|
//
|
|
// Arguments: [vt] - the variant type to be looked up
|
|
//
|
|
// Returns: VARNT_DATA& - a reference to the variant type information
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
inline const CTableVariant::VARNT_DATA& CTableVariant::_FindVarType(
|
|
VARTYPE vtype
|
|
) {
|
|
USHORT vtBase = vtype & VT_TYPEMASK;
|
|
|
|
if (vtBase < cVarntData)
|
|
{
|
|
return varntData[vtBase];
|
|
}
|
|
else if (vtBase >= minExtVariantType &&
|
|
vtBase < minExtVariantType + cVarntExtData)
|
|
{
|
|
return varntExtData[ vtBase - minExtVariantType ];
|
|
}
|
|
else
|
|
{
|
|
return varntData[0]; // return ref. to VT_EMPTY info
|
|
}
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CTableVariant::_IsInternalVariant, inline private
|
|
//
|
|
// Synopsis: Return whether the variant is an internal form with
|
|
// pointers stored as offsets and variable data embedded.
|
|
//
|
|
// Arguments: -None-
|
|
//
|
|
// Returns: BOOL - TRUE if the variant is in internal form.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
inline BOOL CTableVariant::_IsInternalVariant(
|
|
void
|
|
) const {
|
|
return (wReserved1 == _wInternalSig &&
|
|
wReserved3 == _wInternalSig &&
|
|
VT_DECIMAL != vt);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CTableVariant::SetDataSize, public
|
|
//
|
|
// Synopsis: Set variable data size for an internal variant
|
|
//
|
|
// Arguments: [cbVarData] - length of variable data associated with
|
|
// the variant.
|
|
//
|
|
// Returns: -Nothing-
|
|
//
|
|
// Notes: For variants which are stored internally in the table,
|
|
// the size is computed once and stored in the wReserved2
|
|
// field of the variant structure.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
inline void CTableVariant::SetDataSize (ULONG cbVarData)
|
|
{
|
|
Win4Assert(cbVarData <= USHRT_MAX);
|
|
|
|
if (vt != VT_DECIMAL) // this uses the reserved fields
|
|
{
|
|
wReserved2 = (USHORT)cbVarData;
|
|
|
|
//
|
|
// Put a signature value in the variant to distinguish internal
|
|
// vs. external variants.
|
|
//
|
|
wReserved1 = wReserved3 = _wInternalSig;
|
|
}
|
|
}
|
|
|
|
|
|
inline void CTableVariant::ResetDataSize ()
|
|
{
|
|
if (vt != VT_DECIMAL)
|
|
wReserved1 = wReserved2 = wReserved3 = 0;
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CTableVariant::_StoreDecimal, private
|
|
//
|
|
// Synopsis: Copy variant integer data, coercing to VT_DECIMAL
|
|
//
|
|
// Arguments: [pDec] -- destination buffer
|
|
// [lElem] -- element of vector to convert
|
|
//
|
|
// Returns: status for copy
|
|
//
|
|
// History: 25 Nov 1996 AlanW Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
inline DBSTATUS CTableVariant::_StoreDecimal( DECIMAL * pDec,
|
|
LONG lElem ) const
|
|
{
|
|
ULONGLONG ul8Value = 0;
|
|
|
|
Win4Assert( (vt & VT_TYPEMASK) != VT_DECIMAL );
|
|
|
|
DBSTATUS DstStatus = _GetUL8Value (&ul8Value, lElem);
|
|
|
|
if (DBSTATUS_S_OK == DstStatus)
|
|
{
|
|
pDec->scale = 0;
|
|
pDec->sign = 0;
|
|
pDec->Hi32 = 0;
|
|
pDec->Lo64 = ul8Value;
|
|
}
|
|
else if ( DBSTATUS_E_CANTCONVERTVALUE == DstStatus )
|
|
{
|
|
LONGLONG l8Value;
|
|
DstStatus = _GetL8Value (&l8Value, lElem);
|
|
|
|
if (DBSTATUS_S_OK == DstStatus)
|
|
{
|
|
pDec->scale = 0;
|
|
pDec->Hi32 = 0;
|
|
if ( l8Value < 0 )
|
|
{
|
|
pDec->sign = DECIMAL_NEG;
|
|
pDec->Lo64 = -l8Value;
|
|
}
|
|
else
|
|
{
|
|
pDec->sign = 0;
|
|
pDec->Lo64 = l8Value;
|
|
}
|
|
}
|
|
}
|
|
|
|
return DstStatus;
|
|
} //_StoreDecimal
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CTableVariant::_StoreIntegerUnSignedToSigned, private
|
|
//
|
|
// Synopsis: Copy variant integer data, coerce if possible
|
|
//
|
|
// Arguments: [vtDst] -- type of the destination
|
|
// [pbDstBuf] -- destination buffer
|
|
// [lElem] -- element of vector to convert
|
|
//
|
|
// Returns: status for copy
|
|
//
|
|
// History: 24 Jul 1995 dlee Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
inline DBSTATUS CTableVariant::_StoreIntegerUnSignedToSigned(
|
|
VARTYPE vtDst,
|
|
BYTE * pbDstBuf,
|
|
LONG lElem ) const
|
|
{
|
|
ULONGLONG ul8Value = 0;
|
|
DBSTATUS DstStatus = _GetUL8Value(&ul8Value, lElem);
|
|
|
|
// Store the ULONGLONG assuming alignment verified at accessor creation
|
|
if (DBSTATUS_S_OK == DstStatus)
|
|
{
|
|
switch ( vtDst )
|
|
{
|
|
case VT_I1 :
|
|
* (signed char *) pbDstBuf = (signed char) ul8Value;
|
|
if ( ul8Value > SCHAR_MAX )
|
|
DstStatus = DBSTATUS_E_DATAOVERFLOW;
|
|
break;
|
|
case VT_I2 :
|
|
* (short *) pbDstBuf = (short) ul8Value;
|
|
if ( ul8Value > SHRT_MAX )
|
|
DstStatus = DBSTATUS_E_DATAOVERFLOW;
|
|
break;
|
|
case VT_I4 :
|
|
case VT_INT :
|
|
* (long *) pbDstBuf = (long) ul8Value;
|
|
if ( ul8Value > LONG_MAX )
|
|
DstStatus = DBSTATUS_E_DATAOVERFLOW;
|
|
break;
|
|
case VT_I8 :
|
|
* (LONGLONG *) pbDstBuf = (LONGLONG) ul8Value;
|
|
if ( ul8Value > _I64_MAX )
|
|
DstStatus = DBSTATUS_E_DATAOVERFLOW;
|
|
break;
|
|
default:
|
|
//tbDebugOut(( DEB_WARN, "US bad dst type %4x\n", vtDst ));
|
|
DstStatus = DBSTATUS_E_CANTCONVERTVALUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return DstStatus;
|
|
} //_StoreIntegerUnSignedToSigned
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CTableVariant::_StoreIntegerUnSignedToUnSigned, private
|
|
//
|
|
// Synopsis: Copy variant integer data, coerce if possible
|
|
//
|
|
// Arguments: [vtDst] -- type of the destination
|
|
// [pbDstBuf] -- destination buffer
|
|
// [lElem] -- element of vector to convert
|
|
//
|
|
// Returns: status for copy
|
|
//
|
|
// History: 24 Jul 1995 dlee Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
inline DBSTATUS CTableVariant::_StoreIntegerUnSignedToUnSigned(
|
|
VARTYPE vtDst,
|
|
BYTE * pbDstBuf,
|
|
LONG lElem ) const
|
|
{
|
|
ULONGLONG ul8Value;
|
|
DBSTATUS DstStatus = _GetUL8Value(&ul8Value, lElem);
|
|
|
|
// Store the ULONGLONG assuming alignment verified at accessor creation
|
|
if (DBSTATUS_S_OK == DstStatus)
|
|
{
|
|
switch ( vtDst )
|
|
{
|
|
case VT_UI1 :
|
|
* (unsigned char *) pbDstBuf = (char) ul8Value;
|
|
if ( ul8Value > UCHAR_MAX )
|
|
DstStatus = DBSTATUS_E_DATAOVERFLOW;
|
|
break;
|
|
|
|
case VT_UI2 :
|
|
* (unsigned short *) pbDstBuf = (unsigned short) ul8Value;
|
|
if ( ul8Value > USHRT_MAX )
|
|
DstStatus = DBSTATUS_E_DATAOVERFLOW;
|
|
break;
|
|
|
|
case VT_UI4 :
|
|
case VT_UINT :
|
|
* (unsigned long *) pbDstBuf = (unsigned long) ul8Value;
|
|
if ( ul8Value > ULONG_MAX )
|
|
DstStatus = DBSTATUS_E_DATAOVERFLOW;
|
|
break;
|
|
|
|
case VT_UI8 :
|
|
* (ULONGLONG *) pbDstBuf = ul8Value;
|
|
break;
|
|
|
|
default:
|
|
//tbDebugOut(( DEB_WARN, "UU bad dst type %4x\n", vtDst ));
|
|
DstStatus = DBSTATUS_E_CANTCONVERTVALUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return DstStatus;
|
|
} //_StoreIntegerUnSignedToUnSigned
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CTableVariant::_StoreIntegerSignedToUnSigned, private
|
|
//
|
|
// Synopsis: Copy variant integer data, coerce if possible
|
|
//
|
|
// Arguments: [vtDst] -- type of the destination
|
|
// [pbDstBuf] -- destination buffer
|
|
// [lElem] -- element of vector to convert
|
|
//
|
|
// Returns: status for copy
|
|
//
|
|
// History: 24 Jul 1995 dlee Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
inline DBSTATUS CTableVariant::_StoreIntegerSignedToUnSigned(
|
|
VARTYPE vtDst,
|
|
BYTE * pbDstBuf,
|
|
LONG lElem ) const
|
|
{
|
|
LONGLONG l8Value;
|
|
DBSTATUS DstStatus = _GetL8Value( &l8Value, lElem ) ;
|
|
|
|
// Store the LONGLONG assuming alignment verified at accessor creation
|
|
if (DBSTATUS_S_OK == DstStatus)
|
|
{
|
|
if ( l8Value < 0 )
|
|
DstStatus = DBSTATUS_E_SIGNMISMATCH;
|
|
else
|
|
{
|
|
switch ( vtDst )
|
|
{
|
|
case VT_UI1 :
|
|
* (unsigned char *) pbDstBuf = (unsigned char) l8Value;
|
|
if ( l8Value > UCHAR_MAX )
|
|
DstStatus = DBSTATUS_E_DATAOVERFLOW;
|
|
break;
|
|
case VT_UI2 :
|
|
* (unsigned short *) pbDstBuf = (unsigned short) l8Value;
|
|
if ( l8Value > USHRT_MAX )
|
|
DstStatus = DBSTATUS_E_DATAOVERFLOW;
|
|
break;
|
|
case VT_UI4 :
|
|
case VT_UINT :
|
|
* (unsigned long *) pbDstBuf = (unsigned long) l8Value;
|
|
if ( l8Value > ULONG_MAX )
|
|
DstStatus = DBSTATUS_E_DATAOVERFLOW;
|
|
break;
|
|
case VT_UI8 :
|
|
* (ULONGLONG *) pbDstBuf = (ULONGLONG) l8Value;
|
|
break;
|
|
default:
|
|
//tbDebugOut(( DEB_WARN, "SU bad dst type %4x\n", vtDst ));
|
|
DstStatus = DBSTATUS_E_CANTCONVERTVALUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return DstStatus;
|
|
} //_StoreIntegerSignedToUnSigned
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CTableVariant::_StoreIntegerSignedToSigned, private
|
|
//
|
|
// Synopsis: Copy variant integer data, coerce if possible
|
|
//
|
|
// Arguments: [vtDst] -- type of the destination
|
|
// [pbDstBuf] -- destination buffer
|
|
// [lElem] -- element of vector to convert
|
|
//
|
|
// Returns: status for copy
|
|
//
|
|
// History: 24 Jul 1995 dlee Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
inline DBSTATUS CTableVariant::_StoreIntegerSignedToSigned(
|
|
VARTYPE vtDst,
|
|
BYTE * pbDstBuf,
|
|
LONG lElem ) const
|
|
{
|
|
LONGLONG l8Value = 0;
|
|
DBSTATUS DstStatus = _GetL8Value ( &l8Value, lElem );
|
|
|
|
|
|
// Store the ULONGLONG assuming alignment verified at accessor creation
|
|
if (DBSTATUS_S_OK == DstStatus)
|
|
{
|
|
switch ( vtDst )
|
|
{
|
|
case VT_I1 :
|
|
* (signed char *) pbDstBuf = (signed char) l8Value;
|
|
if (l8Value < SCHAR_MIN || l8Value > SCHAR_MAX)
|
|
DstStatus = DBSTATUS_E_DATAOVERFLOW;
|
|
break;
|
|
case VT_I2 :
|
|
* (short *) pbDstBuf = (short) l8Value;
|
|
if (l8Value < SHRT_MIN || l8Value > SHRT_MAX)
|
|
DstStatus = DBSTATUS_E_DATAOVERFLOW;
|
|
break;
|
|
case VT_I4 :
|
|
* (long *) pbDstBuf = (long) l8Value;
|
|
if (l8Value < LONG_MIN || l8Value > LONG_MAX)
|
|
DstStatus = DBSTATUS_E_DATAOVERFLOW;
|
|
break;
|
|
case VT_I8 :
|
|
* (LONGLONG *) pbDstBuf = l8Value;
|
|
break;
|
|
default:
|
|
//tbDebugOut(( DEB_WARN, "SS bad dst type %4x\n", vtDst ));
|
|
DstStatus = DBSTATUS_E_CANTCONVERTVALUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return DstStatus;
|
|
} //_StoreIntegerSignedToSigned
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CTableVariant::_StoreInteger, private
|
|
//
|
|
// Synopsis: Copy variant integer data, coerce if possible
|
|
//
|
|
// Arguments: [vtDst] -- type of the destination
|
|
// [pbDstBuf] -- destination buffer
|
|
// [lElem] -- element of vector to convert
|
|
//
|
|
// Returns: status for copy
|
|
//
|
|
// History: 24 Jul 1995 dlee Rewrote to support unsigned values
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
inline BOOL isSignedInteger( VARTYPE vt )
|
|
{
|
|
return ( VT_I1 == vt ||
|
|
VT_I2 == vt ||
|
|
VT_I4 == vt ||
|
|
VT_INT == vt ||
|
|
VT_I8 == vt ||
|
|
VT_BOOL == vt );
|
|
} //isSignedInteger
|
|
|
|
inline DBSTATUS CTableVariant::_StoreInteger(
|
|
VARTYPE vtDst,
|
|
BYTE * pbDstBuf,
|
|
LONG lElem ) const
|
|
{
|
|
// vt is the type of the source of the data
|
|
|
|
Win4Assert( vt == VT_I1 ||
|
|
vt == VT_UI1 ||
|
|
vt == VT_I2 ||
|
|
vt == VT_UI2 ||
|
|
vt == VT_I4 ||
|
|
vt == VT_UI4 ||
|
|
vt == VT_I8 ||
|
|
vt == VT_UI8 ||
|
|
vt == VT_INT ||
|
|
vt == VT_UINT ||
|
|
vt == VT_BOOL ||
|
|
vt == VT_ERROR ||
|
|
vt == VT_HRESULT ||
|
|
vt == VT_FILETIME ||
|
|
vt == VT_EMPTY || // empty if object is deleted
|
|
vt == (VT_I1 | VT_VECTOR) ||
|
|
vt == (VT_UI1 | VT_VECTOR) ||
|
|
vt == (VT_I2 | VT_VECTOR) ||
|
|
vt == (VT_UI2 | VT_VECTOR) ||
|
|
vt == (VT_I4 | VT_VECTOR) ||
|
|
vt == (VT_UI4 | VT_VECTOR) ||
|
|
vt == (VT_I8 | VT_VECTOR) ||
|
|
vt == (VT_UI8 | VT_VECTOR) ||
|
|
vt == (VT_BOOL | VT_VECTOR) ||
|
|
vt == (VT_ERROR | VT_VECTOR) ||
|
|
vt == (VT_FILETIME | VT_VECTOR));
|
|
|
|
BOOL fSrcSigned = isSignedInteger( vt & VT_TYPEMASK );
|
|
BOOL fDstSigned = isSignedInteger( vtDst );
|
|
|
|
if ( fSrcSigned && fDstSigned )
|
|
return _StoreIntegerSignedToSigned( vtDst, pbDstBuf, lElem );
|
|
else if ( fSrcSigned && !fDstSigned )
|
|
return _StoreIntegerSignedToUnSigned( vtDst, pbDstBuf, lElem );
|
|
else if ( !fSrcSigned && fDstSigned )
|
|
return _StoreIntegerUnSignedToSigned( vtDst, pbDstBuf, lElem );
|
|
else
|
|
return _StoreIntegerUnSignedToUnSigned( vtDst, pbDstBuf, lElem );
|
|
|
|
} //_StoreInteger
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CTableVariant::_GetL8Value, private
|
|
//
|
|
// Synopsis: Converts the variant value to a LONGLONG
|
|
//
|
|
// Arguments: [*l8Value] - LONGLONG value on return
|
|
// [lElem] - for vector variants, the element whose value is
|
|
// to be converted
|
|
//
|
|
// Returns: DBSTATUS
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
inline DBSTATUS CTableVariant::_GetL8Value(LONGLONG * l8Value, LONG lElem ) const
|
|
{
|
|
*l8Value = 0;
|
|
DBSTATUS DstStatus = DBSTATUS_S_OK;
|
|
|
|
Win4Assert((lElem == 0) || (vt & DBTYPE_VECTOR));
|
|
|
|
switch ( vt ) // type of the source
|
|
{
|
|
case VT_I1:
|
|
*l8Value = (CHAR)bVal;
|
|
break;
|
|
|
|
case VT_I2:
|
|
case VT_BOOL:
|
|
*l8Value = iVal;
|
|
break;
|
|
|
|
case VT_I4:
|
|
case VT_INT :
|
|
*l8Value = lVal;
|
|
break;
|
|
|
|
case VT_I8:
|
|
*l8Value = hVal.QuadPart;
|
|
break;
|
|
|
|
case VT_EMPTY:
|
|
case VT_NULL :
|
|
DstStatus = DBSTATUS_S_ISNULL;
|
|
break;
|
|
|
|
case VT_I1 | VT_VECTOR: // no i1 vector struct definition use UI1 and cast
|
|
*l8Value = (CHAR)caub.pElems[lElem];
|
|
break;
|
|
|
|
case VT_I2 | VT_VECTOR:
|
|
*l8Value = cai.pElems[lElem];
|
|
break;
|
|
|
|
case VT_I4 | VT_VECTOR:
|
|
*l8Value = cal.pElems[lElem];
|
|
break;
|
|
|
|
case VT_I8 | VT_VECTOR:
|
|
*l8Value = cah.pElems[lElem].QuadPart;
|
|
break;
|
|
|
|
default:
|
|
//tbDebugOut(( DEB_WARN, "_GetL8Value bad src type %4x\n", vt ));
|
|
DstStatus = DBSTATUS_E_CANTCONVERTVALUE;
|
|
break;
|
|
}
|
|
return DstStatus;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CTableVariant::_GetUL8Value, private
|
|
//
|
|
// Synopsis: Converts the variant value to a ULONGLONG
|
|
//
|
|
// Arguments: [*ul8Value] - ULONGLONG value on return
|
|
// [lElem] - for vector variants, the element whose value is
|
|
// to be converted
|
|
//
|
|
// Returns: DBSTATUS
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
inline DBSTATUS CTableVariant::_GetUL8Value(ULONGLONG * ul8Value, LONG lElem ) const
|
|
{
|
|
*ul8Value = 0;
|
|
DBSTATUS DstStatus = DBSTATUS_S_OK;
|
|
|
|
Win4Assert((lElem == 0) || (vt & DBTYPE_VECTOR));
|
|
|
|
switch ( vt ) // type of the source
|
|
{
|
|
case VT_UI1:
|
|
*ul8Value = bVal;
|
|
break;
|
|
|
|
case VT_UI2:
|
|
*ul8Value = uiVal;
|
|
break;
|
|
|
|
case VT_UI4:
|
|
case VT_UINT :
|
|
case VT_ERROR :
|
|
case VT_HRESULT :
|
|
*ul8Value = ulVal;
|
|
break;
|
|
|
|
case VT_UI8:
|
|
case VT_FILETIME :
|
|
*ul8Value = uhVal.QuadPart;
|
|
break;
|
|
|
|
case VT_EMPTY:
|
|
case VT_NULL :
|
|
DstStatus = DBSTATUS_S_ISNULL;
|
|
break;
|
|
|
|
case VT_UI1 | VT_VECTOR:
|
|
*ul8Value = caub.pElems[lElem];
|
|
break;
|
|
|
|
case VT_UI2 | VT_VECTOR:
|
|
*ul8Value = caui.pElems[lElem];
|
|
break;
|
|
|
|
case VT_BOOL | VT_VECTOR :
|
|
*ul8Value = cabool.pElems[lElem];
|
|
break;
|
|
|
|
case VT_UI4 | VT_VECTOR:
|
|
*ul8Value = caul.pElems[lElem];
|
|
break;
|
|
|
|
case VT_ERROR | VT_VECTOR:
|
|
*ul8Value = cascode.pElems[lElem];
|
|
break;
|
|
|
|
case VT_UI8 | VT_VECTOR:
|
|
*ul8Value = cauh.pElems[lElem].QuadPart;
|
|
break;
|
|
|
|
case VT_FILETIME | VT_VECTOR:
|
|
*ul8Value = ((ULARGE_INTEGER *)(&cafiletime.pElems[lElem]))->QuadPart;
|
|
break;
|
|
|
|
default:
|
|
//tbDebugOut(( DEB_WARN, "_GetUL8Value bad src type %4x\n", vt ));
|
|
DstStatus = DBSTATUS_E_CANTCONVERTVALUE;
|
|
break;
|
|
}
|
|
return DstStatus;
|
|
|
|
}
|