Hi,
Once more, with patch...
Cheers,
Jon
Changelog:
Jon Griffiths <jon_p_griffiths@yahoo.com>
+dlls/oleaut32/variant.c dlls/oleaut32/variant.h
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.
__________________________________
Do you Yahoo!?
The New Yahoo! Shopping - with improved product search
http://shopping.yahoo.com
diff -uP --minimal wine/dlls/oleaut32/variant.c wine-cumul1/dlls/oleaut32/variant.c
--- wine/dlls/oleaut32/variant.c 2003-09-17 14:37:21.000000000 +0100
+++ wine-cumul1/dlls/oleaut32/variant.c 2003-09-30 20:16:21.000000000 +0100
@@ -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
*/
@@ -675,7 +656,7 @@
RtlCreateUnicodeStringFromAsciiz( &usBuffer, strIn );
pNewString = usBuffer.Buffer;
-
+
bstr = SysAllocString( pNewString );
RtlFreeUnicodeString( &usBuffer );
return bstr;
@@ -747,272 +728,6 @@
}
/******************************************************************************
- * 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 @@
* 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 @@
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 @@
* 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 @@
* 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 @@
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);
-
- memset(pvarg, 0, sizeof (VARIANTARG));
- V_VT(pvarg) = VT_EMPTY;
+ TRACE("(%p)\n", pVarg);
- 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 )
- {
- 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;
- }
+ if (V_BSTR(pVarg))
+ SysFreeString(V_BSTR(pVarg));
+ }
+ else if (V_VT(pVarg) == VT_RECORD)
+ {
+ 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));
+ }
+ else if (V_VT(pVarg) == VT_VARIANT)
+ {
+ if (V_VARIANTREF(pVarg))
+ VariantClear(V_VARIANTREF(pVarg));
}
}
-
- /*
- * Empty all the fields and mark the type as empty.
- */
- memset(pvarg, 0, sizeof (VARIANTARG));
- V_VT(pvarg) = VT_EMPTY;
+ V_VT(pVarg) = VT_EMPTY;
}
-
- return res;
+ 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 @@
/******************************************************************************
* 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 @@
/******************************************************************************
* 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 @@
/******************************************************************************
* 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)
@@ -2271,7 +2129,7 @@
/* Convert the source variant to a "byvalue" variant.
*/
VARIANTARG Variant;
-
+
if ((V_VT(pvargSrc) & 0xf000) != VT_BYREF) {
FIXME("VT_TYPEMASK %x is unhandled.\n",V_VT(pvargSrc) & VT_TYPEMASK);
return E_FAIL;
@@ -2490,39 +2348,8 @@
*/
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 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 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 @@
/* 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 @@
/* Check range of value.
*/
- if( dateIn < -(FLT_MAX) || dateIn > FLT_MAX )
+ if( dateIn < -(R4_MAX) || dateIn > R4_MAX )
{
return DISP_E_OVERFLOW;
}
@@ -3064,38 +2829,8 @@
*/
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 );
-
- /* 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;
+ TRACE("(%s, 0x%08lx, 0x%08lx, %p)\n", debugstr_w(strIn), lcid, dwFlags, pfltOut);
+ return _VarR4FromStr(strIn, lcid, dwFlags, pfltOut);
}
/**********************************************************************
@@ -3221,31 +2956,8 @@
*/
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 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 @@
}
}
- HeapFree( GetProcessHeap(), 0, pNewString );
-
return ret;
}
@@ -3836,7 +3545,7 @@
/* Check range of value.
*/
- if( bIn > CHAR_MAX )
+ if( bIn > I1_MAX )
{
return DISP_E_OVERFLOW;
}
@@ -3853,7 +3562,7 @@
{
TRACE("( %d, %p ), stub\n", uiIn, pcOut );
- if( uiIn > CHAR_MAX )
+ if( uiIn > I1_MAX )
{
return DISP_E_OVERFLOW;
}
@@ -3870,7 +3579,7 @@
{
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 @@
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 @@
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 @@
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 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 @@
{
TRACE("( %d, %p ), stub\n", uiIn, pcOut );
- if( uiIn > CHAR_MAX )
+ if( uiIn > I1_MAX )
{
return DISP_E_OVERFLOW;
}
@@ -4010,7 +3688,7 @@
{
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 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 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 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 @@
* 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,101 +4234,762 @@
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;
- FIXME("(%s,flags=%lx,....), partial stub!\n",debugstr_w(strIn),dwFlags);
- FIXME("numparse: cDig=%d, InFlags=%lx\n",pnumprs->cDig,pnumprs->dwInFlags);
+ TRACE("(%s,%ld,%ld,%p,%p)\n", debugstr_w(lpszStr), lcid, dwFlags, pNumprs, rgbDig);
- /* The other struct components are to be set by us */
- memset(rgbDig,0,pnumprs->cDig);
+ if (pNumprs->dwInFlags & NUMPRS_HEX_OCT)
+ FIXME("dwInFlags & NUMPRS_HEX_OCT not yet implemented!\n");
- /* FIXME: Just patching some values in */
- pnumprs->nPwr10 = 0;
- pnumprs->nBaseShift = 0;
- pnumprs->cchUsed = lastent;
- pnumprs->dwOutFlags = NUMPRS_DECIMAL;
+ if (!pNumprs || !rgbDig)
+ return E_INVALIDARG;
- 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;
- }
- } else if ((strIn[i]=='-') && (foundNum==FALSE)) {
- pnumprs->dwOutFlags |= NUMPRS_NEG;
+ if (pNumprs->cDig < iMaxDigits)
+ iMaxDigits = pNumprs->cDig;
+
+ pNumprs->cDig = 0;
+ pNumprs->dwOutFlags = 0;
+ pNumprs->cchUsed = 0;
+ pNumprs->nBaseShift = 0;
+ pNumprs->nPwr10 = 0;
+
+ if (!lpszStr)
+ return DISP_E_TYPEMISMATCH;
+
+ VARIANT_GetLocalisedNumberChars(&chars, lcid, dwFlags);
+
+ /* 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 (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++;
+ }
}
- pnumprs->cDig = cDig;
- TRACE("numparse out: cDig=%d, OutFlags=%lx\n",pnumprs->cDig,pnumprs->dwOutFlags);
- return S_OK;
+ 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++;
+ }
+ 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 * pvar)
+HRESULT WINAPI VarNumFromParseNum(NUMPARSE *pNumprs, BYTE *rgbDig,
+ ULONG dwVtBits, VARIANT *pVarDst)
{
- DWORD xint;
+ /* 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.
+ */
+ 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;
+ }
}
- VariantInit(pvar);
- if (dwVtBits & VTBIT_I4) {
- V_VT(pvar) = VT_I4;
- V_UNION(pvar,intVal) = xint;
- return S_OK;
+ /* 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);
+
+ 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++;
+ }
}
- if (dwVtBits & VTBIT_R8) {
- V_VT(pvar) = VT_R8;
- V_UNION(pvar,dblVal) = xint;
- return S_OK;
+
+ /* 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;
+ }
+ 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;
- return S_OK;
+ 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_UI1 && ul64 <= UI1_MAX)
+ {
+ V_VT(pVarDst) = VT_UI1;
+ V_UI1(pVarDst) = ul64;
+ return S_OK;
+ }
+ 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;
+ }
}
- if (dwVtBits & VTBIT_I2) {
- V_VT(pvar) = VT_I2;
- V_UNION(pvar,iVal) = xint;
+ }
+
+ 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");
}
- /* 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 (!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
}
+ }
- FIXME("vtbitmask is unsupported %lx, int=%d\n",dwVtBits, (int) xint);
- return E_FAIL;
+ 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]
*/
@@ -5338,7 +5571,7 @@
LONGLONG lVal = -1;
LONGLONG rVal = -1;
LONGLONG res = -1;
- int resT = 0; /* Testing has shown I2 & I2 == I2, all else
+ int resT = 0; /* Testing has shown I2 & I2 == I2, all else
becomes I4, even unsigned ints (incl. UI2) */
lOk = TRUE;
@@ -5736,7 +5969,7 @@
LONGLONG lVal = -1;
LONGLONG rVal = -1;
LONGLONG res = -1;
- int resT = 0; /* Testing has shown I2 & I2 == I2, all else
+ int resT = 0; /* Testing has shown I2 & I2 == I2, all else
becomes I4, even unsigned ints (incl. UI2) */
lOk = TRUE;
diff -uP --minimal wine/dlls/oleaut32/variant.h wine-cumul1/dlls/oleaut32/variant.h
--- wine/dlls/oleaut32/variant.h 1970-01-01 01:00:00.000000000 +0100
+++ wine-cumul1/dlls/oleaut32/variant.h 2003-09-30 20:16:25.000000000 +0100
@@ -0,0 +1,418 @@
+/*
+ * 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
+ */
+#include "config.h"
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+#include "windef.h"
+#include "winerror.h"
+#include "wine/debug.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);