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

  1. /*++
  2. Copyright (c) Microsoft Corporation
  3. Module Name:
  4. rtlfindcharinunicodestring.c
  5. Abstract:
  6. This module implements NLS support functions for NT.
  7. Author:
  8. Mark Lucovsky (markl) 16-Apr-1991
  9. Environment:
  10. Kernel or user-mode
  11. Revision History:
  12. 16-Feb-1993 JulieB Added Upcase Rtl Routines.
  13. 08-Mar-1993 JulieB Moved Upcase Macro to ntrtlp.h.
  14. 02-Apr-1993 JulieB Fixed RtlAnsiCharToUnicodeChar to use transl. tbls.
  15. 02-Apr-1993 JulieB Fixed BUFFER_TOO_SMALL check.
  16. 28-May-1993 JulieB Fixed code to properly handle DBCS.
  17. November 30, 2001 JayKrell broken out of nls.c for easier reuse
  18. --*/
  19. NTSTATUS
  20. RtlFindCharInUnicodeString(
  21. ULONG Flags,
  22. PCUNICODE_STRING StringToSearch,
  23. PCUNICODE_STRING CharSet,
  24. USHORT *NonInclusivePrefixLength
  25. )
  26. {
  27. NTSTATUS Status;
  28. USHORT PrefixLengthFound = 0;
  29. USHORT CharsToSearch = 0;
  30. int MovementDirection = 0;
  31. PCWSTR Cursor = NULL;
  32. BOOLEAN Found = FALSE;
  33. USHORT CharSetChars = 0;
  34. PCWSTR CharSetBuffer = NULL;
  35. USHORT i;
  36. if (NonInclusivePrefixLength != 0)
  37. *NonInclusivePrefixLength = 0;
  38. if (((Flags & ~(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END |
  39. RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET |
  40. RTL_FIND_CHAR_IN_UNICODE_STRING_CASE_INSENSITIVE)) != 0) ||
  41. (NonInclusivePrefixLength == NULL)) {
  42. Status = STATUS_INVALID_PARAMETER;
  43. goto Exit;
  44. }
  45. Status = RtlValidateUnicodeString(0, StringToSearch);
  46. if (!NT_SUCCESS(Status))
  47. goto Exit;
  48. Status = RtlValidateUnicodeString(0, CharSet);
  49. if (!NT_SUCCESS(Status))
  50. goto Exit;
  51. CharsToSearch = StringToSearch->Length / sizeof(WCHAR);
  52. CharSetChars = CharSet->Length / sizeof(WCHAR);
  53. CharSetBuffer = CharSet->Buffer;
  54. if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END) {
  55. MovementDirection = -1;
  56. Cursor = StringToSearch->Buffer + CharsToSearch - 1;
  57. } else {
  58. MovementDirection = 1;
  59. Cursor = StringToSearch->Buffer;
  60. }
  61. if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_CASE_INSENSITIVE) {
  62. // Unicode standard says to always do case insensitive comparisons in lower case since the case mappings are
  63. // asymmetric.
  64. WCHAR CharSetStackBuffer[32]; // optimized pre-downcased for case insensitive
  65. // Optimization for the case of a relatively small char set to match
  66. if (CharSetChars <= RTL_NUMBER_OF(CharSetStackBuffer)) {
  67. for (i=0; i<CharSetChars; i++)
  68. CharSetStackBuffer[i] = RtlDowncaseUnicodeChar(CharSetBuffer[i]);
  69. while (CharsToSearch != 0) {
  70. const WCHAR wch = RtlDowncaseUnicodeChar(*Cursor);
  71. if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET) {
  72. for (i=0; i<CharSetChars; i++) {
  73. if (wch == CharSetStackBuffer[i])
  74. break;
  75. }
  76. if (i == CharSetChars)
  77. break;
  78. } else {
  79. for (i=0; i<CharSetChars; i++) {
  80. if (wch == CharSetStackBuffer[i])
  81. break;
  82. }
  83. if (i != CharSetChars)
  84. break;
  85. }
  86. CharsToSearch--;
  87. Cursor += MovementDirection;
  88. }
  89. } else {
  90. while (CharsToSearch != 0) {
  91. const WCHAR wch = RtlDowncaseUnicodeChar(*Cursor);
  92. if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET) {
  93. for (i=0; i<CharSetChars; i++) {
  94. if (wch == RtlDowncaseUnicodeChar(CharSetBuffer[i])) {
  95. break;
  96. }
  97. }
  98. if (i == CharSetChars)
  99. break;
  100. } else {
  101. for (i=0; i<CharSetChars; i++) {
  102. if (wch == RtlDowncaseUnicodeChar(CharSetBuffer[i])) {
  103. break;
  104. }
  105. }
  106. if (i != CharSetChars)
  107. break;
  108. }
  109. CharsToSearch--;
  110. Cursor += MovementDirection;
  111. }
  112. }
  113. } else {
  114. if (CharSetChars == 1) {
  115. // Significant optimization for looking for one character.
  116. const WCHAR wchSearchChar = CharSetBuffer[0];
  117. if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET) {
  118. while (CharsToSearch != 0) {
  119. if (*Cursor != wchSearchChar)
  120. break;
  121. CharsToSearch--;
  122. Cursor += MovementDirection;
  123. }
  124. } else {
  125. while (CharsToSearch != 0) {
  126. if (*Cursor == wchSearchChar)
  127. break;
  128. CharsToSearch--;
  129. Cursor += MovementDirection;
  130. }
  131. }
  132. } else {
  133. while (CharsToSearch != 0) {
  134. const WCHAR wch = *Cursor;
  135. if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET) {
  136. for (i=0; i<CharSetChars; i++) {
  137. if (wch == CharSetBuffer[i])
  138. break;
  139. }
  140. if (i == CharSetChars)
  141. break;
  142. } else {
  143. for (i=0; i<CharSetChars; i++) {
  144. if (wch == CharSetBuffer[i])
  145. break;
  146. }
  147. if (i != CharSetChars)
  148. break;
  149. }
  150. CharsToSearch--;
  151. Cursor += MovementDirection;
  152. }
  153. }
  154. }
  155. if (CharsToSearch == 0) {
  156. Status = STATUS_NOT_FOUND;
  157. goto Exit;
  158. }
  159. CharsToSearch--;
  160. if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END)
  161. PrefixLengthFound = (USHORT) (CharsToSearch * sizeof(WCHAR));
  162. else
  163. PrefixLengthFound = (USHORT) (StringToSearch->Length - (CharsToSearch * sizeof(WCHAR)));
  164. *NonInclusivePrefixLength = PrefixLengthFound;
  165. Status = STATUS_SUCCESS;
  166. Exit:
  167. return Status;
  168. }