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 * @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 NTSTATUS
STDCALL STDCALL
RtlCharToInteger( RtlCharToInteger(
IN PCSZ String, PCSZ str, /* [I] '\0' terminated single-byte string containing a number */
IN ULONG Base, ULONG base, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
IN OUT PULONG Value) 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) if (*str == '+') {
{ str++;
Base = 10; } else if (*str == '-') {
if (*String == '0') bMinus = 1;
{ str++;
Base = 8; } /* if */
String++;
if ((*String == 'x') && isxdigit (String[1]))
{
String++;
Base = 16;
}
}
}
if (!isxdigit (*String)) if (base == 0) {
return STATUS_INVALID_PARAMETER; 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) && if (value == NULL) {
(Val = isdigit (*String) ? * String - '0' : (islower (*String) return STATUS_ACCESS_VIOLATION;
? toupper (*String) : *String) - 'A' + 10) < Base) } /* if */
{
*Value = *Value * Base + Val;
String++;
}
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 * @implemented
*/ */
@ -807,113 +852,113 @@ RtlPrefixUnicodeString(
return FALSE; return FALSE;
} }
/**************************************************************************
* RtlUnicodeStringToInteger (NTDLL.@)
/*
* @implemented * @implemented
* Converts an unicode string into its integer equivalent.
* *
* Note that regardless of success or failure status, we should leave the * RETURNS
* partial value in Value. An error is never returned based on the chars * Success: STATUS_SUCCESS. value contains the converted number
* in the string. * 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, * NOTES
* else STATUS_INVALID_PARAMETER is returned. * 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 NTSTATUS
STDCALL STDCALL
RtlUnicodeStringToInteger( RtlUnicodeStringToInteger(
IN PUNICODE_STRING String, PUNICODE_STRING str, /* [I] Unicode string to be converted */
IN ULONG Base, ULONG base, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
OUT PULONG Value) PULONG value) /* [O] Destination for the converted value */
{ {
PWCHAR Str; LPWSTR lpwstr = str->Buffer;
ULONG lenmin = 0; USHORT CharsRemaining = str->Length / sizeof(WCHAR);
ULONG i; WCHAR wchCurrent;
ULONG Val; int digit;
BOOLEAN addneg = FALSE; ULONG RunningTotal = 0;
NTSTATUS Status = STATUS_SUCCESS; char bMinus = 0;
*Value = 0; while (CharsRemaining >= 1 && *lpwstr <= ' ') {
Str = String->Buffer; lpwstr++;
CharsRemaining--;
} /* while */
if( Base && Base != 2 && Base != 8 && Base != 10 && Base != 16 ) if (CharsRemaining >= 1) {
return STATUS_INVALID_PARAMETER; if (*lpwstr == '+') {
lpwstr++;
CharsRemaining--;
} else if (*lpwstr == '-') {
bMinus = 1;
lpwstr++;
CharsRemaining--;
} /* if */
} /* if */
for (i = 0; i < String->Length / sizeof(WCHAR); i++) if (base == 0) {
{ base = 10;
if (*Str == L'b') if (CharsRemaining >= 2 && lpwstr[0] == '0') {
{ if (lpwstr[1] == 'b') {
Base = 2; lpwstr += 2;
lenmin++; CharsRemaining -= 2;
} base = 2;
else if (*Str == L'o') } else if (lpwstr[1] == 'o') {
{ lpwstr += 2;
Base = 8; CharsRemaining -= 2;
lenmin++; base = 8;
} } else if (lpwstr[1] == 'x') {
else if (*Str == L'd') lpwstr += 2;
{ CharsRemaining -= 2;
Base = 10; base = 16;
lenmin++; } /* if */
} } /* if */
else if (*Str == L'x') } else if (base != 2 && base != 8 && base != 10 && base != 16) {
{ return STATUS_INVALID_PARAMETER;
Base = 16; } /* if */
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++;
}
Str = String->Buffer + lenmin; if (value == NULL) {
return STATUS_ACCESS_VIOLATION;
} /* if */
if (Base == 0) while (CharsRemaining >= 1) {
Base = 10; 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) && RunningTotal = RunningTotal * base + digit;
(Val = lpwstr++;
iswdigit (*Str) ? CharsRemaining--;
*Str - L'0' : } /* while */
(towupper (*Str) - L'A' + 10)) < Base)
{
*Value = *Value * Base + Val;
Str++;
}
if (addneg == TRUE) *value = bMinus ? -RunningTotal : RunningTotal;
*Value *= -1; return STATUS_SUCCESS;
return Status;
} }
/* /*
* @implemented * @implemented
* *