- Merge audio components from head
[reactos.git] / ntoskrnl / fsrtl / name.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/fsrtl/name.c
5 * PURPOSE: Provides name parsing and other support routines for FSDs
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Filip Navara (navaraf@reactos.org)
8 * Pierre Schweitzer (pierre.schweitzer@reactos.org)
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 /* PRIVATE FUNCTIONS *********************************************************/
18 BOOLEAN
19 NTAPI
20 FsRtlIsNameInExpressionPrivate(IN PUNICODE_STRING Expression,
21 IN PUNICODE_STRING Name,
22 IN BOOLEAN IgnoreCase,
23 IN PWCHAR UpcaseTable OPTIONAL)
24 {
25 ULONG i = 0, j, k = 0;
26
27 ASSERT(!FsRtlDoesNameContainWildCards(Name));
28
29 while (i < Name->Length / sizeof(WCHAR) && k < Expression->Length / sizeof(WCHAR))
30 {
31 if ((Expression->Buffer[k] == (IgnoreCase ? UpcaseTable[Name->Buffer[i]] : Name->Buffer[i])) ||
32 (Expression->Buffer[k] == L'?') || (Expression->Buffer[k] == DOS_QM) ||
33 (Expression->Buffer[k] == DOS_DOT && (Name->Buffer[i] == L'.' || Name->Buffer[i] == L'0')))
34 {
35 i++;
36 k++;
37 }
38 else if (Expression->Buffer[k] == L'*')
39 {
40 if (k < (Expression->Length / sizeof(WCHAR) - 1))
41 {
42 if (Expression->Buffer[k+1] != L'*' && Expression->Buffer[k+1] != L'?' &&
43 Expression->Buffer[k+1] != DOS_DOT && Expression->Buffer[k+1] != DOS_QM &&
44 Expression->Buffer[k+1] != DOS_STAR)
45 {
46 while ((IgnoreCase ? UpcaseTable[Name->Buffer[i]] : Name->Buffer[i]) != Expression->Buffer[k+1] &&
47 i < Name->Length / sizeof(WCHAR)) i++;
48 }
49 else
50 {
51 if (!(Expression->Buffer[k+1] != DOS_DOT && (Name->Buffer[i] == L'.' || Name->Buffer[i] == L'0')))
52 {
53 i++;
54 }
55 }
56 }
57 else
58 {
59 i = Name->Length / sizeof(WCHAR);
60 }
61 k++;
62 }
63 else if (Expression->Buffer[k] == DOS_STAR)
64 {
65 j = i;
66 while (j < Name->Length / sizeof(WCHAR))
67 {
68 if (Name->Buffer[j] == L'.')
69 {
70 i = j;
71 }
72 j++;
73 }
74 k++;
75 }
76 else
77 {
78 i = Name->Length / sizeof(WCHAR);
79 }
80 }
81
82 return (k == Expression->Length / sizeof(WCHAR) && i == Name->Length / sizeof(WCHAR));
83 }
84
85 /* PUBLIC FUNCTIONS **********************************************************/
86
87 /*++
88 * @name FsRtlAreNamesEqual
89 * @implemented
90 *
91 * Compare two strings to check if they match
92 *
93 * @param Name1
94 * First unicode string to compare
95 *
96 * @param Name2
97 * Second unicode string to compare
98 *
99 * @param IgnoreCase
100 * If TRUE, Case will be ignored when comparing strings
101 *
102 * @param UpcaseTable
103 * Table for upcase letters. If NULL is given, system one will be used
104 *
105 * @return TRUE if the strings are equal
106 *
107 * @remarks From Bo Branten's ntifs.h v25.
108 *
109 *--*/
110 BOOLEAN
111 NTAPI
112 FsRtlAreNamesEqual(IN PCUNICODE_STRING Name1,
113 IN PCUNICODE_STRING Name2,
114 IN BOOLEAN IgnoreCase,
115 IN PCWCH UpcaseTable OPTIONAL)
116 {
117 UNICODE_STRING UpcaseName1;
118 UNICODE_STRING UpcaseName2;
119 BOOLEAN StringsAreEqual, MemoryAllocated = FALSE;
120 ULONG i;
121 NTSTATUS Status;
122
123 /* Well, first check their size */
124 if (Name1->Length != Name2->Length) return FALSE;
125
126 /* Check if the caller didn't give an upcase table */
127 if ((IgnoreCase) && !(UpcaseTable))
128 {
129 /* Upcase the string ourselves */
130 Status = RtlUpcaseUnicodeString(&UpcaseName1, Name1, TRUE);
131 if (!NT_SUCCESS(Status)) RtlRaiseStatus(Status);
132
133 /* Upcase the second string too */
134 RtlUpcaseUnicodeString(&UpcaseName2, Name2, TRUE);
135 Name1 = &UpcaseName1;
136 Name2 = &UpcaseName2;
137
138 /* Make sure we go through the path below, but free the strings */
139 IgnoreCase = FALSE;
140 MemoryAllocated = TRUE;
141 }
142
143 /* Do a case-sensitive search */
144 if (!IgnoreCase)
145 {
146 /* Use a raw memory compare */
147 StringsAreEqual = RtlEqualMemory(Name1->Buffer,
148 Name2->Buffer,
149 Name1->Length);
150
151 /* Check if we allocated strings */
152 if (MemoryAllocated)
153 {
154 /* Free them */
155 RtlFreeUnicodeString(&UpcaseName1);
156 RtlFreeUnicodeString(&UpcaseName2);
157 }
158
159 /* Return the equality */
160 return StringsAreEqual;
161 }
162 else
163 {
164 /* Case in-sensitive search */
165 for (i = 0; i < Name1->Length / sizeof(WCHAR); i++)
166 {
167 /* Check if the character matches */
168 if (UpcaseTable[Name1->Buffer[i]] != UpcaseTable[Name2->Buffer[i]])
169 {
170 /* Non-match found! */
171 return FALSE;
172 }
173 }
174
175 /* We finished the loop so we are equal */
176 return TRUE;
177 }
178 }
179
180 /*++
181 * @name FsRtlDissectName
182 * @implemented
183 *
184 * Dissects a given path name into first and remaining part.
185 *
186 * @param Name
187 * Unicode string to dissect.
188 *
189 * @param FirstPart
190 * Pointer to user supplied UNICODE_STRING, that will later point
191 * to the first part of the original name.
192 *
193 * @param RemainingPart
194 * Pointer to user supplied UNICODE_STRING, that will later point
195 * to the remaining part of the original name.
196 *
197 * @return None
198 *
199 * @remarks Example:
200 * Name: \test1\test2\test3
201 * FirstPart: test1
202 * RemainingPart: test2\test3
203 *
204 *--*/
205 VOID
206 NTAPI
207 FsRtlDissectName(IN UNICODE_STRING Name,
208 OUT PUNICODE_STRING FirstPart,
209 OUT PUNICODE_STRING RemainingPart)
210 {
211 ULONG FirstPosition, i;
212 ULONG SkipFirstSlash = 0;
213
214 /* Zero the strings before continuing */
215 RtlZeroMemory(FirstPart, sizeof(UNICODE_STRING));
216 RtlZeroMemory(RemainingPart, sizeof(UNICODE_STRING));
217
218 /* Just quit if the string is empty */
219 if (!Name.Length) return;
220
221 /* Find first backslash */
222 FirstPosition = Name.Length / sizeof(WCHAR) ;
223 for (i = 0; i < Name.Length / sizeof(WCHAR); i++)
224 {
225 /* If we found one... */
226 if (Name.Buffer[i] == L'\\')
227 {
228 /* If it begins string, just notice it and continue */
229 if (i == 0)
230 {
231 SkipFirstSlash = 1;
232 }
233 else
234 {
235 /* Else, save its position and break out of the loop */
236 FirstPosition = i;
237 break;
238 }
239 }
240 }
241
242 /* Set up the first result string */
243 FirstPart->Buffer = Name.Buffer + SkipFirstSlash;
244 FirstPart->Length = (FirstPosition - SkipFirstSlash) * sizeof(WCHAR);
245 FirstPart->MaximumLength = FirstPart->Length;
246
247 /* And second one, if necessary */
248 if (FirstPosition < (Name.Length / sizeof(WCHAR)))
249 {
250 RemainingPart->Buffer = Name.Buffer + FirstPosition + 1;
251 RemainingPart->Length = Name.Length - (FirstPosition + 1) * sizeof(WCHAR);
252 RemainingPart->MaximumLength = RemainingPart->Length;
253 }
254 }
255
256 /*++
257 * @name FsRtlDoesNameContainWildCards
258 * @implemented
259 *
260 * Checks if the given string contains WildCards
261 *
262 * @param Name
263 * Pointer to a UNICODE_STRING containing Name to examine
264 *
265 * @return TRUE if Name contains wildcards, FALSE otherwise
266 *
267 * @remarks From Bo Branten's ntifs.h v12.
268 *
269 *--*/
270 BOOLEAN
271 NTAPI
272 FsRtlDoesNameContainWildCards(IN PUNICODE_STRING Name)
273 {
274 PWCHAR Ptr;
275
276 /* Loop through every character */
277 if (Name->Length)
278 {
279 Ptr = Name->Buffer + (Name->Length / sizeof(WCHAR)) - 1;
280 while ((Ptr >= Name->Buffer) && (*Ptr != L'\\'))
281 {
282 /* Check for Wildcard */
283 if (FsRtlIsUnicodeCharacterWild(*Ptr)) return TRUE;
284 Ptr--;
285 }
286 }
287
288 /* Nothing Found */
289 return FALSE;
290 }
291
292 /*++
293 * @name FsRtlIsNameInExpression
294 * @implemented
295 *
296 * Check if the Name string is in the Expression string.
297 *
298 * @param Expression
299 * The string in which we've to find Name. It can contain wildcards.
300 * If IgnoreCase is set to TRUE, this string MUST BE uppercase.
301 *
302 * @param Name
303 * The string to find. It cannot contain wildcards
304 *
305 * @param IgnoreCase
306 * If set to TRUE, case will be ignore with upcasing both strings
307 *
308 * @param UpcaseTable
309 * If not NULL, and if IgnoreCase is set to TRUE, it will be used to
310 * upcase the both strings
311 *
312 * @return TRUE if Name is in Expression, FALSE otherwise
313 *
314 * @remarks From Bo Branten's ntifs.h v12. This function should be
315 * rewritten to avoid recursion and better wildcard handling
316 * should be implemented (see FsRtlDoesNameContainWildCards).
317 *
318 *--*/
319 BOOLEAN
320 NTAPI
321 FsRtlIsNameInExpression(IN PUNICODE_STRING Expression,
322 IN PUNICODE_STRING Name,
323 IN BOOLEAN IgnoreCase,
324 IN PWCHAR UpcaseTable OPTIONAL)
325 {
326 BOOLEAN Result;
327 NTSTATUS Status;
328 UNICODE_STRING IntName;
329
330 if (IgnoreCase && !UpcaseTable)
331 {
332 Status = RtlUpcaseUnicodeString(&IntName, Name, TRUE);
333 if (Status != STATUS_SUCCESS)
334 {
335 ExRaiseStatus(Status);
336 }
337 Name = &IntName;
338 IgnoreCase = FALSE;
339 }
340 else
341 {
342 IntName.Buffer = NULL;
343 }
344
345 Result = FsRtlIsNameInExpressionPrivate(Expression, Name, IgnoreCase, UpcaseTable);
346
347 if (IntName.Buffer != NULL)
348 {
349 RtlFreeUnicodeString(&IntName);
350 }
351
352 return Result;
353 }