Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

211 lines
6.5 KiB

/*++
Copyright (c) Microsoft Corporation
Module Name:
rtlfindcharinunicodestring.c
Abstract:
This module implements NLS support functions for NT.
Author:
Mark Lucovsky (markl) 16-Apr-1991
Environment:
Kernel or user-mode
Revision History:
16-Feb-1993 JulieB Added Upcase Rtl Routines.
08-Mar-1993 JulieB Moved Upcase Macro to ntrtlp.h.
02-Apr-1993 JulieB Fixed RtlAnsiCharToUnicodeChar to use transl. tbls.
02-Apr-1993 JulieB Fixed BUFFER_TOO_SMALL check.
28-May-1993 JulieB Fixed code to properly handle DBCS.
November 30, 2001 JayKrell broken out of nls.c for easier reuse
--*/
NTSTATUS
RtlFindCharInUnicodeString(
ULONG Flags,
PCUNICODE_STRING StringToSearch,
PCUNICODE_STRING CharSet,
USHORT *NonInclusivePrefixLength
)
{
NTSTATUS Status;
USHORT PrefixLengthFound = 0;
USHORT CharsToSearch = 0;
int MovementDirection = 0;
PCWSTR Cursor = NULL;
BOOLEAN Found = FALSE;
USHORT CharSetChars = 0;
PCWSTR CharSetBuffer = NULL;
USHORT i;
if (NonInclusivePrefixLength != 0)
*NonInclusivePrefixLength = 0;
if (((Flags & ~(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END |
RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET |
RTL_FIND_CHAR_IN_UNICODE_STRING_CASE_INSENSITIVE)) != 0) ||
(NonInclusivePrefixLength == NULL)) {
Status = STATUS_INVALID_PARAMETER;
goto Exit;
}
Status = RtlValidateUnicodeString(0, StringToSearch);
if (!NT_SUCCESS(Status))
goto Exit;
Status = RtlValidateUnicodeString(0, CharSet);
if (!NT_SUCCESS(Status))
goto Exit;
CharsToSearch = StringToSearch->Length / sizeof(WCHAR);
CharSetChars = CharSet->Length / sizeof(WCHAR);
CharSetBuffer = CharSet->Buffer;
if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END) {
MovementDirection = -1;
Cursor = StringToSearch->Buffer + CharsToSearch - 1;
} else {
MovementDirection = 1;
Cursor = StringToSearch->Buffer;
}
if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_CASE_INSENSITIVE) {
// Unicode standard says to always do case insensitive comparisons in lower case since the case mappings are
// asymmetric.
WCHAR CharSetStackBuffer[32]; // optimized pre-downcased for case insensitive
// Optimization for the case of a relatively small char set to match
if (CharSetChars <= RTL_NUMBER_OF(CharSetStackBuffer)) {
for (i=0; i<CharSetChars; i++)
CharSetStackBuffer[i] = RtlDowncaseUnicodeChar(CharSetBuffer[i]);
while (CharsToSearch != 0) {
const WCHAR wch = RtlDowncaseUnicodeChar(*Cursor);
if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET) {
for (i=0; i<CharSetChars; i++) {
if (wch == CharSetStackBuffer[i])
break;
}
if (i == CharSetChars)
break;
} else {
for (i=0; i<CharSetChars; i++) {
if (wch == CharSetStackBuffer[i])
break;
}
if (i != CharSetChars)
break;
}
CharsToSearch--;
Cursor += MovementDirection;
}
} else {
while (CharsToSearch != 0) {
const WCHAR wch = RtlDowncaseUnicodeChar(*Cursor);
if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET) {
for (i=0; i<CharSetChars; i++) {
if (wch == RtlDowncaseUnicodeChar(CharSetBuffer[i])) {
break;
}
}
if (i == CharSetChars)
break;
} else {
for (i=0; i<CharSetChars; i++) {
if (wch == RtlDowncaseUnicodeChar(CharSetBuffer[i])) {
break;
}
}
if (i != CharSetChars)
break;
}
CharsToSearch--;
Cursor += MovementDirection;
}
}
} else {
if (CharSetChars == 1) {
// Significant optimization for looking for one character.
const WCHAR wchSearchChar = CharSetBuffer[0];
if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET) {
while (CharsToSearch != 0) {
if (*Cursor != wchSearchChar)
break;
CharsToSearch--;
Cursor += MovementDirection;
}
} else {
while (CharsToSearch != 0) {
if (*Cursor == wchSearchChar)
break;
CharsToSearch--;
Cursor += MovementDirection;
}
}
} else {
while (CharsToSearch != 0) {
const WCHAR wch = *Cursor;
if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET) {
for (i=0; i<CharSetChars; i++) {
if (wch == CharSetBuffer[i])
break;
}
if (i == CharSetChars)
break;
} else {
for (i=0; i<CharSetChars; i++) {
if (wch == CharSetBuffer[i])
break;
}
if (i != CharSetChars)
break;
}
CharsToSearch--;
Cursor += MovementDirection;
}
}
}
if (CharsToSearch == 0) {
Status = STATUS_NOT_FOUND;
goto Exit;
}
CharsToSearch--;
if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END)
PrefixLengthFound = (USHORT) (CharsToSearch * sizeof(WCHAR));
else
PrefixLengthFound = (USHORT) (StringToSearch->Length - (CharsToSearch * sizeof(WCHAR)));
*NonInclusivePrefixLength = PrefixLengthFound;
Status = STATUS_SUCCESS;
Exit:
return Status;
}