diff --git a/dlls/oleaut32/tests/vartest.c b/dlls/oleaut32/tests/vartest.c index eb80a977924..0113250c74e 100644 --- a/dlls/oleaut32/tests/vartest.c +++ b/dlls/oleaut32/tests/vartest.c @@ -789,6 +789,45 @@ static void test_VarParseNumFromStr(void) EXPECTRGB(2,0); EXPECTRGB(3,FAILDIG); + /* VB hex */ + CONVERT("&HF800", NUMPRS_HEX_OCT); + EXPECT(4,NUMPRS_HEX_OCT,0x40,6,4,0); + EXPECTRGB(0,15); + EXPECTRGB(1,8); + EXPECTRGB(2,0); + EXPECTRGB(3,0); + EXPECTRGB(4,FAILDIG); + + /* VB hex lower case and leading zero */ + CONVERT("&h0abcd", NUMPRS_HEX_OCT); + EXPECT(4,NUMPRS_HEX_OCT,0x40,7,4,0); + EXPECTRGB(0,10); + EXPECTRGB(1,11); + EXPECTRGB(2,12); + EXPECTRGB(3,13); + EXPECTRGB(4,FAILDIG); + + /* VB oct */ + CONVERT("&O300", NUMPRS_HEX_OCT); + EXPECT(3,NUMPRS_HEX_OCT,0x40,5,3,0); + EXPECTRGB(0,3); + EXPECTRGB(1,0); + EXPECTRGB(2,0); + EXPECTRGB(3,FAILDIG); + + /* VB oct lower case and leading zero */ + CONVERT("&o0777", NUMPRS_HEX_OCT); + EXPECT(3,NUMPRS_HEX_OCT,0x40,6,3,0); + EXPECTRGB(0,7); + EXPECTRGB(1,7); + EXPECTRGB(2,7); + EXPECTRGB(3,FAILDIG); + + /* VB oct char bigger than 7 */ + CONVERT("&o128", NUMPRS_HEX_OCT); + EXPECTFAIL; + EXPECTRGB(0,FAILDIG); + /** NUMPRS_PARENS **/ /* Empty parens = error */ diff --git a/dlls/oleaut32/variant.c b/dlls/oleaut32/variant.c index cdfb3787e3a..8a2e43cccc4 100644 --- a/dlls/oleaut32/variant.c +++ b/dlls/oleaut32/variant.c @@ -1464,6 +1464,8 @@ void VARIANT_GetLocalisedNumberChars(VARIANT_NUMBER_CHARS *lpChars, LCID lcid, D #define B_EXPONENT_START 0x4 #define B_INEXACT_ZEROS 0x8 #define B_LEADING_ZERO 0x10 +#define B_PROCESSING_HEX 0x20 +#define B_PROCESSING_OCT 0x40 /********************************************************************** * VarParseNumFromStr [OLEAUT32.46] @@ -1581,6 +1583,23 @@ HRESULT WINAPI VarParseNumFromStr(OLECHAR *lpszStr, LCID lcid, ULONG dwFlags, chars.cCurrencyDigitSeperator = chars.cDigitSeperator; } + if ((*lpszStr == '&' && (*(lpszStr+1) == 'H' || *(lpszStr+1) == 'h')) && + pNumprs->dwInFlags & NUMPRS_HEX_OCT) + { + dwState |= B_PROCESSING_HEX; + pNumprs->dwOutFlags |= NUMPRS_HEX_OCT; + cchUsed=cchUsed+2; + lpszStr=lpszStr+2; + } + else if ((*lpszStr == '&' && (*(lpszStr+1) == 'O' || *(lpszStr+1) == 'o')) && + pNumprs->dwInFlags & NUMPRS_HEX_OCT) + { + dwState |= B_PROCESSING_OCT; + pNumprs->dwOutFlags |= NUMPRS_HEX_OCT; + cchUsed=cchUsed+2; + lpszStr=lpszStr+2; + } + /* Strip Leading zeros */ while (*lpszStr == '0') { @@ -1624,7 +1643,8 @@ HRESULT WINAPI VarParseNumFromStr(OLECHAR *lpszStr, LCID lcid, ULONG dwFlags, } else { - if (pNumprs->cDig >= iMaxDigits) + if ((pNumprs->cDig >= iMaxDigits) && !(dwState & B_PROCESSING_HEX) + && !(dwState & B_PROCESSING_OCT)) { pNumprs->dwOutFlags |= NUMPRS_INEXACT; @@ -1639,8 +1659,13 @@ HRESULT WINAPI VarParseNumFromStr(OLECHAR *lpszStr, LCID lcid, ULONG dwFlags, } else { + if ((dwState & B_PROCESSING_OCT) && ((*lpszStr == '8') || (*lpszStr == '9'))) { + return DISP_E_TYPEMISMATCH; + } + if (pNumprs->dwOutFlags & NUMPRS_DECIMAL) pNumprs->nPwr10--; /* Count decimal points in nPwr10 */ + rgbTmp[pNumprs->cDig] = *lpszStr - '0'; } pNumprs->cDig++; @@ -1694,6 +1719,24 @@ HRESULT WINAPI VarParseNumFromStr(OLECHAR *lpszStr, LCID lcid, ULONG dwFlags, dwState |= B_NEGATIVE_EXPONENT; cchUsed++; } + else if (((*lpszStr >= 'a' && *lpszStr <= 'f') || + (*lpszStr >= 'A' && *lpszStr <= 'F')) && + dwState & B_PROCESSING_HEX) + { + if (pNumprs->cDig >= iMaxDigits) + { + return DISP_E_OVERFLOW; + } + else + { + if (*lpszStr >= 'a') + rgbTmp[pNumprs->cDig] = *lpszStr - 'a' + 10; + else + rgbTmp[pNumprs->cDig] = *lpszStr - 'A' + 10; + } + pNumprs->cDig++; + cchUsed++; + } else break; /* Stop at an unrecognised character */ @@ -1724,14 +1767,26 @@ HRESULT WINAPI VarParseNumFromStr(OLECHAR *lpszStr, LCID lcid, ULONG dwFlags, /* cDig of X and writes X+Y where Y>=0 number of digits to rgbDig */ memcpy(rgbDig, rgbTmp, pNumprs->cDig * sizeof(BYTE)); - while (pNumprs->cDig > 1 && !rgbTmp[pNumprs->cDig - 1]) - { - if (pNumprs->dwOutFlags & NUMPRS_DECIMAL) - pNumprs->nPwr10--; - else - pNumprs->nPwr10++; + if (dwState & B_PROCESSING_HEX) { + /* hex numbers have always the same format */ + pNumprs->nPwr10=0; + pNumprs->nBaseShift=4; + } else { + if (dwState & B_PROCESSING_OCT) { + /* oct numbers have always the same format */ + pNumprs->nPwr10=0; + pNumprs->nBaseShift=3; + } else { + while (pNumprs->cDig > 1 && !rgbTmp[pNumprs->cDig - 1]) + { + if (pNumprs->dwOutFlags & NUMPRS_DECIMAL) + pNumprs->nPwr10--; + else + pNumprs->nPwr10++; - pNumprs->cDig--; + pNumprs->cDig--; + } + } } } else { @@ -1866,7 +1921,110 @@ HRESULT WINAPI VarNumFromParseNum(NUMPARSE *pNumprs, BYTE *rgbDig, if (pNumprs->nBaseShift) { /* nBaseShift indicates a hex or octal number */ - FIXME("nBaseShift=%d not yet implemented, returning overflow\n", pNumprs->nBaseShift); + ULONG64 ul64 = 0; + LONG64 l64; + int i; + + /* Convert the hex or octal number string into a UI64 */ + for (i = 0; i < pNumprs->cDig; i++) + { + if (ul64 > ((UI8_MAX>>pNumprs->nBaseShift) - rgbDig[i])) + { + TRACE("Overflow multiplying digits\n"); + return DISP_E_OVERFLOW; + } + ul64 = (ul64<nBaseShift) + rgbDig[i]; + } + + /* also make a negative representation */ + l64=-ul64; + + /* Try signed and unsigned types in size order */ + if (dwVtBits & VTBIT_I1 && ((ul64 <= I1_MAX)||(l64 >= I1_MIN))) + { + V_VT(pVarDst) = VT_I1; + if (ul64 <= I1_MAX) + V_I1(pVarDst) = ul64; + else + V_I1(pVarDst) = l64; + return S_OK; + } + else if (dwVtBits & VTBIT_UI1 && ul64 <= UI1_MAX) + { + V_VT(pVarDst) = VT_UI1; + V_UI1(pVarDst) = ul64; + return S_OK; + } + else if (dwVtBits & VTBIT_I2 && ((ul64 <= I2_MAX)||(l64 >= I2_MIN))) + { + V_VT(pVarDst) = VT_I2; + if (ul64 <= I2_MAX) + V_I2(pVarDst) = ul64; + else + V_I2(pVarDst) = l64; + return S_OK; + } + else if (dwVtBits & VTBIT_UI2 && ul64 <= UI2_MAX) + { + V_VT(pVarDst) = VT_UI2; + V_UI2(pVarDst) = ul64; + return S_OK; + } + else if (dwVtBits & VTBIT_I4 && ((ul64 <= I4_MAX)||(l64 >= I4_MIN))) + { + V_VT(pVarDst) = VT_I4; + if (ul64 <= I4_MAX) + V_I4(pVarDst) = ul64; + else + V_I4(pVarDst) = l64; + return S_OK; + } + else if (dwVtBits & VTBIT_UI4 && ul64 <= UI4_MAX) + { + V_VT(pVarDst) = VT_UI4; + V_UI4(pVarDst) = ul64; + return S_OK; + } + else if (dwVtBits & VTBIT_I8 && ((ul64 <= I4_MAX)||(l64>=I4_MIN))) + { + V_VT(pVarDst) = VT_I8; + V_I8(pVarDst) = ul64; + return S_OK; + } + else if (dwVtBits & VTBIT_UI8) + { + V_VT(pVarDst) = VT_UI8; + V_UI8(pVarDst) = ul64; + return S_OK; + } + else if ((dwVtBits & REAL_VTBITS) == VTBIT_DECIMAL) + { + V_VT(pVarDst) = VT_DECIMAL; + DEC_SIGNSCALE(&V_DECIMAL(pVarDst)) = SIGNSCALE(DECIMAL_POS,0); + DEC_HI32(&V_DECIMAL(pVarDst)) = 0; + DEC_LO64(&V_DECIMAL(pVarDst)) = ul64; + return S_OK; + } + else if (dwVtBits & VTBIT_R4 && ((ul64 <= I4_MAX)||(l64 >= I4_MIN))) + { + V_VT(pVarDst) = VT_R4; + if (ul64 <= I4_MAX) + V_R4(pVarDst) = ul64; + else + V_R4(pVarDst) = l64; + return S_OK; + } + else if (dwVtBits & VTBIT_R8 && ((ul64 <= I4_MAX)||(l64 >= I4_MIN))) + { + V_VT(pVarDst) = VT_R8; + if (ul64 <= I4_MAX) + V_R8(pVarDst) = ul64; + else + V_R8(pVarDst) = l64; + return S_OK; + } + + TRACE("Overflow: possible return types: 0x%lx, value: %s\n", dwVtBits, wine_dbgstr_longlong(ul64)); return DISP_E_OVERFLOW; }