Commit 166e96d1 authored by Jon Griffiths's avatar Jon Griffiths Committed by Alexandre Julliard

Add VarParseNumFromStr()/VarNumFromParseNum(), use them for

conversions. VariantInit(): Only touch V_VT field. VariantClear(): Support IRecordInfo, don't free null bstrs. Add support for upcoming vtypes, remove dead code, docs.
parent 06fd1e25
......@@ -27,8 +27,6 @@
* - The Variant APIs do not support international languages, currency
* types, number formating and calendar. They only support U.S. English format.
* - The Variant APIs do not the following types: IUknown, IDispatch, DECIMAL and SafeArray.
* The prototypes for these are commented out in the oleauto.h file. They need
* to be implemented and cases need to be added to the switches of the existing APIs.
* - The parsing of date for the VarDateFromStr is not complete.
* - The date manipulations do not support dates prior to 1900.
* - The parsing does not accept as many formats as the Windows implementation.
......@@ -55,39 +53,22 @@
#include "winreg.h"
#include "heap.h"
#include "wine/debug.h"
#include "wine/unicode.h"
#include "winerror.h"
#include "parsedt.h"
#include "typelib.h"
#include "winternl.h"
#include "variant.h"
WINE_DEFAULT_DEBUG_CHANNEL(ole);
#define SYSDUPSTRING(str) SysAllocStringByteLen((LPCSTR)(str), SysStringByteLen(str))
#ifndef FLT_MAX
# ifdef MAXFLOAT
# define FLT_MAX MAXFLOAT
# else
# error "Can't find #define for MAXFLOAT/FLT_MAX"
# endif
#endif
/* Flags set in V_VT, other than the actual type value */
#define VT_EXTRA_TYPE (VT_VECTOR|VT_ARRAY|VT_BYREF|VT_RESERVED)
#undef CHAR_MAX
#undef CHAR_MIN
static const char CHAR_MAX = 127;
static const char CHAR_MIN = -128;
static const BYTE UI1_MAX = 255;
static const BYTE UI1_MIN = 0;
static const unsigned short UI2_MAX = 65535;
static const unsigned short UI2_MIN = 0;
static const short I2_MAX = 32767;
static const short I2_MIN = -32768;
static const unsigned long UI4_MAX = 4294967295U;
static const unsigned long UI4_MIN = 0;
static const long I4_MAX = 2147483647;
static const long I4_MIN = -(2147483648U);
static const DATE DATE_MIN = -657434;
static const DATE DATE_MAX = 2958465;
/* Get the extra flags from a variant pointer */
#define V_EXTRA_TYPE(v) (V_VT(v) & VT_EXTRA_TYPE)
/* the largest valid type
*/
......@@ -747,272 +728,6 @@ static double round( double d )
}
/******************************************************************************
* RemoveCharacterFromString [INTERNAL]
*
* Removes any of the characters in "strOfCharToRemove" from the "str" argument.
*/
static void RemoveCharacterFromString( LPSTR str, LPSTR strOfCharToRemove )
{
LPSTR pNewString = NULL;
LPSTR strToken = NULL;
/* Check if we have a valid argument
*/
if( str != NULL )
{
pNewString = strdup( str );
str[0] = '\0';
strToken = strtok( pNewString, strOfCharToRemove );
while( strToken != NULL ) {
strcat( str, strToken );
strToken = strtok( NULL, strOfCharToRemove );
}
free( pNewString );
}
return;
}
/******************************************************************************
* GetValidRealString [INTERNAL]
*
* Checks if the string is of proper format to be converted to a real value.
*/
static BOOL IsValidRealString( LPSTR strRealString )
{
/* Real values that have a decimal point are required to either have
* digits before or after the decimal point. We will assume that
* we do not have any digits at either position. If we do encounter
* some we will disable this flag.
*/
BOOL bDigitsRequired = TRUE;
/* Processed fields in the string representation of the real number.
*/
BOOL bWhiteSpaceProcessed = FALSE;
BOOL bFirstSignProcessed = FALSE;
BOOL bFirstDigitsProcessed = FALSE;
BOOL bDecimalPointProcessed = FALSE;
BOOL bSecondDigitsProcessed = FALSE;
BOOL bExponentProcessed = FALSE;
BOOL bSecondSignProcessed = FALSE;
BOOL bThirdDigitsProcessed = FALSE;
/* Assume string parameter "strRealString" is valid and try to disprove it.
*/
BOOL bValidRealString = TRUE;
/* Used to count the number of tokens in the "strRealString".
*/
LPSTR strToken = NULL;
int nTokens = 0;
LPSTR pChar = NULL;
/* Check if we have a valid argument
*/
if( strRealString == NULL )
{
bValidRealString = FALSE;
}
if( bValidRealString == TRUE )
{
/* Make sure we only have ONE token in the string.
*/
strToken = strtok( strRealString, " " );
while( strToken != NULL ) {
nTokens++;
strToken = strtok( NULL, " " );
}
if( nTokens != 1 )
{
bValidRealString = FALSE;
}
}
/* Make sure this token contains only valid characters.
* The string argument to atof has the following form:
* [whitespace] [sign] [digits] [.digits] [ {d | D | e | E }[sign]digits]
* Whitespace consists of space and|or <TAB> characters, which are ignored.
* Sign is either plus '+' or minus '-'.
* Digits are one or more decimal digits.
* Note: If no digits appear before the decimal point, at least one must
* appear after the decimal point.
* The decimal digits may be followed by an exponent.
* An Exponent consists of an introductory letter ( D, d, E, or e) and
* an optionally signed decimal integer.
*/
pChar = strRealString;
while( bValidRealString == TRUE && *pChar != '\0' )
{
switch( *pChar )
{
/* If whitespace...
*/
case ' ':
case '\t':
if( bWhiteSpaceProcessed ||
bFirstSignProcessed ||
bFirstDigitsProcessed ||
bDecimalPointProcessed ||
bSecondDigitsProcessed ||
bExponentProcessed ||
bSecondSignProcessed ||
bThirdDigitsProcessed )
{
bValidRealString = FALSE;
}
break;
/* If sign...
*/
case '+':
case '-':
if( bFirstSignProcessed == FALSE )
{
if( bFirstDigitsProcessed ||
bDecimalPointProcessed ||
bSecondDigitsProcessed ||
bExponentProcessed ||
bSecondSignProcessed ||
bThirdDigitsProcessed )
{
bValidRealString = FALSE;
}
bWhiteSpaceProcessed = TRUE;
bFirstSignProcessed = TRUE;
}
else if( bSecondSignProcessed == FALSE )
{
/* Note: The exponent must be present in
* order to accept the second sign...
*/
if( bExponentProcessed == FALSE ||
bThirdDigitsProcessed ||
bDigitsRequired )
{
bValidRealString = FALSE;
}
bFirstSignProcessed = TRUE;
bWhiteSpaceProcessed = TRUE;
bFirstDigitsProcessed = TRUE;
bDecimalPointProcessed = TRUE;
bSecondDigitsProcessed = TRUE;
bSecondSignProcessed = TRUE;
}
break;
/* If decimals...
*/
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if( bFirstDigitsProcessed == FALSE )
{
if( bDecimalPointProcessed ||
bSecondDigitsProcessed ||
bExponentProcessed ||
bSecondSignProcessed ||
bThirdDigitsProcessed )
{
bValidRealString = FALSE;
}
bFirstSignProcessed = TRUE;
bWhiteSpaceProcessed = TRUE;
/* We have found some digits before the decimal point
* so disable the "Digits required" flag.
*/
bDigitsRequired = FALSE;
}
else if( bSecondDigitsProcessed == FALSE )
{
if( bExponentProcessed ||
bSecondSignProcessed ||
bThirdDigitsProcessed )
{
bValidRealString = FALSE;
}
bFirstSignProcessed = TRUE;
bWhiteSpaceProcessed = TRUE;
bFirstDigitsProcessed = TRUE;
bDecimalPointProcessed = TRUE;
/* We have found some digits after the decimal point
* so disable the "Digits required" flag.
*/
bDigitsRequired = FALSE;
}
else if( bThirdDigitsProcessed == FALSE )
{
/* Getting here means everything else should be processed.
* If we get anything else than a decimal following this
* digit it will be flagged by the other cases, so
* we do not really need to do anything in here.
*/
}
break;
/* If DecimalPoint...
*/
case '.':
if( bDecimalPointProcessed ||
bSecondDigitsProcessed ||
bExponentProcessed ||
bSecondSignProcessed ||
bThirdDigitsProcessed )
{
bValidRealString = FALSE;
}
bFirstSignProcessed = TRUE;
bWhiteSpaceProcessed = TRUE;
bFirstDigitsProcessed = TRUE;
bDecimalPointProcessed = TRUE;
break;
/* If Exponent...
*/
case 'e':
case 'E':
case 'd':
case 'D':
if( bExponentProcessed ||
bSecondSignProcessed ||
bThirdDigitsProcessed ||
bDigitsRequired )
{
bValidRealString = FALSE;
}
bFirstSignProcessed = TRUE;
bWhiteSpaceProcessed = TRUE;
bFirstDigitsProcessed = TRUE;
bDecimalPointProcessed = TRUE;
bSecondDigitsProcessed = TRUE;
bExponentProcessed = TRUE;
break;
default:
bValidRealString = FALSE;
break;
}
/* Process next character.
*/
pChar++;
}
/* If the required digits were not present we have an invalid
* string representation of a real number.
*/
if( bDigitsRequired == TRUE )
{
bValidRealString = FALSE;
}
return bValidRealString;
}
/******************************************************************************
* Coerce [INTERNAL]
*
* This function dispatches execution to the proper conversion API
......@@ -1795,7 +1510,7 @@ static HRESULT Coerce( VARIANTARG* pd, LCID lcid, ULONG dwFlags, VARIANTARG* ps,
* Used internally by the hi-level Variant API to determine
* if the vartypes are valid.
*/
static HRESULT WINAPI ValidateVtRange( VARTYPE vt )
static HRESULT ValidateVtRange( VARTYPE vt )
{
/* if by value we must make sure it is in the
* range of the valid types.
......@@ -1807,6 +1522,70 @@ static HRESULT WINAPI ValidateVtRange( VARTYPE vt )
return S_OK;
}
/* Copy data from one variant to another. */
static void VARIANT_CopyData(const VARIANT *srcVar, VARTYPE vt, void *pOut)
{
switch(vt)
{
case VT_I1:
case VT_UI1: memcpy(pOut, &V_UI1(srcVar), sizeof(BYTE)); break;
case VT_BOOL:
case VT_I2:
case VT_UI2: memcpy(pOut, &V_UI2(srcVar), sizeof(SHORT)); break;
case VT_R4:
case VT_I4:
case VT_UI4: memcpy(pOut, &V_UI4(srcVar), sizeof (LONG)); break;
case VT_R8:
case VT_DATE:
case VT_CY:
case VT_I8:
case VT_UI8: memcpy(pOut, &V_UI8(srcVar), sizeof (LONG64)); break;
case VT_DECIMAL: memcpy(pOut, &V_DECIMAL(srcVar), sizeof (DECIMAL)); break;
default:
FIXME("VT_ type %d unhandled, please report!\n", vt);
}
}
/* Coerce VT_DISPATCH to another type */
HRESULT VARIANT_FromDisp(IDispatch* pdispIn, LCID lcid, void* pOut, VARTYPE vt)
{
VARIANTARG srcVar, dstVar;
HRESULT hRet;
V_VT(&srcVar) = VT_DISPATCH;
V_DISPATCH(&srcVar) = pdispIn;
hRet = VariantChangeTypeEx(&dstVar, &srcVar, lcid, 0, vt);
if (SUCCEEDED(hRet))
VARIANT_CopyData(&dstVar, vt, pOut);
return hRet;
}
/* Coerce VT_BSTR to a numeric type */
HRESULT VARIANT_NumberFromBstr(OLECHAR* pStrIn, LCID lcid, ULONG ulFlags,
void* pOut, VARTYPE vt)
{
VARIANTARG dstVar;
HRESULT hRet;
NUMPARSE np;
BYTE rgb[1024];
/* Use VarParseNumFromStr/VarNumFromParseNum as MSDN indicates */
np.cDig = sizeof(rgb) / sizeof(BYTE);
np.dwInFlags = NUMPRS_STD;
hRet = VarParseNumFromStr(pStrIn, lcid, ulFlags, &np, rgb);
if (SUCCEEDED(hRet))
{
/* 1 << vt gives us the VTBIT constant for the destination number type */
hRet = VarNumFromParseNum(&np, rgb, 1 << vt, &dstVar);
if (SUCCEEDED(hRet))
VARIANT_CopyData(&dstVar, vt, pOut);
}
return hRet;
}
/******************************************************************************
* ValidateVartype [INTERNAL]
......@@ -1814,7 +1593,7 @@ static HRESULT WINAPI ValidateVtRange( VARTYPE vt )
* Used internally by the hi-level Variant API to determine
* if the vartypes are valid.
*/
static HRESULT WINAPI ValidateVariantType( VARTYPE vt )
static HRESULT ValidateVariantType( VARTYPE vt )
{
HRESULT res = S_OK;
......@@ -1847,7 +1626,7 @@ static HRESULT WINAPI ValidateVariantType( VARTYPE vt )
* Used internally by the hi-level Variant API to determine
* if the vartypes are valid.
*/
static HRESULT WINAPI ValidateVt( VARTYPE vt )
static HRESULT ValidateVt( VARTYPE vt )
{
HRESULT res = S_OK;
......@@ -1874,92 +1653,126 @@ static HRESULT WINAPI ValidateVt( VARTYPE vt )
return res;
}
/******************************************************************************
* Check if a variants type is valid.
*/
static inline HRESULT VARIANT_ValidateType(VARTYPE vt)
{
VARTYPE vtExtra = vt & VT_EXTRA_TYPE;
vt &= VT_TYPEMASK;
if (!(vtExtra & (VT_VECTOR|VT_RESERVED)))
{
if (vt < VT_VOID || vt == VT_RECORD || vt == VT_CLSID)
{
if ((vtExtra & (VT_BYREF|VT_ARRAY)) && vt <= VT_NULL)
return DISP_E_BADVARTYPE;
if (vt != (VARTYPE)15)
return S_OK;
}
}
return DISP_E_BADVARTYPE;
}
/******************************************************************************
* VariantInit [OLEAUT32.8]
*
* Initializes the Variant. Unlike VariantClear it does not interpret
* the current contents of the Variant.
* Initialise a variant.
*
* PARAMS
* pVarg [O] Variant to initialise
*
* RETURNS
* Nothing.
*
* NOTES
* This function simply sets the type of the variant to VT_EMPTY. It does not
* free any existing value, use VariantClear() for that.
*/
void WINAPI VariantInit(VARIANTARG* pvarg)
void WINAPI VariantInit(VARIANTARG* pVarg)
{
TRACE("(%p)\n",pvarg);
TRACE("(%p)\n", pVarg);
memset(pvarg, 0, sizeof (VARIANTARG));
V_VT(pvarg) = VT_EMPTY;
return;
V_VT(pVarg) = VT_EMPTY; /* Native doesn't set any other fields */
}
/******************************************************************************
* VariantClear [OLEAUT32.9]
*
* This function clears the VARIANT by setting the vt field to VT_EMPTY. It also
* sets the wReservedX field to 0. The current contents of the VARIANT are
* freed. If the vt is VT_BSTR the string is freed. If VT_DISPATCH the object is
* released. If VT_ARRAY the array is freed.
* Clear a variant.
*
* PARAMS
* pVarg [I/O] Variant to clear
*
* RETURNS
* Success: S_OK. Any previous value in pVarg is freed and its type is set to VT_EMPTY.
* Failure: DISP_E_BADVARTYPE, if the variant is a not a valid variant type.
*/
HRESULT WINAPI VariantClear(VARIANTARG* pvarg)
HRESULT WINAPI VariantClear(VARIANTARG* pVarg)
{
HRESULT res = S_OK;
TRACE("(%p)\n",pvarg);
HRESULT hres = S_OK;
res = ValidateVariantType( V_VT(pvarg) );
if( res == S_OK )
TRACE("(%p)\n", pVarg);
hres = VARIANT_ValidateType(V_VT(pVarg));
if (SUCCEEDED(hres))
{
if( !( V_VT(pvarg) & VT_BYREF ) )
if (!V_ISBYREF(pVarg))
{
/*
* The VT_ARRAY flag is a special case of a safe array.
*/
if ( (V_VT(pvarg) & VT_ARRAY) != 0)
if (V_ISARRAY(pVarg) || V_VT(pVarg) == VT_SAFEARRAY)
{
SafeArrayDestroy(V_UNION(pvarg,parray));
if (V_ARRAY(pVarg))
hres = SafeArrayDestroy(V_ARRAY(pVarg));
}
else
else if (V_VT(pVarg) == VT_BSTR)
{
switch( V_VT(pvarg) & VT_TYPEMASK )
if (V_BSTR(pVarg))
SysFreeString(V_BSTR(pVarg));
}
else if (V_VT(pVarg) == VT_RECORD)
{
case( VT_BSTR ):
SysFreeString( V_UNION(pvarg,bstrVal) );
break;
case( VT_DISPATCH ):
if(V_UNION(pvarg,pdispVal)!=NULL)
IDispatch_Release(V_UNION(pvarg,pdispVal));
break;
case( VT_VARIANT ):
VariantClear(V_UNION(pvarg,pvarVal));
break;
case( VT_UNKNOWN ):
if(V_UNION(pvarg,punkVal)!=NULL)
IUnknown_Release(V_UNION(pvarg,punkVal));
break;
case( VT_SAFEARRAY ):
SafeArrayDestroy(V_UNION(pvarg,parray));
break;
default:
break;
struct __tagBRECORD* pBr = &V_UNION(pVarg,brecVal);
if (pBr->pRecInfo)
{
IRecordInfo_RecordClear(pBr->pRecInfo, pBr->pvRecord);
IRecordInfo_Release(pBr->pRecInfo);
}
}
else if (V_VT(pVarg) == VT_DISPATCH ||
V_VT(pVarg) == VT_UNKNOWN)
{
if (V_UNKNOWN(pVarg))
IUnknown_Release(V_UNKNOWN(pVarg));
}
/*
* Empty all the fields and mark the type as empty.
*/
memset(pvarg, 0, sizeof (VARIANTARG));
V_VT(pvarg) = VT_EMPTY;
else if (V_VT(pVarg) == VT_VARIANT)
{
if (V_VARIANTREF(pVarg))
VariantClear(V_VARIANTREF(pVarg));
}
return res;
}
V_VT(pVarg) = VT_EMPTY;
}
return hres;
}
/******************************************************************************
* VariantCopy [OLEAUT32.10]
*
* Frees up the designation variant and makes a copy of the source.
* Copy a variant.
*
* PARAMS
* pvargDest [O] Destination for copy
* pvargSrc [I] Source variant to copy
*
* RETURNS
* Success: S_OK. pvargDest contains a copy of pvargSrc.
* Failure: An HRESULT error code indicating the error.
*
* NOTES
* pvargDest is always freed, and may be equal to pvargSrc.
* If pvargSrc is by-reference, pvargDest is by-reference also.
*/
HRESULT WINAPI VariantCopy(VARIANTARG* pvargDest, VARIANTARG* pvargSrc)
{
......@@ -2039,8 +1852,20 @@ HRESULT WINAPI VariantCopy(VARIANTARG* pvargDest, VARIANTARG* pvargSrc)
/******************************************************************************
* VariantCopyInd [OLEAUT32.11]
*
* Frees up the destination variant and makes a copy of the source. If
* the source is of type VT_BYREF it performs the necessary indirections.
*
* Copy a variant, dereferencing if it is by-reference.
*
* PARAMS
* pvargDest [O] Destination for copy
* pvargSrc [I] Source variant to copy
*
* RETURNS
* Success: S_OK. pvargDest contains a copy of pvargSrc.
* Failure: An HRESULT error code indicating the error.
*
* NOTES
* pvargDest is always freed, and may be equal to pvargSrc.
* If pvargSrc is not by-reference, this function acts as VariantCopy().
*/
HRESULT WINAPI VariantCopyInd(VARIANT* pvargDest, VARIANTARG* pvargSrc)
{
......@@ -2217,6 +2042,22 @@ coerce_array(
/******************************************************************************
* VariantChangeType [OLEAUT32.12]
*
* Change the type of a variant.
*
* PARAMS
* pvargDest [O] Destination for the converted variant
* pvargSrc [O] Source variant to change the type of
* wFlags [I] VARIANT_ flags from "oleauto.h"
* vt [I] Variant type to change pvargSrc into
*
* RETURNS
* Success: S_OK. pvargDest contains the converted value.
* Failure: An HRESULT error code describing the failure.
*
* NOTES
* The LCID used for the conversion is LOCALE_USER_DEFAULT.
* See VariantChangeTypeEx.
*/
HRESULT WINAPI VariantChangeType(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
USHORT wFlags, VARTYPE vt)
......@@ -2226,6 +2067,23 @@ HRESULT WINAPI VariantChangeType(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
/******************************************************************************
* VariantChangeTypeEx [OLEAUT32.147]
*
* Change the type of a variant.
*
* PARAMS
* pvargDest [O] Destination for the converted variant
* pvargSrc [O] Source variant to change the type of
* lcid [I] LCID for the conversion
* wFlags [I] VARIANT_ flags from "oleauto.h"
* vt [I] Variant type to change pvargSrc into
*
* RETURNS
* Success: S_OK. pvargDest contains the converted value.
* Failure: An HRESULT error code describing the failure.
*
* NOTES
* pvargDest and pvargSrc can point to the same variant to perform an in-place
* conversion. If the conversion is successful, pvargSrc will be freed.
*/
HRESULT WINAPI VariantChangeTypeEx(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
LCID lcid, USHORT wFlags, VARTYPE vt)
......@@ -2490,39 +2348,8 @@ HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
*/
HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
{
double dValue = 0.0;
LPSTR pNewString = NULL;
TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, pbOut );
/* Check if we have a valid argument
*/
pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
RemoveCharacterFromString( pNewString, "," );
if( IsValidRealString( pNewString ) == FALSE )
{
return DISP_E_TYPEMISMATCH;
}
/* Convert the valid string to a floating point number.
*/
dValue = atof( pNewString );
/* We don't need the string anymore so free it.
*/
HeapFree( GetProcessHeap(), 0 , pNewString );
/* Check range of value.
*/
dValue = round( dValue );
if( dValue < UI1_MIN || dValue > UI1_MAX )
{
return DISP_E_OVERFLOW;
}
*pbOut = (BYTE) dValue;
return S_OK;
TRACE("(%s, 0x%08lx, 0x%08lx, %p)\n", debugstr_w(strIn), lcid, dwFlags, pbOut);
return _VarUI1FromStr(strIn, lcid, dwFlags, pbOut);
}
/**********************************************************************
......@@ -2696,39 +2523,8 @@ HRESULT WINAPI VarI2FromUI4(ULONG ulIn, short* psOut)
*/
HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, short* psOut)
{
double dValue = 0.0;
LPSTR pNewString = NULL;
TRACE("( %s, 0x%08lx, 0x%08lx, %p ), stub\n", debugstr_w(strIn), lcid, dwFlags, psOut );
/* Check if we have a valid argument
*/
pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
RemoveCharacterFromString( pNewString, "," );
if( IsValidRealString( pNewString ) == FALSE )
{
return DISP_E_TYPEMISMATCH;
}
/* Convert the valid string to a floating point number.
*/
dValue = atof( pNewString );
/* We don't need the string anymore so free it.
*/
HeapFree( GetProcessHeap(), 0, pNewString );
/* Check range of value.
*/
dValue = round( dValue );
if( dValue < I2_MIN || dValue > I2_MAX )
{
return DISP_E_OVERFLOW;
}
*psOut = (short) dValue;
return S_OK;
TRACE("(%s, 0x%08lx, 0x%08lx, %p)\n", debugstr_w(strIn), lcid, dwFlags, psOut);
return _VarI2FromStr(strIn, lcid, dwFlags, psOut);
}
/**********************************************************************
......@@ -2889,39 +2685,8 @@ HRESULT WINAPI VarI4FromI2(short sIn, LONG* plOut)
*/
HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG* plOut)
{
double dValue = 0.0;
LPSTR pNewString = NULL;
TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, plOut );
/* Check if we have a valid argument
*/
pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
RemoveCharacterFromString( pNewString, "," );
if( IsValidRealString( pNewString ) == FALSE )
{
return DISP_E_TYPEMISMATCH;
}
/* Convert the valid string to a floating point number.
*/
dValue = atof( pNewString );
/* We don't need the string anymore so free it.
*/
HeapFree( GetProcessHeap(), 0, pNewString );
/* Check range of value.
*/
dValue = round( dValue );
if( dValue < I4_MIN || dValue > I4_MAX )
{
return DISP_E_OVERFLOW;
}
*plOut = (LONG) dValue;
return S_OK;
TRACE("(%s, 0x%08lx, 0x%08lx, %p)\n", debugstr_w(strIn), lcid, dwFlags, plOut);
return _VarI4FromStr(strIn, lcid, dwFlags, plOut);
}
/**********************************************************************
......@@ -2982,7 +2747,7 @@ HRESULT WINAPI VarR4FromR8(double dblIn, FLOAT* pfltOut)
/* Check range of value.
*/
if( dblIn < -(FLT_MAX) || dblIn > FLT_MAX )
if( dblIn < -(R4_MAX) || dblIn > R4_MAX )
{
return DISP_E_OVERFLOW;
}
......@@ -3001,7 +2766,7 @@ HRESULT WINAPI VarR4FromDate(DATE dateIn, FLOAT* pfltOut)
/* Check range of value.
*/
if( dateIn < -(FLT_MAX) || dateIn > FLT_MAX )
if( dateIn < -(R4_MAX) || dateIn > R4_MAX )
{
return DISP_E_OVERFLOW;
}
......@@ -3064,43 +2829,13 @@ HRESULT WINAPI VarR4FromUI4(ULONG ulIn, FLOAT* pfltOut)
*/
HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, FLOAT* pfltOut)
{
double dValue = 0.0;
LPSTR pNewString = NULL;
TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pfltOut );
TRACE("(%s, 0x%08lx, 0x%08lx, %p)\n", debugstr_w(strIn), lcid, dwFlags, pfltOut);
return _VarR4FromStr(strIn, lcid, dwFlags, pfltOut);
}
/* Check if we have a valid argument
*/
pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
RemoveCharacterFromString( pNewString, "," );
if( IsValidRealString( pNewString ) == FALSE )
{
return DISP_E_TYPEMISMATCH;
}
/* Convert the valid string to a floating point number.
*/
dValue = atof( pNewString );
/* We don't need the string anymore so free it.
*/
HeapFree( GetProcessHeap(), 0, pNewString );
/* Check range of value.
*/
if( dValue < -(FLT_MAX) || dValue > FLT_MAX )
{
return DISP_E_OVERFLOW;
}
*pfltOut = (FLOAT) dValue;
return S_OK;
}
/**********************************************************************
* VarR4FromCy [OLEAUT32.72]
* Convert currency to float
/**********************************************************************
* VarR4FromCy [OLEAUT32.72]
* Convert currency to float
*/
HRESULT WINAPI VarR4FromCy(CY cyIn, FLOAT* pfltOut) {
*pfltOut = (FLOAT)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
......@@ -3221,31 +2956,8 @@ HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double* pdblOut)
*/
HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double* pdblOut)
{
double dValue = 0.0;
LPSTR pNewString = NULL;
pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
TRACE("( %s, %ld, %ld, %p ), stub\n", pNewString, lcid, dwFlags, pdblOut );
/* Check if we have a valid argument
*/
RemoveCharacterFromString( pNewString, "," );
if( IsValidRealString( pNewString ) == FALSE )
{
return DISP_E_TYPEMISMATCH;
}
/* Convert the valid string to a floating point number.
*/
dValue = atof( pNewString );
/* We don't need the string anymore so free it.
*/
HeapFree( GetProcessHeap(), 0, pNewString );
*pdblOut = dValue;
return S_OK;
TRACE("(%s, 0x%08lx, 0x%08lx, %p)\n", debugstr_w(strIn), lcid, dwFlags, pdblOut);
return _VarR8FromStr(strIn, lcid, dwFlags, pdblOut);
}
/**********************************************************************
......@@ -3737,25 +3449,24 @@ HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL* pboolOut)
*/
HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL* pboolOut)
{
static const WCHAR szTrue[] = { 'T','r','u','e','\0' };
static const WCHAR szFalse[] = { 'F','a','l','s','e','\0' };
HRESULT ret = S_OK;
char* pNewString = NULL;
TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pboolOut );
pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
if( pNewString == NULL || strlen( pNewString ) == 0 )
if( strIn == NULL || strlenW( strIn ) == 0 )
{
ret = DISP_E_TYPEMISMATCH;
}
if( ret == S_OK )
{
if( strncasecmp( pNewString, "True", strlen( pNewString ) ) == 0 )
if( strcmpiW( (LPCWSTR)strIn, szTrue ) == 0 )
{
*pboolOut = VARIANT_TRUE;
}
else if( strncasecmp( pNewString, "False", strlen( pNewString ) ) == 0 )
else if( strcmpiW( (LPCWSTR)strIn, szFalse ) == 0 )
{
*pboolOut = VARIANT_FALSE;
}
......@@ -3775,8 +3486,6 @@ HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_
}
}
HeapFree( GetProcessHeap(), 0, pNewString );
return ret;
}
......@@ -3836,7 +3545,7 @@ HRESULT WINAPI VarI1FromUI1(BYTE bIn, signed char *pcOut)
/* Check range of value.
*/
if( bIn > CHAR_MAX )
if( bIn > I1_MAX )
{
return DISP_E_OVERFLOW;
}
......@@ -3853,7 +3562,7 @@ HRESULT WINAPI VarI1FromI2(short uiIn, signed char *pcOut)
{
TRACE("( %d, %p ), stub\n", uiIn, pcOut );
if( uiIn > CHAR_MAX )
if( uiIn > I1_MAX )
{
return DISP_E_OVERFLOW;
}
......@@ -3870,7 +3579,7 @@ HRESULT WINAPI VarI1FromI4(LONG lIn, signed char *pcOut)
{
TRACE("( %ld, %p ), stub\n", lIn, pcOut );
if( lIn < CHAR_MIN || lIn > CHAR_MAX )
if( lIn < I1_MIN || lIn > I1_MAX )
{
return DISP_E_OVERFLOW;
}
......@@ -3888,7 +3597,7 @@ HRESULT WINAPI VarI1FromR4(FLOAT fltIn, signed char *pcOut)
TRACE("( %f, %p ), stub\n", fltIn, pcOut );
fltIn = round( fltIn );
if( fltIn < CHAR_MIN || fltIn > CHAR_MAX )
if( fltIn < I1_MIN || fltIn > I1_MAX )
{
return DISP_E_OVERFLOW;
}
......@@ -3906,7 +3615,7 @@ HRESULT WINAPI VarI1FromR8(double dblIn, signed char *pcOut)
TRACE("( %f, %p ), stub\n", dblIn, pcOut );
dblIn = round( dblIn );
if( dblIn < CHAR_MIN || dblIn > CHAR_MAX )
if( dblIn < I1_MIN || dblIn > I1_MAX )
{
return DISP_E_OVERFLOW;
}
......@@ -3924,7 +3633,7 @@ HRESULT WINAPI VarI1FromDate(DATE dateIn, signed char *pcOut)
TRACE("( %f, %p ), stub\n", dateIn, pcOut );
dateIn = round( dateIn );
if( dateIn < CHAR_MIN || dateIn > CHAR_MAX )
if( dateIn < I1_MIN || dateIn > I1_MAX )
{
return DISP_E_OVERFLOW;
}
......@@ -3939,39 +3648,8 @@ HRESULT WINAPI VarI1FromDate(DATE dateIn, signed char *pcOut)
*/
HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, signed char *pcOut)
{
double dValue = 0.0;
LPSTR pNewString = NULL;
TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pcOut );
/* Check if we have a valid argument
*/
pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
RemoveCharacterFromString( pNewString, "," );
if( IsValidRealString( pNewString ) == FALSE )
{
return DISP_E_TYPEMISMATCH;
}
/* Convert the valid string to a floating point number.
*/
dValue = atof( pNewString );
/* We don't need the string anymore so free it.
*/
HeapFree( GetProcessHeap(), 0, pNewString );
/* Check range of value.
*/
dValue = round( dValue );
if( dValue < CHAR_MIN || dValue > CHAR_MAX )
{
return DISP_E_OVERFLOW;
}
*pcOut = (CHAR) dValue;
return S_OK;
TRACE("(%s, 0x%08lx, 0x%08lx, %p)\n", debugstr_w(strIn), lcid, dwFlags, pcOut);
return _VarI1FromStr(strIn, lcid, dwFlags, pcOut);
}
/******************************************************************************
......@@ -3993,7 +3671,7 @@ HRESULT WINAPI VarI1FromUI2(USHORT uiIn, signed char *pcOut)
{
TRACE("( %d, %p ), stub\n", uiIn, pcOut );
if( uiIn > CHAR_MAX )
if( uiIn > I1_MAX )
{
return DISP_E_OVERFLOW;
}
......@@ -4010,7 +3688,7 @@ HRESULT WINAPI VarI1FromUI4(ULONG ulIn, signed char *pcOut)
{
TRACE("( %ld, %p ), stub\n", ulIn, pcOut );
if( ulIn > CHAR_MAX )
if( ulIn > I1_MAX )
{
return DISP_E_OVERFLOW;
}
......@@ -4027,7 +3705,7 @@ HRESULT WINAPI VarI1FromUI4(ULONG ulIn, signed char *pcOut)
HRESULT WINAPI VarI1FromCy(CY cyIn, signed char *pcOut) {
double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
if (t > CHAR_MAX || t < CHAR_MIN) return DISP_E_OVERFLOW;
if (t > I1_MAX || t < I1_MIN) return DISP_E_OVERFLOW;
*pcOut = (CHAR)t;
return S_OK;
......@@ -4138,39 +3816,8 @@ HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* puiOut)
*/
HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* puiOut)
{
double dValue = 0.0;
LPSTR pNewString = NULL;
TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, puiOut );
/* Check if we have a valid argument
*/
pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
RemoveCharacterFromString( pNewString, "," );
if( IsValidRealString( pNewString ) == FALSE )
{
return DISP_E_TYPEMISMATCH;
}
/* Convert the valid string to a floating point number.
*/
dValue = atof( pNewString );
/* We don't need the string anymore so free it.
*/
HeapFree( GetProcessHeap(), 0, pNewString );
/* Check range of value.
*/
dValue = round( dValue );
if( dValue < UI2_MIN || dValue > UI2_MAX )
{
return DISP_E_OVERFLOW;
}
*puiOut = (USHORT) dValue;
return S_OK;
TRACE("(%s, 0x%08lx, 0x%08lx, %p)\n", debugstr_w(strIn), lcid, dwFlags, puiOut);
return _VarUI2FromStr(strIn, lcid, dwFlags, puiOut);
}
/******************************************************************************
......@@ -4219,39 +3866,8 @@ HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* puiOut)
*/
HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG* pulOut)
{
double dValue = 0.0;
LPSTR pNewString = NULL;
TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pulOut );
/* Check if we have a valid argument
*/
pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
RemoveCharacterFromString( pNewString, "," );
if( IsValidRealString( pNewString ) == FALSE )
{
return DISP_E_TYPEMISMATCH;
}
/* Convert the valid string to a floating point number.
*/
dValue = atof( pNewString );
/* We don't need the string anymore so free it.
*/
HeapFree( GetProcessHeap(), 0, pNewString );
/* Check range of value.
*/
dValue = round( dValue );
if( dValue < UI4_MIN || dValue > UI4_MAX )
{
return DISP_E_OVERFLOW;
}
*pulOut = (ULONG) dValue;
return S_OK;
TRACE("(%s, 0x%08lx, 0x%08lx, %p)\n", debugstr_w(strIn), lcid, dwFlags, pulOut);
return _VarUI4FromStr(strIn, lcid, dwFlags, pulOut);
}
/**********************************************************************
......@@ -4495,54 +4111,10 @@ HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pcyOut) {
* VarCyFromStr [OLEAUT32.104]
* FIXME: Never tested with decimal separator other than '.'
*/
HRESULT WINAPI VarCyFromStr(OLECHAR *strIn, LCID lcid, ULONG dwFlags, CY *pcyOut) {
LPSTR pNewString = NULL;
char *decSep = NULL;
char *strPtr,*curPtr = NULL;
int size, rc;
double currencyVal = 0.0;
pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
TRACE("( '%s', 0x%08lx, 0x%08lx, %p )\n", pNewString, lcid, dwFlags, pcyOut );
/* Get locale information - Decimal Separator (size includes 0x00) */
size = GetLocaleInfoA(lcid, LOCALE_SDECIMAL, NULL, 0);
decSep = (char *) malloc(size);
rc = GetLocaleInfoA(lcid, LOCALE_SDECIMAL, decSep, size);
TRACE("Decimal Separator is '%s'\n", decSep);
/* Now copy to temporary buffer, skipping any character except 0-9 and
the decimal separator */
curPtr = pBuffer; /* Current position in string being built */
strPtr = pNewString; /* Current position in supplied currenct string */
while (*strPtr) {
/* If decimal separator, skip it and put '.' in string */
if (strncmp(strPtr, decSep, (size-1)) == 0) {
strPtr = strPtr + (size-1);
*curPtr = '.';
curPtr++;
} else if ((*strPtr == '+' || *strPtr == '-') ||
(*strPtr >= '0' && *strPtr <= '9')) {
*curPtr = *strPtr;
strPtr++;
curPtr++;
} else strPtr++;
}
*curPtr = 0x00;
/* Try to get currency into a double */
currencyVal = atof(pBuffer);
TRACE("Converted string '%s' to %f\n", pBuffer, currencyVal);
/* Free allocated storage */
HeapFree( GetProcessHeap(), 0, pNewString );
free(decSep);
/* Convert double -> currency using internal routine */
return VarCyFromR8(currencyVal, pcyOut);
HRESULT WINAPI VarCyFromStr(OLECHAR *strIn, LCID lcid, ULONG dwFlags, CY *pcyOut)
{
TRACE("(%s, 0x%08lx, 0x%08lx, %p)\n", debugstr_w(strIn), lcid, dwFlags, pcyOut);
return _VarCyFromStr(strIn, lcid, dwFlags, pcyOut);
}
......@@ -4662,100 +4234,761 @@ INT WINAPI DosDateTimeToVariantTime(USHORT wDosDate, USHORT wDosTime,
return TmToDATE( &t, pvtime );
}
#define GET_NUMBER_TEXT(fld,name) \
buff[0] = 0; \
if (!GetLocaleInfoW(lcid, lctype|fld, buff, sizeof(WCHAR) * 2)) \
WARN("buffer too small for " #fld "\n"); \
else \
if (buff[0]) lpChars->name = buff[0]; \
TRACE("lcid 0x%lx, " #name "=%d '%c'\n", lcid, lpChars->name, lpChars->name)
/* Get the valid number characters for an lcid */
void VARIANT_GetLocalisedNumberChars(VARIANT_NUMBER_CHARS *lpChars, LCID lcid, DWORD dwFlags)
{
static const VARIANT_NUMBER_CHARS defaultChars = { '-','+','.',',','$',0,'.',',' };
LCTYPE lctype = 0;
WCHAR buff[4];
if (dwFlags & VARIANT_NOUSEROVERRIDE)
lctype |= LOCALE_NOUSEROVERRIDE;
memcpy(lpChars, &defaultChars, sizeof(defaultChars));
GET_NUMBER_TEXT(LOCALE_SNEGATIVESIGN, cNegativeSymbol);
GET_NUMBER_TEXT(LOCALE_SPOSITIVESIGN, cPositiveSymbol);
GET_NUMBER_TEXT(LOCALE_SDECIMAL, cDecimalPoint);
GET_NUMBER_TEXT(LOCALE_STHOUSAND, cDigitSeperator);
GET_NUMBER_TEXT(LOCALE_SMONDECIMALSEP, cCurrencyDecimalPoint);
GET_NUMBER_TEXT(LOCALE_SMONTHOUSANDSEP, cCurrencyDigitSeperator);
/* Local currency symbols are often 2 characters */
lpChars->cCurrencyLocal2 = '\0';
switch(GetLocaleInfoW(lcid, lctype|LOCALE_SCURRENCY, buff, sizeof(WCHAR) * 4))
{
case 3: lpChars->cCurrencyLocal2 = buff[1]; /* Fall through */
case 2: lpChars->cCurrencyLocal = buff[0];
break;
default: WARN("buffer too small for LOCALE_SCURRENCY\n");
}
TRACE("lcid 0x%lx, cCurrencyLocal =%d,%d '%c','%c'\n", lcid, lpChars->cCurrencyLocal,
lpChars->cCurrencyLocal2, lpChars->cCurrencyLocal, lpChars->cCurrencyLocal2);
}
/* Number Parsing States */
#define B_PROCESSING_EXPONENT 0x1
#define B_NEGATIVE_EXPONENT 0x2
#define B_EXPONENT_START 0x4
#define B_INEXACT_ZEROS 0x8
#define B_LEADING_ZERO 0x10
/**********************************************************************
* VarParseNumFromStr [OLEAUT32.46]
*
* Parse a string containing a number into a NUMPARSE structure.
*
* PARAMS
* lpszStr [I] String to parse number from
* lcid [I] Locale Id for the conversion
* dwFlags [I] Apparently not used
* pNumprs [I/O] Destination for parsed number
* rgbDig [O] Destination for digits read in
*
* RETURNS
* Success: S_OK. pNumprs and rgbDig contain the parsed representation of
* the number.
* Failure: E_INVALIDARG, if any parameter is invalid.
* DISP_E_TYPEMISMATCH, if the string is not a number or is formatted
* incorrectly.
* DISP_E_OVERFLOW, if rgbDig is too small to hold the number.
*
* NOTES
* pNumprs must have the following fields set:
* cDig: Set to the size of rgbDig.
* dwInFlags: Set to the allowable syntax of the number using NUMPRS_ flags
* from "oleauto.h".
*
* FIXME
* - I am unsure if this function should parse non-arabic (e.g. Thai)
* numerals, so this has not been implemented.
*/
HRESULT WINAPI VarParseNumFromStr(OLECHAR * strIn, LCID lcid, ULONG dwFlags,
NUMPARSE * pnumprs, BYTE * rgbDig)
HRESULT WINAPI VarParseNumFromStr(OLECHAR *lpszStr, LCID lcid, ULONG dwFlags,
NUMPARSE *pNumprs, BYTE *rgbDig)
{
int i,lastent=0;
int cDig;
BOOL foundNum=FALSE;
VARIANT_NUMBER_CHARS chars;
BYTE rgbTmp[1024];
DWORD dwState = B_EXPONENT_START|B_INEXACT_ZEROS;
int iMaxDigits = sizeof(rgbTmp) / sizeof(BYTE);
int cchUsed = 0;
TRACE("(%s,%ld,%ld,%p,%p)\n", debugstr_w(lpszStr), lcid, dwFlags, pNumprs, rgbDig);
if (pNumprs->dwInFlags & NUMPRS_HEX_OCT)
FIXME("dwInFlags & NUMPRS_HEX_OCT not yet implemented!\n");
if (!pNumprs || !rgbDig)
return E_INVALIDARG;
if (pNumprs->cDig < iMaxDigits)
iMaxDigits = pNumprs->cDig;
FIXME("(%s,flags=%lx,....), partial stub!\n",debugstr_w(strIn),dwFlags);
FIXME("numparse: cDig=%d, InFlags=%lx\n",pnumprs->cDig,pnumprs->dwInFlags);
pNumprs->cDig = 0;
pNumprs->dwOutFlags = 0;
pNumprs->cchUsed = 0;
pNumprs->nBaseShift = 0;
pNumprs->nPwr10 = 0;
/* The other struct components are to be set by us */
memset(rgbDig,0,pnumprs->cDig);
if (!lpszStr)
return DISP_E_TYPEMISMATCH;
/* FIXME: Just patching some values in */
pnumprs->nPwr10 = 0;
pnumprs->nBaseShift = 0;
pnumprs->cchUsed = lastent;
pnumprs->dwOutFlags = NUMPRS_DECIMAL;
VARIANT_GetLocalisedNumberChars(&chars, lcid, dwFlags);
cDig = 0;
for (i=0; strIn[i] ;i++) {
if ((strIn[i]>='0') && (strIn[i]<='9')) {
foundNum = TRUE;
if (pnumprs->cDig > cDig) {
*(rgbDig++)=strIn[i]-'0';
cDig++;
lastent = i;
/* First consume all the leading symbols and space from the string */
while (1)
{
if (pNumprs->dwInFlags & NUMPRS_LEADING_WHITE && isspaceW(*lpszStr))
{
pNumprs->dwOutFlags |= NUMPRS_LEADING_WHITE;
do
{
cchUsed++;
lpszStr++;
} while (isspaceW(*lpszStr));
}
} else if ((strIn[i]=='-') && (foundNum==FALSE)) {
pnumprs->dwOutFlags |= NUMPRS_NEG;
else if (pNumprs->dwInFlags & NUMPRS_LEADING_PLUS &&
*lpszStr == chars.cPositiveSymbol &&
!(pNumprs->dwOutFlags & NUMPRS_LEADING_PLUS))
{
pNumprs->dwOutFlags |= NUMPRS_LEADING_PLUS;
cchUsed++;
lpszStr++;
}
else if (pNumprs->dwInFlags & NUMPRS_LEADING_MINUS &&
*lpszStr == chars.cNegativeSymbol &&
!(pNumprs->dwOutFlags & NUMPRS_LEADING_MINUS))
{
pNumprs->dwOutFlags |= (NUMPRS_LEADING_MINUS|NUMPRS_NEG);
cchUsed++;
lpszStr++;
}
else if (pNumprs->dwInFlags & NUMPRS_CURRENCY &&
!(pNumprs->dwOutFlags & NUMPRS_CURRENCY) &&
*lpszStr == chars.cCurrencyLocal &&
(!chars.cCurrencyLocal2 || lpszStr[1] == chars.cCurrencyLocal2))
{
pNumprs->dwOutFlags |= NUMPRS_CURRENCY;
cchUsed++;
lpszStr++;
/* Only accept currency characters */
chars.cDecimalPoint = chars.cCurrencyDecimalPoint;
chars.cDigitSeperator = chars.cCurrencyDigitSeperator;
}
else if (pNumprs->dwInFlags & NUMPRS_PARENS && *lpszStr == '(' &&
!(pNumprs->dwOutFlags & NUMPRS_PARENS))
{
pNumprs->dwOutFlags |= NUMPRS_PARENS;
cchUsed++;
lpszStr++;
}
else
break;
}
if (!(pNumprs->dwOutFlags & NUMPRS_CURRENCY))
{
/* Only accept non-currency characters */
chars.cCurrencyDecimalPoint = chars.cDecimalPoint;
chars.cCurrencyDigitSeperator = chars.cDigitSeperator;
}
/* Strip Leading zeros */
while (*lpszStr == '0')
{
dwState |= B_LEADING_ZERO;
cchUsed++;
lpszStr++;
}
while (*lpszStr)
{
if (isdigitW(*lpszStr))
{
if (dwState & B_PROCESSING_EXPONENT)
{
int exponentSize = 0;
if (dwState & B_EXPONENT_START)
{
while (*lpszStr == '0')
{
/* Skip leading zero's in the exponent */
cchUsed++;
lpszStr++;
}
if (!isdigitW(*lpszStr))
break; /* No exponent digits - invalid */
}
while (isdigitW(*lpszStr))
{
exponentSize *= 10;
exponentSize += *lpszStr - '0';
cchUsed++;
lpszStr++;
}
if (dwState & B_NEGATIVE_EXPONENT)
exponentSize = -exponentSize;
/* Add the exponent into the powers of 10 */
pNumprs->nPwr10 += exponentSize;
dwState &= ~(B_PROCESSING_EXPONENT|B_EXPONENT_START);
lpszStr--; /* back up to allow processing of next char */
}
else
{
if (pNumprs->cDig >= iMaxDigits)
{
pNumprs->dwOutFlags |= NUMPRS_INEXACT;
if (*lpszStr != '0')
dwState &= ~B_INEXACT_ZEROS; /* Inexact number with non-trailing zeros */
/* This digit can't be represented, but count it in nPwr10 */
if (pNumprs->dwOutFlags & NUMPRS_DECIMAL)
pNumprs->nPwr10--;
else
pNumprs->nPwr10++;
}
else
{
if (pNumprs->dwOutFlags & NUMPRS_DECIMAL)
pNumprs->nPwr10--; /* Count decimal points in nPwr10 */
rgbTmp[pNumprs->cDig] = *lpszStr - '0';
}
pNumprs->cDig++;
cchUsed++;
}
}
else if (*lpszStr == chars.cDigitSeperator && pNumprs->dwInFlags & NUMPRS_THOUSANDS)
{
pNumprs->dwOutFlags |= NUMPRS_THOUSANDS;
cchUsed++;
}
else if (*lpszStr == chars.cDecimalPoint &&
pNumprs->dwInFlags & NUMPRS_DECIMAL &&
!(pNumprs->dwOutFlags & (NUMPRS_DECIMAL|NUMPRS_EXPONENT)))
{
pNumprs->dwOutFlags |= NUMPRS_DECIMAL;
cchUsed++;
/* Remove trailing zeros from the whole number part */
while (pNumprs->cDig > 1 && !rgbTmp[pNumprs->cDig - 1])
{
pNumprs->nPwr10++;
pNumprs->cDig--;
}
/* If we have no digits so far, skip leading zeros */
if (!pNumprs->cDig)
{
while (lpszStr[1] == '0')
{
dwState |= B_LEADING_ZERO;
cchUsed++;
lpszStr++;
}
}
}
else if ((*lpszStr == 'e' || *lpszStr == 'E') &&
pNumprs->dwInFlags & NUMPRS_EXPONENT &&
!(pNumprs->dwOutFlags & NUMPRS_EXPONENT))
{
dwState |= B_PROCESSING_EXPONENT;
pNumprs->dwOutFlags |= NUMPRS_EXPONENT;
cchUsed++;
}
pnumprs->cDig = cDig;
TRACE("numparse out: cDig=%d, OutFlags=%lx\n",pnumprs->cDig,pnumprs->dwOutFlags);
else if (dwState & B_PROCESSING_EXPONENT && *lpszStr == chars.cPositiveSymbol)
{
cchUsed++; /* Ignore positive exponent */
}
else if (dwState & B_PROCESSING_EXPONENT && *lpszStr == chars.cNegativeSymbol)
{
dwState |= B_NEGATIVE_EXPONENT;
cchUsed++;
}
else
break; /* Stop at an unrecognised character */
lpszStr++;
}
if (!pNumprs->cDig && dwState & B_LEADING_ZERO)
{
/* Ensure a 0 on its own gets stored */
pNumprs->cDig = 1;
rgbTmp[0] = 0;
}
if (pNumprs->dwOutFlags & NUMPRS_EXPONENT && dwState & B_PROCESSING_EXPONENT)
{
pNumprs->cchUsed = cchUsed;
return DISP_E_TYPEMISMATCH; /* Failed to completely parse the exponent */
}
if (pNumprs->dwOutFlags & NUMPRS_INEXACT)
{
if (dwState & B_INEXACT_ZEROS)
pNumprs->dwOutFlags &= ~NUMPRS_INEXACT; /* All zeros doesn't set NUMPRS_INEXACT */
}
else
{
/* Remove trailing zeros from the last (whole number or decimal) part */
while (pNumprs->cDig > 1 && !rgbTmp[pNumprs->cDig - 1])
{
if (pNumprs->dwOutFlags & NUMPRS_DECIMAL)
pNumprs->nPwr10--;
else
pNumprs->nPwr10++;
pNumprs->cDig--;
}
}
if (pNumprs->cDig <= iMaxDigits)
pNumprs->dwOutFlags &= ~NUMPRS_INEXACT; /* Ignore stripped zeros for NUMPRS_INEXACT */
else
pNumprs->cDig = iMaxDigits; /* Only return iMaxDigits worth of digits */
/* Copy the digits we processed into rgbDig */
memcpy(rgbDig, rgbTmp, pNumprs->cDig * sizeof(BYTE));
/* Consume any trailing symbols and space */
while (1)
{
if ((pNumprs->dwInFlags & NUMPRS_TRAILING_WHITE) && isspaceW(*lpszStr))
{
pNumprs->dwOutFlags |= NUMPRS_TRAILING_WHITE;
do
{
cchUsed++;
lpszStr++;
} while (isspaceW(*lpszStr));
}
else if (pNumprs->dwInFlags & NUMPRS_TRAILING_PLUS &&
!(pNumprs->dwOutFlags & NUMPRS_LEADING_PLUS) &&
*lpszStr == chars.cPositiveSymbol)
{
pNumprs->dwOutFlags |= NUMPRS_TRAILING_PLUS;
cchUsed++;
lpszStr++;
}
else if (pNumprs->dwInFlags & NUMPRS_TRAILING_MINUS &&
!(pNumprs->dwOutFlags & NUMPRS_LEADING_MINUS) &&
*lpszStr == chars.cNegativeSymbol)
{
pNumprs->dwOutFlags |= (NUMPRS_TRAILING_MINUS|NUMPRS_NEG);
cchUsed++;
lpszStr++;
}
else if (pNumprs->dwInFlags & NUMPRS_PARENS && *lpszStr == ')' &&
pNumprs->dwOutFlags & NUMPRS_PARENS)
{
cchUsed++;
lpszStr++;
pNumprs->dwOutFlags |= NUMPRS_NEG;
}
else
break;
}
if (pNumprs->dwOutFlags & NUMPRS_PARENS && !(pNumprs->dwOutFlags & NUMPRS_NEG))
{
pNumprs->cchUsed = cchUsed;
return DISP_E_TYPEMISMATCH; /* Opening parenthesis not matched */
}
if (pNumprs->dwInFlags & NUMPRS_USE_ALL && *lpszStr != '\0')
return DISP_E_TYPEMISMATCH; /* Not all chars were consumed */
if (!pNumprs->cDig)
return DISP_E_TYPEMISMATCH; /* No Number found */
pNumprs->cchUsed = cchUsed;
return S_OK;
}
/* VTBIT flags indicating an integer value */
#define INTEGER_VTBITS (VTBIT_I1|VTBIT_UI1|VTBIT_I2|VTBIT_UI2|VTBIT_I4|VTBIT_UI4|VTBIT_I8|VTBIT_UI8)
/* VTBIT flags indicating a real number value */
#define REAL_VTBITS (VTBIT_R4|VTBIT_R8|VTBIT_CY|VTBIT_DECIMAL)
/**********************************************************************
* VarNumFromParseNum [OLEAUT32.47]
*
* Convert a NUMPARSE structure into a numeric Variant type.
*
* PARAMS
* pNumprs [I] Source for parsed number. cDig must be set to the size of rgbDig
* rgbDig [I] Source for the numbers digits
* dwVtBits [I] VTBIT_ flags from "oleauto.h" indicating the acceptable dest types
* pVarDst [O] Destination for the converted Variant value.
*
* RETURNS
* Success: S_OK. pVarDst contains the converted value.
* Failure: E_INVALIDARG, if any parameter is invalid.
* DISP_E_OVERFLOW, if the number is too big for the types set in dwVtBits.
*
* NOTES
* - The smallest favoured type present in dwVtBits that can represent the
* number in pNumprs without losing precision is used.
* - Signed types are preferrred over unsigned types of the same size.
* - Preferred types in order are: integer, float, double, currency then decimal.
* - Rounding (dropping of decimal points) occurs without error. See VarI8FromR8()
* for details of the rounding method.
* - pVarDst is not cleared before the result is stored in it.
*/
HRESULT WINAPI VarNumFromParseNum(NUMPARSE *pNumprs, BYTE *rgbDig,
ULONG dwVtBits, VARIANT *pVarDst)
{
/* Scale factors and limits for double arithmatic */
static const double dblMultipliers[11] = {
1.0, 10.0, 100.0, 1000.0, 10000.0, 100000.0,
1000000.0, 10000000.0, 100000000.0, 1000000000.0, 10000000000.0
};
static const double dblMinimums[11] = {
R8_MIN, R8_MIN*10.0, R8_MIN*100.0, R8_MIN*1000.0, R8_MIN*10000.0,
R8_MIN*100000.0, R8_MIN*1000000.0, R8_MIN*10000000.0,
R8_MIN*100000000.0, R8_MIN*1000000000.0, R8_MIN*10000000000.0
};
static const double dblMaximums[11] = {
R8_MAX, R8_MAX/10.0, R8_MAX/100.0, R8_MAX/1000.0, R8_MAX/10000.0,
R8_MAX/100000.0, R8_MAX/1000000.0, R8_MAX/10000000.0,
R8_MAX/100000000.0, R8_MAX/1000000000.0, R8_MAX/10000000000.0
};
int wholeNumberDigits, fractionalDigits, divisor10 = 0, multiplier10 = 0;
TRACE("(%p,%p,0x%lx,%p)\n", pNumprs, rgbDig, dwVtBits, pVarDst);
if (pNumprs->nBaseShift)
{
/* nBaseShift indicates a hex or octal number */
FIXME("nBaseShift=%d not yet implemented, returning overflow\n", pNumprs->nBaseShift);
return DISP_E_OVERFLOW;
}
/* Count the number of relevant fractional and whole digits stored,
* And compute the divisor/multiplier to scale the number by.
*/
HRESULT WINAPI VarNumFromParseNum(NUMPARSE * pnumprs, BYTE * rgbDig,
ULONG dwVtBits, VARIANT * pvar)
{
DWORD xint;
if (pNumprs->nPwr10 < 0)
{
if (-pNumprs->nPwr10 >= pNumprs->cDig)
{
/* A real number < +/- 1.0 e.g. 0.1024 or 0.01024 */
wholeNumberDigits = 0;
fractionalDigits = pNumprs->cDig;
divisor10 = -pNumprs->nPwr10;
}
else
{
/* An exactly represented real number e.g. 1.024 */
wholeNumberDigits = pNumprs->cDig + pNumprs->nPwr10;
fractionalDigits = pNumprs->cDig - wholeNumberDigits;
divisor10 = pNumprs->cDig - wholeNumberDigits;
}
}
else if (pNumprs->nPwr10 == 0)
{
/* An exactly represented whole number e.g. 1024 */
wholeNumberDigits = pNumprs->cDig;
fractionalDigits = 0;
}
else /* pNumprs->nPwr10 > 0 */
{
/* A whole number followed by nPwr10 0's e.g. 102400 */
wholeNumberDigits = pNumprs->cDig;
fractionalDigits = 0;
multiplier10 = pNumprs->nPwr10;
}
TRACE("cDig %d; nPwr10 %d, whole %d, frac %d ", pNumprs->cDig,
pNumprs->nPwr10, wholeNumberDigits, fractionalDigits);
TRACE("mult %d; div %d\n", multiplier10, divisor10);
if (dwVtBits & INTEGER_VTBITS &&
(!fractionalDigits || !(dwVtBits & (REAL_VTBITS|VTBIT_CY|VTBIT_DECIMAL))))
{
/* We have one or more integer output choices, and either:
* 1) An integer input value, or
* 2) A real number input value but no floating output choices.
* So, place the integer value into pVarDst, using the smallest type
* possible and preferring signed over unsigned types.
*/
BOOL bOverflow = FALSE, bNegative;
ULONG64 ul64 = 0;
int i;
FIXME("(..,dwVtBits=%lx,....), partial stub!\n",dwVtBits);
xint = 0;
for (i=0;i<pnumprs->cDig;i++)
xint = xint*10 + rgbDig[i];
/* Convert the integer part of the number into a UI8 */
for (i = 0; i < wholeNumberDigits; i++)
{
if (ul64 > (UI8_MAX / 10 - rgbDig[i]))
{
TRACE("Overflow multiplying digits\n");
bOverflow = TRUE;
break;
}
ul64 = ul64 * 10 + rgbDig[i];
}
if (pnumprs->dwOutFlags & NUMPRS_NEG) {
xint = xint * -1;
/* Account for the scale of the number */
if (!bOverflow && multiplier10)
{
for (i = 0; i < multiplier10; i++)
{
if (ul64 > (UI8_MAX / 10))
{
TRACE("Overflow scaling number\n");
bOverflow = TRUE;
break;
}
ul64 = ul64 * 10;
}
}
/* If we have any fractional digits, round the value.
* Note we dont have to do this if divisor10 is < 1,
* because this means the fractional part must be < 0.5
*/
if (!bOverflow && fractionalDigits && divisor10 > 0)
{
const BYTE* fracDig = rgbDig + wholeNumberDigits;
BOOL bAdjust = FALSE;
TRACE("first decimal value is %d\n", *fracDig);
VariantInit(pvar);
if (dwVtBits & VTBIT_I4) {
V_VT(pvar) = VT_I4;
V_UNION(pvar,intVal) = xint;
if (*fracDig > 5)
bAdjust = TRUE; /* > 0.5 */
else if (*fracDig == 5)
{
for (i = 1; i < fractionalDigits; i++)
{
if (fracDig[i])
{
bAdjust = TRUE; /* > 0.5 */
break;
}
}
/* If exactly 0.5, round only odd values */
if (i == fractionalDigits && (ul64 & 1))
bAdjust = TRUE;
}
if (bAdjust)
{
if (ul64 == UI8_MAX)
{
TRACE("Overflow after rounding\n");
bOverflow = TRUE;
}
ul64++;
}
}
/* Zero is not a negative number */
bNegative = pNumprs->dwOutFlags & NUMPRS_NEG && ul64 ? TRUE : FALSE;
TRACE("Integer value is %lld, bNeg %d\n", ul64, bNegative);
/* For negative integers, try the signed types in size order */
if (!bOverflow && bNegative)
{
if (dwVtBits & (VTBIT_I1|VTBIT_I2|VTBIT_I4|VTBIT_I8))
{
if (dwVtBits & VTBIT_I1 && ul64 <= -I1_MIN)
{
V_VT(pVarDst) = VT_I1;
V_I1(pVarDst) = -ul64;
return S_OK;
}
else if (dwVtBits & VTBIT_I2 && ul64 <= -I2_MIN)
{
V_VT(pVarDst) = VT_I2;
V_I2(pVarDst) = -ul64;
return S_OK;
}
else if (dwVtBits & VTBIT_I4 && ul64 <= -((LONGLONG)I4_MIN))
{
V_VT(pVarDst) = VT_I4;
V_I4(pVarDst) = -ul64;
return S_OK;
}
if (dwVtBits & VTBIT_R8) {
V_VT(pvar) = VT_R8;
V_UNION(pvar,dblVal) = xint;
else if (dwVtBits & VTBIT_I8 && ul64 <= (ULONGLONG)I8_MAX + 1)
{
V_VT(pVarDst) = VT_I8;
V_I8(pVarDst) = -ul64;
return S_OK;
}
if (dwVtBits & VTBIT_R4) {
V_VT(pvar) = VT_R4;
V_UNION(pvar,fltVal) = xint;
}
}
else if (!bOverflow)
{
/* For positive integers, try signed then unsigned types in size order */
if (dwVtBits & VTBIT_I1 && ul64 <= I1_MAX)
{
V_VT(pVarDst) = VT_I1;
V_I1(pVarDst) = ul64;
return S_OK;
}
if (dwVtBits & VTBIT_I2) {
V_VT(pvar) = VT_I2;
V_UNION(pvar,iVal) = xint;
if (dwVtBits & VTBIT_UI1 && ul64 <= UI1_MAX)
{
V_VT(pVarDst) = VT_UI1;
V_UI1(pVarDst) = ul64;
return S_OK;
}
/* FIXME: Currency should be from a double */
if (dwVtBits & VTBIT_CY) {
V_VT(pvar) = VT_CY;
TRACE("Calculated currency is xint=%ld\n", xint);
VarCyFromInt( (int) xint, &V_UNION(pvar,cyVal) );
TRACE("Calculated cy is %ld,%lu\n", V_UNION(pvar,cyVal).s.Hi, V_UNION(pvar,cyVal).s.Lo);
return VarCyFromInt( (int) xint, &V_UNION(pvar,cyVal) );
if (dwVtBits & VTBIT_I2 && ul64 <= I2_MAX)
{
V_VT(pVarDst) = VT_I2;
V_I2(pVarDst) = ul64;
return S_OK;
}
if (dwVtBits & VTBIT_UI2 && ul64 <= UI2_MAX)
{
V_VT(pVarDst) = VT_UI2;
V_UI2(pVarDst) = ul64;
return S_OK;
}
if (dwVtBits & VTBIT_I4 && ul64 <= I4_MAX)
{
V_VT(pVarDst) = VT_I4;
V_I4(pVarDst) = ul64;
return S_OK;
}
if (dwVtBits & VTBIT_UI4 && ul64 <= UI4_MAX)
{
V_VT(pVarDst) = VT_UI4;
V_UI4(pVarDst) = ul64;
return S_OK;
}
if (dwVtBits & VTBIT_I8 && ul64 <= I8_MAX)
{
V_VT(pVarDst) = VT_I8;
V_I8(pVarDst) = ul64;
return S_OK;
}
if (dwVtBits & VTBIT_UI8)
{
V_VT(pVarDst) = VT_UI8;
V_UI8(pVarDst) = ul64;
return S_OK;
}
}
}
FIXME("vtbitmask is unsupported %lx, int=%d\n",dwVtBits, (int) xint);
return E_FAIL;
}
if (dwVtBits & REAL_VTBITS)
{
/* Try to put the number into a float or real */
BOOL bOverflow = FALSE, bNegative = pNumprs->dwOutFlags & NUMPRS_NEG;
double whole = 0.0;
int i;
/* Convert the number into a double */
for (i = 0; i < pNumprs->cDig; i++)
whole = whole * 10.0 + rgbDig[i];
TRACE("Whole double value is %16.16g\n", whole);
/* Account for the scale */
while (multiplier10 > 10)
{
if (whole > dblMaximums[10])
{
dwVtBits &= ~(VTBIT_R4|VTBIT_R8|VTBIT_CY);
bOverflow = TRUE;
break;
}
whole = whole * dblMultipliers[10];
multiplier10 -= 10;
}
if (multiplier10)
{
if (whole > dblMaximums[multiplier10])
{
dwVtBits &= ~(VTBIT_R4|VTBIT_R8|VTBIT_CY);
bOverflow = TRUE;
}
else
whole = whole * dblMultipliers[multiplier10];
}
TRACE("Scaled double value is %16.16g\n", whole);
while (divisor10 > 10)
{
if (whole < dblMinimums[10])
{
dwVtBits &= ~(VTBIT_R4|VTBIT_R8|VTBIT_CY); /* Underflow */
bOverflow = TRUE;
break;
}
whole = whole / dblMultipliers[10];
divisor10 -= 10;
}
if (divisor10)
{
if (whole < dblMinimums[divisor10])
{
dwVtBits &= ~(VTBIT_R4|VTBIT_R8|VTBIT_CY); /* Underflow */
bOverflow = TRUE;
}
else
whole = whole / dblMultipliers[divisor10];
}
if (!bOverflow)
TRACE("Final double value is %16.16g\n", whole);
if (dwVtBits & VTBIT_R4 &&
((whole <= R4_MAX && whole >= R4_MIN) || whole == 0.0))
{
TRACE("Set R4 to final value\n");
V_VT(pVarDst) = VT_R4; /* Fits into a float */
V_R4(pVarDst) = pNumprs->dwOutFlags & NUMPRS_NEG ? -whole : whole;
return S_OK;
}
if (dwVtBits & VTBIT_R8)
{
TRACE("Set R8 to final value\n");
V_VT(pVarDst) = VT_R8; /* Fits into a double */
V_R8(pVarDst) = pNumprs->dwOutFlags & NUMPRS_NEG ? -whole : whole;
return S_OK;
}
if (dwVtBits & VTBIT_CY)
{
if (SUCCEEDED(VarCyFromR8(bNegative ? -whole : whole, &V_CY(pVarDst))))
{
V_VT(pVarDst) = VT_CY; /* Fits into a currency */
TRACE("Set CY to final value\n");
return S_OK;
}
TRACE("Value Overflows CY\n");
}
if (!bOverflow && dwVtBits & VTBIT_DECIMAL)
{
WARN("VTBIT_DECIMAL not yet implemented\n");
#if 0
if (SUCCEEDED(VarDecFromR8(bNegative ? -whole : whole, &V_DECIMAL(pVarDst))))
{
V_VT(pVarDst) = VT_DECIMAL; /* Fits into a decimal */
TRACE("Set DECIMAL to final value\n");
return S_OK;
}
#endif
}
}
if (dwVtBits & VTBIT_DECIMAL)
{
FIXME("VT_DECIMAL > R8 not yet supported, returning overflow\n");
}
return DISP_E_OVERFLOW; /* No more output choices */
}
/**********************************************************************
* VarFormatDateTime [OLEAUT32.97]
......
/*
* Variant Inlines
*
* Copyright 2003 Jon Griffiths
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include "windef.h"
#include "winerror.h"
#include "oleauto.h"
#include <math.h>
/* Size constraints */
#define I1_MAX 0x7f
#define I1_MIN ((-I1_MAX)-1)
#define UI1_MAX 0xff
#define UI1_MIN 0
#define I2_MAX 0x7fff
#define I2_MIN ((-I2_MAX)-1)
#define UI2_MAX 0xffff
#define UI2_MIN 0
#define I4_MAX 0x7fffffff
#define I4_MIN ((-I4_MAX)-1)
#define UI4_MAX 0xffffffff
#define UI4_MIN 0
#define I8_MAX (((LONGLONG)I4_MAX << 32) | UI4_MAX)
#define I8_MIN ((-I8_MAX)-1)
#define UI8_MAX (((ULONGLONG)UI4_MAX << 32) | UI4_MAX)
#define UI8_MIN 0
#define DATE_MAX 2958465
#define DATE_MIN -657434
#define R4_MAX 3.402823567797336e38
#define R4_MIN 1.40129846432481707e-45
#define R8_MAX 1.79769313486231470e+308
#define R8_MIN 4.94065645841246544e-324
/* Value of sign for a positive number */
#define DECIMAL_POS 0
/* Native headers don't change the union ordering for DECIMAL sign/scale (duh).
* This means that the signscale member is only useful for setting both members to 0.
* SIGNSCALE creates endian-correct values so that we can properly set both at once
* to values other than 0.
*/
#ifdef WORDS_BIGENDIAN
#define SIGNSCALE(sign,scale) (((scale) << 8) | sign)
#else
#define SIGNSCALE(sign,scale) (((sign) << 8) | scale)
#endif
/* Macros for getting at a DECIMAL's parts */
#define DEC_SIGN(d) ((d)->u.s.sign)
#define DEC_SCALE(d) ((d)->u.s.scale)
#define DEC_SIGNSCALE(d) ((d)->u.signscale)
#define DEC_HI32(d) ((d)->Hi32)
#define DEC_MID32(d) ((d)->u1.s1.Mid32)
#define DEC_LO32(d) ((d)->u1.s1.Lo32)
#define DEC_LO64(d) ((d)->u1.Lo64)
#define DEC_MAX_SCALE 28 /* Maximum scale for a decimal */
/* Inline return type */
#define RETTYP inline static HRESULT
/* Simple compiler cast from one type to another */
#define SIMPLE(dest, src, func) RETTYP _##func(src in, dest* out) { \
*out = in; return S_OK; }
/* Compiler cast where input cannot be negative */
#define NEGTST(dest, src, func) RETTYP _##func(src in, dest* out) { \
if (in < (src)0) return DISP_E_OVERFLOW; *out = in; return S_OK; }
/* Compiler cast where input cannot be > some number */
#define POSTST(dest, src, func, tst) RETTYP _##func(src in, dest* out) { \
if (in > (dest)tst) return DISP_E_OVERFLOW; *out = in; return S_OK; }
/* Compiler cast where input cannot be < some number or >= some other number */
#define BOTHTST(dest, src, func, lo, hi) RETTYP _##func(src in, dest* out) { \
if (in < (dest)lo || in > hi) return DISP_E_OVERFLOW; *out = in; return S_OK; }
/* Conversions from IDispatch use the same code */
HRESULT VARIANT_FromDisp(IDispatch*,LCID,void*,VARTYPE);
/* As do conversions from BSTR to numeric types */
HRESULT VARIANT_NumberFromBstr(OLECHAR*,LCID,ULONG,void*,VARTYPE);
#define CY_MULTIPLIER 10000 /* 4 dp of precision */
#define CY_MULTIPLIER_F 10000.0
#define CY_HALF (CY_MULTIPLIER/2) /* 0.5 */
#define CY_HALF_F (CY_MULTIPLIER_F/2.0)
/* I1 */
POSTST(signed char, BYTE, VarI1FromUI1, I1_MAX);
BOTHTST(signed char, SHORT, VarI1FromI2, I1_MIN, I1_MAX);
BOTHTST(signed char, LONG, VarI1FromI4, I1_MIN, I1_MAX);
#define _VarI1FromR4(flt,out) VarI1FromR8((double)flt,out)
#define _VarI1FromR8 VarI1FromR8
#define _VarI1FromCy VarI1FromCy
#define _VarI1FromDate(dt,out) VarI1FromR8((double)dt,out)
#define _VarI1FromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_I1)
#define _VarI1FromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, (BYTE*)out, VT_I1)
SIMPLE(signed char, VARIANT_BOOL, VarI1FromBool);
POSTST(signed char, USHORT, VarI1FromUI2, I1_MAX);
POSTST(signed char, ULONG, VarI1FromUI4, I1_MAX);
#define _VarI1FromDec VarI1FromDec
BOTHTST(signed char, LONG64, VarI1FromI8, I1_MIN, I1_MAX);
POSTST(signed char, ULONG64, VarI1FromUI8, I1_MAX);
/* UI1 */
BOTHTST(BYTE, SHORT, VarUI1FromI2, UI1_MIN, UI1_MAX);
#define _VarUI1FromR4(flt,out) VarUI1FromR8((double)flt,out)
#define _VarUI1FromR8 VarUI1FromR8
#define _VarUI1FromCy VarUI1FromCy
#define _VarUI1FromDate(dt,out) VarUI1FromR8((double)dt,out)
#define _VarUI1FromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_UI1)
#define _VarUI1FromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_UI1)
SIMPLE(BYTE, VARIANT_BOOL, VarUI1FromBool);
NEGTST(BYTE, signed char, VarUI1FromI1);
POSTST(BYTE, USHORT, VarUI1FromUI2, UI1_MAX);
BOTHTST(BYTE, LONG, VarUI1FromI4, UI1_MIN, UI1_MAX);
POSTST(BYTE, ULONG, VarUI1FromUI4, UI1_MAX);
#define _VarUI1FromDec VarUI1FromDec
BOTHTST(BYTE, LONG64, VarUI1FromI8, UI1_MIN, UI1_MAX);
POSTST(BYTE, ULONG64, VarUI1FromUI8, UI1_MAX);
/* I2 */
POSTST(SHORT, BYTE, VarI2FromUI1, I2_MAX);
BOTHTST(SHORT, LONG, VarI2FromI4, I2_MIN, I2_MAX);
#define _VarI2FromR4(flt,out) VarI2FromR8((double)flt,out)
#define _VarI2FromR8 VarI2FromR8
#define _VarI2FromCy VarI2FromCy
#define _VarI2FromDate(dt,out) VarI2FromR8((double)dt,out)
#define _VarI2FromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_I2)
#define _VarI2FromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, (BYTE*)out, VT_I2)
SIMPLE(SHORT, VARIANT_BOOL, VarI2FromBool);
SIMPLE(SHORT, signed char, VarI2FromI1);
POSTST(SHORT, USHORT, VarI2FromUI2, I2_MAX);
POSTST(SHORT, ULONG, VarI2FromUI4, I2_MAX);
#define _VarI2FromDec VarI2FromDec
BOTHTST(SHORT, LONG64, VarI2FromI8, I2_MIN, I2_MAX);
POSTST(SHORT, ULONG64, VarI2FromUI8, I2_MAX);
/* UI2 */
SIMPLE(USHORT, BYTE, VarUI2FromUI1);
NEGTST(USHORT, SHORT, VarUI2FromI2);
BOTHTST(USHORT, LONG, VarUI2FromI4, UI2_MIN, UI2_MAX);
#define _VarUI2FromR4(flt,out) VarUI2FromR8((double)flt,out)
#define _VarUI2FromR8 VarUI2FromR8
#define _VarUI2FromCy VarUI2FromCy
#define _VarUI2FromDate(dt,out) VarUI2FromR8((double)dt,out)
#define _VarUI2FromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_UI2)
#define _VarUI2FromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_UI2)
SIMPLE(USHORT, VARIANT_BOOL, VarUI2FromBool);
NEGTST(USHORT, signed char, VarUI2FromI1);
POSTST(USHORT, ULONG, VarUI2FromUI4, UI2_MAX);
#define _VarUI2FromDec VarUI2FromDec
BOTHTST(USHORT, LONG64, VarUI2FromI8, UI2_MIN, UI2_MAX);
POSTST(USHORT, ULONG64, VarUI2FromUI8, UI2_MAX);
/* I4 */
SIMPLE(LONG, BYTE, VarI4FromUI1);
SIMPLE(LONG, SHORT, VarI4FromI2);
#define _VarI4FromR4(flt,out) VarI4FromR8((double)flt,out)
#define _VarI4FromR8 VarI4FromR8
#define _VarI4FromCy VarI4FromCy
#define _VarI4FromDate(dt,out) VarI4FromR8((double)dt,out)
#define _VarI4FromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_I4)
#define _VarI4FromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, (BYTE*)out, VT_I4)
SIMPLE(LONG, VARIANT_BOOL, VarI4FromBool);
SIMPLE(LONG, signed char, VarI4FromI1);
SIMPLE(LONG, USHORT, VarI4FromUI2);
POSTST(LONG, ULONG, VarI4FromUI4, I4_MAX);
#define _VarI4FromDec VarI4FromDec
BOTHTST(LONG, LONG64, VarI4FromI8, I4_MIN, I4_MAX);
POSTST(LONG, ULONG64, VarI4FromUI8, I4_MAX);
/* UI4 */
SIMPLE(ULONG, BYTE, VarUI4FromUI1);
NEGTST(ULONG, SHORT, VarUI4FromI2);
NEGTST(ULONG, LONG, VarUI4FromI4);
#define _VarUI4FromR4(flt,out) VarUI4FromR8((double)flt,out)
#define _VarUI4FromR8 VarUI4FromR8
#define _VarUI4FromCy VarUI4FromCy
#define _VarUI4FromDate(dt,out) VarUI4FromR8((double)dt,out)
#define _VarUI4FromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_UI4)
#define _VarUI4FromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_UI4)
SIMPLE(ULONG, VARIANT_BOOL, VarUI4FromBool);
NEGTST(ULONG, signed char, VarUI4FromI1);
SIMPLE(ULONG, USHORT, VarUI4FromUI2);
#define _VarUI4FromDec VarUI4FromDec
BOTHTST(ULONG, LONG64, VarUI4FromI8, UI4_MIN, UI4_MAX);
POSTST(ULONG, ULONG64, VarUI4FromUI8, UI4_MAX);
/* I8 */
SIMPLE(LONG64, BYTE, VarI8FromUI1);
SIMPLE(LONG64, SHORT, VarI8FromI2);
#define _VarI8FromR4 VarI8FromR8
#define _VarI8FromR8 VarI8FromR8
#define _VarI8FromCy VarI8FromCy
#define _VarI8FromDate(dt,out) VarI8FromR8((double)dt,out)
#define _VarI8FromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_I8)
#define _VarI8FromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_I8)
#define _VarI8FromBool _VarI8FromI2
SIMPLE(LONG64, signed char, VarI8FromI1);
SIMPLE(LONG64, USHORT, VarI8FromUI2);
SIMPLE(LONG64, LONG, VarI8FromI4);
SIMPLE(LONG64, ULONG, VarI8FromUI4);
#define _VarI8FromDec VarI8FromDec
POSTST(LONG64, ULONG64, VarI8FromUI8, I8_MAX);
/* UI8 */
SIMPLE(ULONG64, BYTE, VarUI8FromUI1);
NEGTST(ULONG64, SHORT, VarUI8FromI2);
#define _VarUI8FromR4 VarUI8FromR8
#define _VarUI8FromR8 VarUI8FromR8
#define _VarUI8FromCy VarUI8FromCy
#define _VarUI8FromDate(dt,out) VarUI8FromR8((double)dt,out)
#define _VarUI8FromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_UI8)
#define _VarUI8FromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_UI8)
#define _VarUI8FromBool _VarI8FromI2
NEGTST(ULONG64, signed char, VarUI8FromI1);
SIMPLE(ULONG64, USHORT, VarUI8FromUI2);
NEGTST(ULONG64, LONG, VarUI8FromI4);
SIMPLE(ULONG64, ULONG, VarUI8FromUI4);
#define _VarUI8FromDec VarUI8FromDec
NEGTST(ULONG64, LONG64, VarUI8FromI8);
/* R4 (float) */
SIMPLE(float, BYTE, VarR4FromUI1);
SIMPLE(float, SHORT, VarR4FromI2);
RETTYP _VarR4FromR8(double i, float* o) {
double d = i < 0.0 ? -i : i;
if (d > R4_MAX) return DISP_E_OVERFLOW;
*o = i;
return S_OK;
}
RETTYP _VarR4FromCy(CY i, float* o) { *o = (double)i.int64 / CY_MULTIPLIER_F; return S_OK; }
#define _VarR4FromDate(dt,out) _VarR4FromR8((double)dt,out)
#define _VarR4FromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_R4)
#define _VarR4FromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_R4)
#define _VarR4FromBool _VarR4FromI2
SIMPLE(float, signed char, VarR4FromI1);
SIMPLE(float, USHORT, VarR4FromUI2);
SIMPLE(float, LONG, VarR4FromI4);
SIMPLE(float, ULONG, VarR4FromUI4);
#define _VarR4FromDec VarR4FromDec
SIMPLE(float, LONG64, VarR4FromI8);
SIMPLE(float, ULONG64, VarR4FromUI8);
/* R8 (double) */
SIMPLE(double, BYTE, VarR8FromUI1);
SIMPLE(double, SHORT, VarR8FromI2);
SIMPLE(double, float, VarR8FromR4);
RETTYP _VarR8FromCy(CY i, double* o) { *o = (double)i.int64 / CY_MULTIPLIER_F; return S_OK; }
SIMPLE(double, DATE, VarR8FromDate);
#define _VarR8FromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_R8)
#define _VarR8FromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_R8)
#define _VarR8FromBool _VarR8FromI2
SIMPLE(double, signed char, VarR8FromI1);
SIMPLE(double, USHORT, VarR8FromUI2);
SIMPLE(double, LONG, VarR8FromI4);
SIMPLE(double, ULONG, VarR8FromUI4);
#define _VarR8FromDec VarR8FromDec
SIMPLE(double, LONG64, VarR8FromI8);
SIMPLE(double, ULONG64, VarR8FromUI8);
/* BOOL */
#define BOOLFUNC(src, func) RETTYP _##func(src in, VARIANT_BOOL* out) { \
*out = in ? VARIANT_TRUE : VARIANT_FALSE; return S_OK; }
BOOLFUNC(signed char,VarBoolFromI1);
BOOLFUNC(BYTE,VarBoolFromUI1);
BOOLFUNC(SHORT,VarBoolFromI2);
BOOLFUNC(USHORT,VarBoolFromUI2);
BOOLFUNC(LONG,VarBoolFromI4);
BOOLFUNC(ULONG,VarBoolFromUI4);
BOOLFUNC(LONG64,VarBoolFromI8);
BOOLFUNC(ULONG64,VarBoolFromUI8);
#define _VarBoolFromR4(flt,out) _VarBoolFromR8((double)flt,out)
BOOLFUNC(double,VarBoolFromR8);
#define _VarBoolFromCy(i,o) _VarBoolFromI8(i.int64,o)
#define _VarBoolFromDate(dt,out) _VarBoolFromR8((double)dt,out)
#define _VarBoolFromStr VarBoolFromStr
#define _VarBoolFromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, (BYTE*)out, VT_BOOL)
#define _VarBoolFromDec VarBoolFromDec
/* DECIMAL */
#define _VarDecFromUI1 VarDecFromUI4
#define _VarDecFromI2 VarDecFromI4
#define _VarDecFromR4 VarDecFromR8
#define _VarDecFromR8 VarDecFromR8
#define _VarDecFromCy VarDecFromCy
#define _VarDecFromDate(dt,out) VarDecFromR8((double)dt,out)
#define _VarDecFromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_DECIMAL)
#define _VarDecFromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_DECIMAL)
#define _VarDecFromBool VarDecFromBool
#define _VarDecFromI1 VarDecFromI4
#define _VarDecFromUI2 VarDecFromUI4
#define _VarDecFromI4 VarDecFromI4
#define _VarDecFromUI4 VarDecFromUI4
#define _VarDecFromI8 VarDecFromI8
#define _VarDecFromUI8 VarDecFromUI8
/* CY (Currency) */
#define _VarCyFromUI1 VarCyFromR8
#define _VarCyFromI2 VarCyFromR8
#define _VarCyFromR4 VarCyFromR8
#define _VarCyFromR8 VarCyFromR8
#define _VarCyFromDate VarCyFromR8
#define _VarCyFromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_CY)
#define _VarCyFromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_CY)
#define _VarCyFromBool VarCyFromR8
#define _VarCyFromI1 VarCyFromR8
#define _VarCyFromUI2 VarCyFromR8
#define _VarCyFromI4 VarCyFromR8
#define _VarCyFromUI4 VarCyFromR8
#define _VarCyFromDec VarCyFromDec
RETTYP _VarCyFromI8(LONG64 i, CY* o) {
if (i <= (I8_MIN/CY_MULTIPLIER) || i >= (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW;
o->int64 = i * CY_MULTIPLIER;
return S_OK;
}
#define _VarCyFromUI8 VarCyFromR8
/* DATE */
#define _VarDateFromUI1 VarDateFromR8
#define _VarDateFromI2 VarDateFromR8
#define _VarDateFromR4 VarDateFromR8
#define _VarDateFromR8 VarDateFromR8
#define _VarDateFromCy VarDateFromCy
#define _VarDateFromStr VarDateFromStr
#define _VarDateFromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_DATE)
#define _VarDateFromBool VarDateFromR8
#define _VarDateFromI1 VarDateFromR8
#define _VarDateFromUI2 VarDateFromR8
#define _VarDateFromI4 VarDateFromR8
#define _VarDateFromUI4 VarDateFromR8
#define _VarDateFromDec VarDateFromDec
#define _VarDateFromI8 VarDateFromR8
#define _VarDateFromUI8 VarDateFromR8
/* BSTR */
#define _VarBstrFromUI1 VarBstrFromUI4
#define _VarBstrFromI2 VarBstrFromI4
#define _VarBstrFromR4 VarBstrFromR8
#define _VarBstrFromR8 VarBstrFromR8
#define _VarBstrFromCy VarBstrFromCy
#define _VarBstrFromDate VarBstrFromDate
#define _VarBstrFromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_BSTR)
#define _VarBstrFromBool VarBstrFromBool
#define _VarBstrFromI1 VarBstrFromI4
#define _VarBstrFromUI2 VarBstrFromUI4
#define _VarBstrFromI4 VarBstrFromI4
#define _VarBstrFromUI4 VarBstrFromUI4
#define _VarBstrFromDec VarBstrFromDec
#define _VarBstrFromI8 VarBstrFromI8
#define _VarBstrFromUI8 VarBstrFromUI8
/* Macro to inline conversion from a float or double to any integer type,
* rounding according to the 'dutch' convention.
*/
#define OLEAUT32_DutchRound(typ, value, res) do { \
double whole = floor((double)value), fract = (double)value - whole; \
if (fract > 0.5) res = (typ)whole + (typ)1; \
else if (fract == 0.5) { typ is_odd = (typ)whole & 1; res = whole + is_odd; } \
else if (fract >= 0.0) res = (typ)whole; \
else if (fract == -0.5) { typ is_odd = (typ)whole & 1; res = whole - is_odd; } \
else if (fract > -0.5) res = (typ)whole; \
else res = (typ)whole - (typ)1; \
} while(0);
/* Localised text for variant conversions */
typedef struct tagVARIANT_TEXT
{
LPCWSTR szText;
BYTE langId;
BYTE iOffsetFalse;
BYTE iOffsetYes;
BYTE iOffsetNo;
BYTE iOffsetOn;
BYTE iOffsetOff;
} VARIANT_TEXT;
#define NUM_LOCALISED_LANGS 13
extern const VARIANT_TEXT VARIANT_LocalisedTextList[NUM_LOCALISED_LANGS];
const VARIANT_TEXT *VARIANT_GetLocalisedText(LANGID);
/* The localised characters that make up a valid number */
typedef struct tagVARIANT_NUMBER_CHARS
{
WCHAR cNegativeSymbol;
WCHAR cPositiveSymbol;
WCHAR cDecimalPoint;
WCHAR cDigitSeperator;
WCHAR cCurrencyLocal;
WCHAR cCurrencyLocal2;
WCHAR cCurrencyDecimalPoint;
WCHAR cCurrencyDigitSeperator;
} VARIANT_NUMBER_CHARS;
void VARIANT_GetLocalisedNumberChars(VARIANT_NUMBER_CHARS*,LCID,DWORD);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment