Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

name.c File Reference

#include "FsRtlP.h"

Go to the source code of this file.

Defines

#define Dbg   (0x10000000)
#define DavePrint   NOTHING
#define MODULE_POOL_TAG   ('nrSF')
#define MATCHES_ARRAY_SIZE   16

Functions

BOOLEAN FsRtlIsNameInExpressionPrivate (IN PUNICODE_STRING Expression, IN PUNICODE_STRING Name, IN BOOLEAN IgnoreCase, IN PWCH UpcaseTable)
VOID FsRtlDissectName (IN UNICODE_STRING Path, OUT PUNICODE_STRING FirstName, OUT PUNICODE_STRING RemainingName)
BOOLEAN FsRtlDoesNameContainWildCards (IN PUNICODE_STRING Name)
BOOLEAN FsRtlAreNamesEqual (PCUNICODE_STRING ConstantNameA, PCUNICODE_STRING ConstantNameB, IN BOOLEAN IgnoreCase, IN PCWCH UpcaseTable OPTIONAL)
BOOLEAN FsRtlIsNameInExpression (IN PUNICODE_STRING Expression, IN PUNICODE_STRING Name, IN BOOLEAN IgnoreCase, IN PWCH UpcaseTable OPTIONAL)


Define Documentation

#define DavePrint   NOTHING
 

Definition at line 60 of file name.c.

#define Dbg   (0x10000000)
 

Definition at line 47 of file name.c.

#define MATCHES_ARRAY_SIZE   16
 

Definition at line 475 of file name.c.

#define MODULE_POOL_TAG   ('nrSF')
 

Definition at line 69 of file name.c.


Function Documentation

BOOLEAN FsRtlAreNamesEqual PCUNICODE_STRING  ConstantNameA,
PCUNICODE_STRING  ConstantNameB,
IN BOOLEAN  IgnoreCase,
IN PCWCH UpcaseTable  OPTIONAL
 

Definition at line 288 of file name.c.

References ExRaiseStatus(), FALSE, Index, NT_SUCCESS, NTSTATUS(), PAGED_CODE, RtlFreeUnicodeString(), RtlUpcaseUnicodeString(), Status, and TRUE.

00297 : 00298 00299 This routine simple returns whether the two names are exactly equal. 00300 If the two names are known to be constant, this routine is much 00301 faster than FsRtlIsNameInExpression. 00302 00303 Arguments: 00304 00305 ConstantNameA - Constant name. 00306 00307 ConstantNameB - Constant name. 00308 00309 IgnoreCase - TRUE if the Names should be Upcased before comparing. 00310 00311 UpcaseTable - If supplied, use this table for case insensitive compares, 00312 otherwise, use the default system upcase table. 00313 00314 Return Value: 00315 00316 BOOLEAN - TRUE if the two names are lexically equal. 00317 00318 --*/ 00319 00320 { 00321 ULONG Index; 00322 ULONG NameLength; 00323 BOOLEAN FreeStrings = FALSE; 00324 00325 UNICODE_STRING LocalNameA; 00326 UNICODE_STRING LocalNameB; 00327 00328 PAGED_CODE(); 00329 00330 // 00331 // If the names aren't even the same size, then return FALSE right away. 00332 // 00333 00334 if ( ConstantNameA->Length != ConstantNameB->Length ) { 00335 00336 return FALSE; 00337 } 00338 00339 NameLength = ConstantNameA->Length / sizeof(WCHAR); 00340 00341 // 00342 // If we weren't given an upcase table, we have to upcase the names 00343 // ourselves. 00344 // 00345 00346 if ( IgnoreCase && !ARGUMENT_PRESENT(UpcaseTable) ) { 00347 00348 NTSTATUS Status; 00349 00350 Status = RtlUpcaseUnicodeString( &LocalNameA, ConstantNameA, TRUE ); 00351 00352 if ( !NT_SUCCESS(Status) ) { 00353 00354 ExRaiseStatus( Status ); 00355 } 00356 00357 Status = RtlUpcaseUnicodeString( &LocalNameB, ConstantNameB, TRUE ); 00358 00359 if ( !NT_SUCCESS(Status) ) { 00360 00361 RtlFreeUnicodeString( &LocalNameA ); 00362 00363 ExRaiseStatus( Status ); 00364 } 00365 00366 ConstantNameA = &LocalNameA; 00367 ConstantNameB = &LocalNameB; 00368 00369 IgnoreCase = FALSE; 00370 FreeStrings = TRUE; 00371 } 00372 00373 // 00374 // Do either case sensitive or insensitive compare. 00375 // 00376 00377 if ( !IgnoreCase ) { 00378 00379 BOOLEAN BytesEqual; 00380 00381 BytesEqual = (BOOLEAN) RtlEqualMemory( ConstantNameA->Buffer, 00382 ConstantNameB->Buffer, 00383 ConstantNameA->Length ); 00384 00385 if ( FreeStrings ) { 00386 00387 RtlFreeUnicodeString( &LocalNameA ); 00388 RtlFreeUnicodeString( &LocalNameB ); 00389 } 00390 00391 return BytesEqual; 00392 00393 } else { 00394 00395 for (Index = 0; Index < NameLength; Index += 1) { 00396 00397 if ( UpcaseTable[ConstantNameA->Buffer[Index]] != 00398 UpcaseTable[ConstantNameB->Buffer[Index]] ) { 00399 00400 return FALSE; 00401 } 00402 } 00403 00404 return TRUE; 00405 } 00406 }

VOID FsRtlDissectName IN UNICODE_STRING  Path,
OUT PUNICODE_STRING  FirstName,
OUT PUNICODE_STRING  RemainingName
 

Definition at line 93 of file name.c.

References L, NULL, PAGED_CODE, and USHORT.

00101 : 00102 00103 This routine cracks a path. It picks off the first element in the 00104 given path name and provides both it and the remaining part. A path 00105 is a set of file names separated by backslashes. If a name begins 00106 with a backslash, the FirstName is the string immediately following 00107 the backslash. Here are some examples: 00108 00109 Path FirstName RemainingName 00110 ---- --------- ------------- 00111 empty empty empty 00112 00113 \ empty empty 00114 00115 A A empty 00116 00117 \A A empty 00118 00119 A\B\C\D\E A B\C\D\E 00120 00121 *A? *A? empty 00122 00123 00124 Note that both output strings use the same string buffer memory of the 00125 input string, and are not necessarily null terminated. 00126 00127 Also, this routine makes no judgement as to the legality of each 00128 file name componant. This must be done separatly when each file name 00129 is extracted. 00130 00131 Arguments: 00132 00133 Path - The full path name to crack. 00134 00135 FirstName - The first name in the path. Don't allocate a buffer for 00136 this string. 00137 00138 RemainingName - The rest of the path. Don't allocate a buffer for this 00139 string. 00140 00141 Return Value: 00142 00143 None. 00144 00145 --*/ 00146 00147 { 00148 ULONG i = 0; 00149 ULONG PathLength; 00150 ULONG FirstNameStart; 00151 00152 PAGED_CODE(); 00153 00154 // 00155 // Make both output strings empty for now 00156 // 00157 00158 FirstName->Length = 0; 00159 FirstName->MaximumLength = 0; 00160 FirstName->Buffer = NULL; 00161 00162 RemainingName->Length = 0; 00163 RemainingName->MaximumLength = 0; 00164 RemainingName->Buffer = NULL; 00165 00166 PathLength = Path.Length / sizeof(WCHAR); 00167 00168 // 00169 // Check for an empty input string 00170 // 00171 00172 if (PathLength == 0) { 00173 00174 return; 00175 } 00176 00177 // 00178 // Skip over a starting backslash, and make sure there is more. 00179 // 00180 00181 if ( Path.Buffer[0] == L'\\' ) { 00182 00183 i = 1; 00184 } 00185 00186 // 00187 // Now run down the input string until we hit a backslash or the end 00188 // of the string, remembering where we started; 00189 // 00190 00191 for ( FirstNameStart = i; 00192 (i < PathLength) && (Path.Buffer[i] != L'\\'); 00193 i += 1 ) { 00194 00195 NOTHING; 00196 } 00197 00198 // 00199 // At this point all characters up to (but not including) i are 00200 // in the first part. So setup the first name 00201 // 00202 00203 FirstName->Length = (USHORT)((i - FirstNameStart) * sizeof(WCHAR)); 00204 FirstName->MaximumLength = FirstName->Length; 00205 FirstName->Buffer = &Path.Buffer[FirstNameStart]; 00206 00207 // 00208 // Now the remaining part needs a string only if the first part didn't 00209 // exhaust the entire input string. We know that if anything is left 00210 // that is must start with a backslash. Note that if there is only 00211 // a trailing backslash, the length will get correctly set to zero. 00212 // 00213 00214 if (i < PathLength) { 00215 00216 RemainingName->Length = (USHORT)((PathLength - (i + 1)) * sizeof(WCHAR)); 00217 RemainingName->MaximumLength = RemainingName->Length; 00218 RemainingName->Buffer = &Path.Buffer[i + 1]; 00219 } 00220 00221 // 00222 // And return to our caller 00223 // 00224 00225 return; 00226 }

BOOLEAN FsRtlDoesNameContainWildCards IN PUNICODE_STRING  Name  ) 
 

Definition at line 229 of file name.c.

References FALSE, FsRtlIsUnicodeCharacterWild, L, Name, PAGED_CODE, PUSHORT, and TRUE.

Referenced by FsRtlIsNameInExpressionPrivate(), UdfInitializeEnumeration(), and UdfNormalizeFileNames().

00235 : 00236 00237 This routine simply scans the input Name string looking for any Nt 00238 wild card characters. 00239 00240 Arguments: 00241 00242 Name - The string to check. 00243 00244 Return Value: 00245 00246 BOOLEAN - TRUE if one or more wild card characters was found. 00247 00248 --*/ 00249 { 00250 PUSHORT p; 00251 00252 PAGED_CODE(); 00253 00254 // 00255 // Check each character in the name to see if it's a wildcard 00256 // character. 00257 // 00258 00259 if( Name->Length ) { 00260 for( p = Name->Buffer + (Name->Length / sizeof(WCHAR)) - 1; 00261 p >= Name->Buffer && *p != L'\\' ; 00262 p-- ) { 00263 00264 // 00265 // check for a wild card character 00266 // 00267 00268 if (FsRtlIsUnicodeCharacterWild( *p )) { 00269 00270 // 00271 // Tell caller that this name contains wild cards 00272 // 00273 00274 return TRUE; 00275 } 00276 } 00277 } 00278 00279 // 00280 // No wildcard characters were found, so return to our caller 00281 // 00282 00283 return FALSE; 00284 }

BOOLEAN FsRtlIsNameInExpression IN PUNICODE_STRING  Expression,
IN PUNICODE_STRING  Name,
IN BOOLEAN  IgnoreCase,
IN PWCH UpcaseTable  OPTIONAL
 

Definition at line 415 of file name.c.

References ExRaiseStatus(), FALSE, FsRtlIsNameInExpressionPrivate(), Name, NT_SUCCESS, NTSTATUS(), NULL, RtlFreeUnicodeString(), RtlUpcaseUnicodeString(), Status, and TRUE.

Referenced by UdfIsNameInExpression().

00422 { 00423 BOOLEAN Result; 00424 UNICODE_STRING LocalName; 00425 00426 // 00427 // If we weren't given an upcase table, we have to upcase the names 00428 // ourselves. 00429 // 00430 00431 if ( IgnoreCase && !ARGUMENT_PRESENT(UpcaseTable) ) { 00432 00433 NTSTATUS Status; 00434 00435 Status = RtlUpcaseUnicodeString( &LocalName, Name, TRUE ); 00436 00437 if ( !NT_SUCCESS(Status) ) { 00438 00439 ExRaiseStatus( Status ); 00440 } 00441 00442 Name = &LocalName; 00443 00444 IgnoreCase = FALSE; 00445 00446 } else { 00447 00448 LocalName.Buffer = NULL; 00449 } 00450 00451 // 00452 // Now call the main routine, remembering to free the upcased string 00453 // if we allocated one. 00454 // 00455 00456 try { 00457 00458 Result = FsRtlIsNameInExpressionPrivate( Expression, 00459 Name, 00460 IgnoreCase, 00461 UpcaseTable ); 00462 00463 } finally { 00464 00465 if (LocalName.Buffer != NULL) { 00466 00467 RtlFreeUnicodeString( &LocalName ); 00468 } 00469 } 00470 00471 return Result; 00472 }

BOOLEAN FsRtlIsNameInExpressionPrivate IN PUNICODE_STRING  Expression,
IN PUNICODE_STRING  Name,
IN BOOLEAN  IgnoreCase,
IN PWCH  UpcaseTable
 

Definition at line 482 of file name.c.

References ASSERT, Dbg, DebugTrace, ExFreePool(), FALSE, FsRtlDoesNameContainWildCards(), FsRtlpAllocatePool, L, MATCHES_ARRAY_SIZE, Name, NULL, Offset, PAGED_CODE, PagedPool, TRUE, and USHORT.

Referenced by FsRtlIsNameInExpression().

00491 : 00492 00493 This routine compares a Dbcs name and an expression and tells the caller 00494 if the name is in the language defined by the expression. The input name 00495 cannot contain wildcards, while the expression may contain wildcards. 00496 00497 Expression wild cards are evaluated as shown in the nondeterministic 00498 finite automatons below. Note that ~* and ~? are DOS_STAR and DOS_QM. 00499 00500 00501 ~* is DOS_STAR, ~? is DOS_QM, and ~. is DOS_DOT 00502 00503 00504 S 00505 <-----< 00506 X | | e Y 00507 X * Y == (0)----->-(1)->-----(2)-----(3) 00508 00509 00510 S-. 00511 <-----< 00512 X | | e Y 00513 X ~* Y == (0)----->-(1)->-----(2)-----(3) 00514 00515 00516 00517 X S S Y 00518 X ?? Y == (0)---(1)---(2)---(3)---(4) 00519 00520 00521 00522 X . . Y 00523 X ~.~. Y == (0)---(1)----(2)------(3)---(4) 00524 | |________| 00525 | ^ | 00526 |_______________| 00527 ^EOF or .^ 00528 00529 00530 X S-. S-. Y 00531 X ~?~? Y == (0)---(1)-----(2)-----(3)---(4) 00532 | |________| 00533 | ^ | 00534 |_______________| 00535 ^EOF or .^ 00536 00537 00538 00539 where S is any single character 00540 00541 S-. is any single character except the final . 00542 00543 e is a null character transition 00544 00545 EOF is the end of the name string 00546 00547 In words: 00548 00549 * matches 0 or more characters. 00550 00551 ? matches exactly 1 character. 00552 00553 DOS_STAR matches 0 or more characters until encountering and matching 00554 the final . in the name. 00555 00556 DOS_QM matches any single character, or upon encountering a period or 00557 end of name string, advances the expression to the end of the 00558 set of contiguous DOS_QMs. 00559 00560 DOS_DOT matches either a . or zero characters beyond name string. 00561 00562 Arguments: 00563 00564 Expression - Supplies the input expression to check against 00565 (Caller must already upcase if passing CaseInsensitive TRUE.) 00566 00567 Name - Supplies the input name to check for. 00568 00569 CaseInsensitive - TRUE if Name should be Upcased before comparing. 00570 00571 Return Value: 00572 00573 BOOLEAN - TRUE if Name is an element in the set of strings denoted 00574 by the input Expression and FALSE otherwise. 00575 00576 --*/ 00577 00578 { 00579 USHORT NameOffset; 00580 USHORT ExprOffset; 00581 00582 ULONG SrcCount; 00583 ULONG DestCount; 00584 ULONG PreviousDestCount; 00585 ULONG MatchesCount; 00586 00587 WCHAR NameChar, ExprChar; 00588 00589 USHORT LocalBuffer[MATCHES_ARRAY_SIZE * 2]; 00590 00591 USHORT *AuxBuffer = NULL; 00592 USHORT *PreviousMatches; 00593 USHORT *CurrentMatches; 00594 00595 USHORT MaxState; 00596 USHORT CurrentState; 00597 00598 BOOLEAN NameFinished = FALSE; 00599 00600 // 00601 // The idea behind the algorithm is pretty simple. We keep track of 00602 // all possible locations in the regular expression that are matching 00603 // the name. If when the name has been exhausted one of the locations 00604 // in the expression is also just exhausted, the name is in the language 00605 // defined by the regular expression. 00606 // 00607 00608 PAGED_CODE(); 00609 00610 DebugTrace(+1, Dbg, "FsRtlIsNameInExpression\n", 0); 00611 DebugTrace( 0, Dbg, " Expression = %Z\n", Expression ); 00612 DebugTrace( 0, Dbg, " Name = %Z\n", Name ); 00613 DebugTrace( 0, Dbg, " CaseInsensitive = %08lx\n", CaseInsensitive ); 00614 00615 ASSERT( Name->Length != 0 ); 00616 ASSERT( Expression->Length != 0 ); 00617 00618 // 00619 // If one string is empty return FALSE. If both are empty return TRUE. 00620 // 00621 00622 if ( (Name->Length == 0) || (Expression->Length == 0) ) { 00623 00624 return (BOOLEAN)(!(Name->Length + Expression->Length)); 00625 } 00626 00627 // 00628 // Special case by far the most common wild card search of * 00629 // 00630 00631 if ((Expression->Length == 2) && (Expression->Buffer[0] == L'*')) { 00632 00633 return TRUE; 00634 } 00635 00636 ASSERT( FsRtlDoesNameContainWildCards( Expression ) ); 00637 00638 ASSERT( !IgnoreCase || ARGUMENT_PRESENT(UpcaseTable) ); 00639 00640 // 00641 // Also special case expressions of the form *X. With this and the prior 00642 // case we have covered virtually all normal queries. 00643 // 00644 00645 if (Expression->Buffer[0] == L'*') { 00646 00647 UNICODE_STRING LocalExpression; 00648 00649 LocalExpression = *Expression; 00650 00651 LocalExpression.Buffer += 1; 00652 LocalExpression.Length -= 2; 00653 00654 // 00655 // Only special case an expression with a single * 00656 // 00657 00658 if ( !FsRtlDoesNameContainWildCards( &LocalExpression ) ) { 00659 00660 ULONG StartingNameOffset; 00661 00662 if (Name->Length < (USHORT)(Expression->Length - sizeof(WCHAR))) { 00663 00664 return FALSE; 00665 } 00666 00667 StartingNameOffset = ( Name->Length - 00668 LocalExpression.Length ) / sizeof(WCHAR); 00669 00670 // 00671 // Do a simple memory compare if case sensitive, otherwise 00672 // we have got to check this one character at a time. 00673 // 00674 00675 if ( !IgnoreCase ) { 00676 00677 return (BOOLEAN) RtlEqualMemory( LocalExpression.Buffer, 00678 Name->Buffer + StartingNameOffset, 00679 LocalExpression.Length ); 00680 00681 } else { 00682 00683 for ( ExprOffset = 0; 00684 ExprOffset < (USHORT)(LocalExpression.Length / sizeof(WCHAR)); 00685 ExprOffset += 1 ) { 00686 00687 NameChar = Name->Buffer[StartingNameOffset + ExprOffset]; 00688 NameChar = UpcaseTable[NameChar]; 00689 00690 ExprChar = LocalExpression.Buffer[ExprOffset]; 00691 00692 ASSERT( ExprChar == UpcaseTable[ExprChar] ); 00693 00694 if ( NameChar != ExprChar ) { 00695 00696 return FALSE; 00697 } 00698 } 00699 00700 return TRUE; 00701 } 00702 } 00703 } 00704 00705 // 00706 // Walk through the name string, picking off characters. We go one 00707 // character beyond the end because some wild cards are able to match 00708 // zero characters beyond the end of the string. 00709 // 00710 // With each new name character we determine a new set of states that 00711 // match the name so far. We use two arrays that we swap back and forth 00712 // for this purpose. One array lists the possible expression states for 00713 // all name characters up to but not including the current one, and other 00714 // array is used to build up the list of states considering the current 00715 // name character as well. The arrays are then switched and the process 00716 // repeated. 00717 // 00718 // There is not a one-to-one correspondence between state number and 00719 // offset into the expression. This is evident from the NFAs in the 00720 // initial comment to this function. State numbering is not continuous. 00721 // This allows a simple conversion between state number and expression 00722 // offset. Each character in the expression can represent one or two 00723 // states. * and DOS_STAR generate two states: ExprOffset*2 and 00724 // ExprOffset*2 + 1. All other expreesion characters can produce only 00725 // a single state. Thus ExprOffset = State/2. 00726 // 00727 // 00728 // Here is a short description of the variables involved: 00729 // 00730 // NameOffset - The offset of the current name char being processed. 00731 // 00732 // ExprOffset - The offset of the current expression char being processed. 00733 // 00734 // SrcCount - Prior match being investigated with current name char 00735 // 00736 // DestCount - Next location to put a matching assuming current name char 00737 // 00738 // NameFinished - Allows one more itteration through the Matches array 00739 // after the name is exhusted (to come *s for example) 00740 // 00741 // PreviousDestCount - This is used to prevent entry duplication, see coment 00742 // 00743 // PreviousMatches - Holds the previous set of matches (the Src array) 00744 // 00745 // CurrentMatches - Holds the current set of matches (the Dest array) 00746 // 00747 // AuxBuffer, LocalBuffer - the storage for the Matches arrays 00748 // 00749 00750 // 00751 // Set up the initial variables 00752 // 00753 00754 PreviousMatches = &LocalBuffer[0]; 00755 CurrentMatches = &LocalBuffer[MATCHES_ARRAY_SIZE]; 00756 00757 PreviousMatches[0] = 0; 00758 MatchesCount = 1; 00759 00760 NameOffset = 0; 00761 00762 MaxState = (USHORT)(Expression->Length * 2); 00763 00764 while ( !NameFinished ) { 00765 00766 if ( NameOffset < Name->Length ) { 00767 00768 NameChar = Name->Buffer[NameOffset / sizeof(WCHAR)]; 00769 00770 NameOffset += sizeof(WCHAR);; 00771 00772 } else { 00773 00774 NameFinished = TRUE; 00775 00776 // 00777 // if we have already exhasted the expression, cool. Don't 00778 // continue. 00779 // 00780 00781 if ( PreviousMatches[MatchesCount-1] == MaxState ) { 00782 00783 break; 00784 } 00785 } 00786 00787 00788 // 00789 // Now, for each of the previous stored expression matches, see what 00790 // we can do with this name character. 00791 // 00792 00793 SrcCount = 0; 00794 DestCount = 0; 00795 PreviousDestCount = 0; 00796 00797 while ( SrcCount < MatchesCount ) { 00798 00799 USHORT Length; 00800 00801 // 00802 // We have to carry on our expression analysis as far as possible 00803 // for each character of name, so we loop here until the 00804 // expression stops matching. A clue here is that expression 00805 // cases that can match zero or more characters end with a 00806 // continue, while those that can accept only a single character 00807 // end with a break. 00808 // 00809 00810 ExprOffset = (USHORT)((PreviousMatches[SrcCount++] + 1) / 2); 00811 00812 00813 Length = 0; 00814 00815 while ( TRUE ) { 00816 00817 if ( ExprOffset == Expression->Length ) { 00818 00819 break; 00820 } 00821 00822 // 00823 // The first time through the loop we don't want 00824 // to increment ExprOffset. 00825 // 00826 00827 ExprOffset += Length; 00828 Length = sizeof(WCHAR); 00829 00830 CurrentState = (USHORT)(ExprOffset * 2); 00831 00832 if ( ExprOffset == Expression->Length ) { 00833 00834 CurrentMatches[DestCount++] = MaxState; 00835 break; 00836 } 00837 00838 ExprChar = Expression->Buffer[ExprOffset / sizeof(WCHAR)]; 00839 00840 ASSERT( !IgnoreCase || !((ExprChar >= L'a') && (ExprChar <= L'z')) ); 00841 00842 // 00843 // Before we get started, we have to check for something 00844 // really gross. We may be about to exhaust the local 00845 // space for ExpressionMatches[][], so we have to allocate 00846 // some pool if this is the case. Yuk! 00847 // 00848 00849 if ( (DestCount >= MATCHES_ARRAY_SIZE - 2) && 00850 (AuxBuffer == NULL) ) { 00851 00852 ULONG ExpressionChars; 00853 00854 ExpressionChars = Expression->Length / sizeof(WCHAR); 00855 00856 AuxBuffer = FsRtlpAllocatePool( PagedPool, 00857 (ExpressionChars+1) * 00858 sizeof(USHORT)*2*2 ); 00859 00860 RtlCopyMemory( AuxBuffer, 00861 CurrentMatches, 00862 MATCHES_ARRAY_SIZE * sizeof(USHORT) ); 00863 00864 CurrentMatches = AuxBuffer; 00865 00866 RtlCopyMemory( AuxBuffer + (ExpressionChars+1)*2, 00867 PreviousMatches, 00868 MATCHES_ARRAY_SIZE * sizeof(USHORT) ); 00869 00870 PreviousMatches = AuxBuffer + (ExpressionChars+1)*2; 00871 } 00872 00873 // 00874 // * matches any character zero or more times. 00875 // 00876 00877 if (ExprChar == L'*') { 00878 00879 CurrentMatches[DestCount++] = CurrentState; 00880 CurrentMatches[DestCount++] = CurrentState + 3; 00881 continue; 00882 } 00883 00884 // 00885 // DOS_STAR matches any character except . zero or more times. 00886 // 00887 00888 if (ExprChar == DOS_STAR) { 00889 00890 BOOLEAN ICanEatADot = FALSE; 00891 00892 // 00893 // If we are at a period, determine if we are allowed to 00894 // consume it, ie. make sure it is not the last one. 00895 // 00896 00897 if ( !NameFinished && (NameChar == '.') ) { 00898 00899 USHORT Offset; 00900 00901 for ( Offset = NameOffset; 00902 Offset < Name->Length; 00903 Offset += Length ) { 00904 00905 if (Name->Buffer[Offset / sizeof(WCHAR)] == L'.') { 00906 00907 ICanEatADot = TRUE; 00908 break; 00909 } 00910 } 00911 } 00912 00913 if (NameFinished || (NameChar != L'.') || ICanEatADot) { 00914 00915 CurrentMatches[DestCount++] = CurrentState; 00916 CurrentMatches[DestCount++] = CurrentState + 3; 00917 continue; 00918 00919 } else { 00920 00921 // 00922 // We are at a period. We can only match zero 00923 // characters (ie. the epsilon transition). 00924 // 00925 00926 CurrentMatches[DestCount++] = CurrentState + 3; 00927 continue; 00928 } 00929 } 00930 00931 // 00932 // The following expreesion characters all match by consuming 00933 // a character, thus force the expression, and thus state 00934 // forward. 00935 // 00936 00937 CurrentState += (USHORT)(sizeof(WCHAR) * 2); 00938 00939 // 00940 // DOS_QM is the most complicated. If the name is finished, 00941 // we can match zero characters. If this name is a '.', we 00942 // don't match, but look at the next expression. Otherwise 00943 // we match a single character. 00944 // 00945 00946 if ( ExprChar == DOS_QM ) { 00947 00948 if ( NameFinished || (NameChar == L'.') ) { 00949 00950 continue; 00951 } 00952 00953 CurrentMatches[DestCount++] = CurrentState; 00954 break; 00955 } 00956 00957 // 00958 // A DOS_DOT can match either a period, or zero characters 00959 // beyond the end of name. 00960 // 00961 00962 if (ExprChar == DOS_DOT) { 00963 00964 if ( NameFinished ) { 00965 00966 continue; 00967 } 00968 00969 if (NameChar == L'.') { 00970 00971 CurrentMatches[DestCount++] = CurrentState; 00972 break; 00973 } 00974 } 00975 00976 // 00977 // From this point on a name character is required to even 00978 // continue, let alone make a match. 00979 // 00980 00981 if ( NameFinished ) { 00982 00983 break; 00984 } 00985 00986 // 00987 // If this expression was a '?' we can match it once. 00988 // 00989 00990 if (ExprChar == L'?') { 00991 00992 CurrentMatches[DestCount++] = CurrentState; 00993 break; 00994 } 00995 00996 // 00997 // Finally, check if the expression char matches the name char 00998 // 00999 01000 if (ExprChar == (WCHAR)(IgnoreCase ? 01001 UpcaseTable[NameChar] : NameChar)) { 01002 01003 CurrentMatches[DestCount++] = CurrentState; 01004 break; 01005 } 01006 01007 // 01008 // The expression didn't match so go look at the next 01009 // previous match. 01010 // 01011 01012 break; 01013 } 01014 01015 01016 // 01017 // Prevent duplication in the destination array. 01018 // 01019 // Each of the arrays is montonically increasing and non- 01020 // duplicating, thus we skip over any source element in the src 01021 // array if we just added the same element to the destination 01022 // array. This guarentees non-duplication in the dest. array. 01023 // 01024 01025 if ((SrcCount < MatchesCount) && 01026 (PreviousDestCount < DestCount) ) { 01027 01028 while (PreviousDestCount < DestCount) { 01029 01030 while ( PreviousMatches[SrcCount] < 01031 CurrentMatches[PreviousDestCount] ) { 01032 01033 SrcCount += 1; 01034 } 01035 01036 PreviousDestCount += 1; 01037 } 01038 } 01039 } 01040 01041 // 01042 // If we found no matches in the just finished itteration, it's time 01043 // to bail. 01044 // 01045 01046 if ( DestCount == 0 ) { 01047 01048 if (AuxBuffer != NULL) { ExFreePool( AuxBuffer ); } 01049 01050 return FALSE; 01051 } 01052 01053 // 01054 // Swap the meaning the two arrays 01055 // 01056 01057 { 01058 USHORT *Tmp; 01059 01060 Tmp = PreviousMatches; 01061 01062 PreviousMatches = CurrentMatches; 01063 01064 CurrentMatches = Tmp; 01065 } 01066 01067 MatchesCount = DestCount; 01068 } 01069 01070 01071 CurrentState = PreviousMatches[MatchesCount-1]; 01072 01073 if (AuxBuffer != NULL) { ExFreePool( AuxBuffer ); } 01074 01075 01076 return (BOOLEAN)(CurrentState == MaxState); 01077 } }


Generated on Sat May 15 19:44:49 2004 for test by doxygen 1.3.7