Let VarParseNumFromStr and VarNumFromParseNum cope with hex and oct

strings. Needed from VB conversions such as CLng, CInt, CByte...
This commit is contained in:
Fabian Cenedese 2004-03-16 19:15:04 +00:00 committed by Alexandre Julliard
parent ccd428e503
commit 5feedfdc73
2 changed files with 206 additions and 9 deletions

View File

@ -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 */

View File

@ -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<<pNumprs->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;
}