Fireball patch for fixing RtlUnicodeStringToInteger and RtlCharToInteger

<Fireball> Imported WINE's RtlUnicodeStringToInteger and RtlCharToInteger - they were seriously broken in our revision. Thanks to GreatLord for his help pointing out this bug with me :)

svn path=/trunk/; revision=15092
This commit is contained in:
Magnus Olsen 2005-05-07 22:17:03 +00:00
parent 456be5d16b
commit f6b87bd320

View file

@ -154,51 +154,96 @@ RtlAppendUnicodeStringToString(
}
/*
/**************************************************************************
* RtlCharToInteger (NTDLL.@)
* @implemented
* Converts a character string into its integer equivalent.
*
* RETURNS
* Success: STATUS_SUCCESS. value contains the converted number
* Failure: STATUS_INVALID_PARAMETER, if base is not 0, 2, 8, 10 or 16.
* STATUS_ACCESS_VIOLATION, if value is NULL.
*
* NOTES
* For base 0 it uses 10 as base and the string should be in the format
* "{whitespace} [+|-] [0[x|o|b]] {digits}".
* For other bases the string should be in the format
* "{whitespace} [+|-] {digits}".
* No check is made for value overflow, only the lower 32 bits are assigned.
* If str is NULL it crashes, as the native function does.
*
* DIFFERENCES
* This function does not read garbage behind '\0' as the native version does.
*/
NTSTATUS
STDCALL
RtlCharToInteger(
IN PCSZ String,
IN ULONG Base,
IN OUT PULONG Value)
PCSZ str, /* [I] '\0' terminated single-byte string containing a number */
ULONG base, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
PULONG value) /* [O] Destination for the converted value */
{
ULONG Val;
CHAR chCurrent;
int digit;
ULONG RunningTotal = 0;
char bMinus = 0;
*Value = 0;
while (*str != '\0' && *str <= ' ') {
str++;
} /* while */
if (Base == 0)
{
Base = 10;
if (*String == '0')
{
Base = 8;
String++;
if ((*String == 'x') && isxdigit (String[1]))
{
String++;
Base = 16;
}
}
}
if (*str == '+') {
str++;
} else if (*str == '-') {
bMinus = 1;
str++;
} /* if */
if (!isxdigit (*String))
return STATUS_INVALID_PARAMETER;
if (base == 0) {
base = 10;
if (str[0] == '0') {
if (str[1] == 'b') {
str += 2;
base = 2;
} else if (str[1] == 'o') {
str += 2;
base = 8;
} else if (str[1] == 'x') {
str += 2;
base = 16;
} /* if */
} /* if */
} else if (base != 2 && base != 8 && base != 10 && base != 16) {
return STATUS_INVALID_PARAMETER;
} /* if */
while (isxdigit (*String) &&
(Val = isdigit (*String) ? * String - '0' : (islower (*String)
? toupper (*String) : *String) - 'A' + 10) < Base)
{
*Value = *Value * Base + Val;
String++;
}
if (value == NULL) {
return STATUS_ACCESS_VIOLATION;
} /* if */
return STATUS_SUCCESS;
while (*str != '\0') {
chCurrent = *str;
if (chCurrent >= '0' && chCurrent <= '9') {
digit = chCurrent - '0';
} else if (chCurrent >= 'A' && chCurrent <= 'Z') {
digit = chCurrent - 'A' + 10;
} else if (chCurrent >= 'a' && chCurrent <= 'z') {
digit = chCurrent - 'a' + 10;
} else {
digit = -1;
} /* if */
if (digit < 0 || digit >= base) {
*value = bMinus ? -RunningTotal : RunningTotal;
return STATUS_SUCCESS;
} /* if */
RunningTotal = RunningTotal * base + digit;
str++;
} /* while */
*value = bMinus ? -RunningTotal : RunningTotal;
return STATUS_SUCCESS;
}
/*
* @implemented
*/
@ -807,113 +852,113 @@ RtlPrefixUnicodeString(
return FALSE;
}
/*
/**************************************************************************
* RtlUnicodeStringToInteger (NTDLL.@)
* @implemented
* Converts an unicode string into its integer equivalent.
*
* Note that regardless of success or failure status, we should leave the
* partial value in Value. An error is never returned based on the chars
* in the string.
* RETURNS
* Success: STATUS_SUCCESS. value contains the converted number
* Failure: STATUS_INVALID_PARAMETER, if base is not 0, 2, 8, 10 or 16.
* STATUS_ACCESS_VIOLATION, if value is NULL.
*
* This function does check the base. Only 2, 8, 10, 16 are permitted,
* else STATUS_INVALID_PARAMETER is returned.
* NOTES
* For base 0 it uses 10 as base and the string should be in the format
* "{whitespace} [+|-] [0[x|o|b]] {digits}".
* For other bases the string should be in the format
* "{whitespace} [+|-] {digits}".
* No check is made for value overflow, only the lower 32 bits are assigned.
* If str is NULL it crashes, as the native function does.
*
* Note that regardless of success or failure status, we should leave the
* partial value in Value. An error is never returned based on the chars
* in the string.
*
* DIFFERENCES
* This function does not read garbage on string length 0 as the native
* version does.
*/
NTSTATUS
STDCALL
RtlUnicodeStringToInteger(
IN PUNICODE_STRING String,
IN ULONG Base,
OUT PULONG Value)
PUNICODE_STRING str, /* [I] Unicode string to be converted */
ULONG base, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
PULONG value) /* [O] Destination for the converted value */
{
PWCHAR Str;
ULONG lenmin = 0;
ULONG i;
ULONG Val;
BOOLEAN addneg = FALSE;
NTSTATUS Status = STATUS_SUCCESS;
LPWSTR lpwstr = str->Buffer;
USHORT CharsRemaining = str->Length / sizeof(WCHAR);
WCHAR wchCurrent;
int digit;
ULONG RunningTotal = 0;
char bMinus = 0;
*Value = 0;
Str = String->Buffer;
while (CharsRemaining >= 1 && *lpwstr <= ' ') {
lpwstr++;
CharsRemaining--;
} /* while */
if( Base && Base != 2 && Base != 8 && Base != 10 && Base != 16 )
return STATUS_INVALID_PARAMETER;
if (CharsRemaining >= 1) {
if (*lpwstr == '+') {
lpwstr++;
CharsRemaining--;
} else if (*lpwstr == '-') {
bMinus = 1;
lpwstr++;
CharsRemaining--;
} /* if */
} /* if */
for (i = 0; i < String->Length / sizeof(WCHAR); i++)
{
if (*Str == L'b')
{
Base = 2;
lenmin++;
}
else if (*Str == L'o')
{
Base = 8;
lenmin++;
}
else if (*Str == L'd')
{
Base = 10;
lenmin++;
}
else if (*Str == L'x')
{
Base = 16;
lenmin++;
}
else if (*Str == L'+')
{
lenmin++;
}
else if (*Str == L'-')
{
addneg = TRUE;
lenmin++;
}
else if ((*Str > L'1') && (Base == 2))
{
break;
}
else if (((*Str > L'7') || (*Str < L'0')) && (Base == 8))
{
break;
}
else if (((*Str > L'9') || (*Str < L'0')) && (Base == 10))
{
break;
}
else if ( ((*Str > L'9') || (*Str < L'0')) &&
((towupper (*Str) > L'F') || (towupper (*Str) < L'A')) &&
(Base == 16))
{
break;
}
Str++;
}
if (base == 0) {
base = 10;
if (CharsRemaining >= 2 && lpwstr[0] == '0') {
if (lpwstr[1] == 'b') {
lpwstr += 2;
CharsRemaining -= 2;
base = 2;
} else if (lpwstr[1] == 'o') {
lpwstr += 2;
CharsRemaining -= 2;
base = 8;
} else if (lpwstr[1] == 'x') {
lpwstr += 2;
CharsRemaining -= 2;
base = 16;
} /* if */
} /* if */
} else if (base != 2 && base != 8 && base != 10 && base != 16) {
return STATUS_INVALID_PARAMETER;
} /* if */
Str = String->Buffer + lenmin;
if (value == NULL) {
return STATUS_ACCESS_VIOLATION;
} /* if */
if (Base == 0)
Base = 10;
while (CharsRemaining >= 1) {
wchCurrent = *lpwstr;
if (wchCurrent >= '0' && wchCurrent <= '9') {
digit = wchCurrent - '0';
} else if (wchCurrent >= 'A' && wchCurrent <= 'Z') {
digit = wchCurrent - 'A' + 10;
} else if (wchCurrent >= 'a' && wchCurrent <= 'z') {
digit = wchCurrent - 'a' + 10;
} else {
digit = -1;
} /* if */
if (digit < 0 || digit >= base) {
*value = bMinus ? -RunningTotal : RunningTotal;
return STATUS_SUCCESS;
} /* if */
while (iswxdigit (*Str) &&
(Val =
iswdigit (*Str) ?
*Str - L'0' :
(towupper (*Str) - L'A' + 10)) < Base)
{
*Value = *Value * Base + Val;
Str++;
}
RunningTotal = RunningTotal * base + digit;
lpwstr++;
CharsRemaining--;
} /* while */
if (addneg == TRUE)
*Value *= -1;
return Status;
*value = bMinus ? -RunningTotal : RunningTotal;
return STATUS_SUCCESS;
}
/*
* @implemented
*