From de2ccc1c5138fd78a7a30df233ecc4f38c930d7c Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Mon, 7 Nov 2005 21:57:50 +0000 Subject: [PATCH] - Implement more of RtlInsertUnicodePrefix: handle case where tree was found, and a match in the tree was found (handle case-sensitive and case-insensitve match). - Partially umplement CompareUnicodeStrings to scan the two strings (Can't use RtlCompareUnicodeString because we want control over how many chars to case-compare. svn path=/trunk/; revision=19045 --- reactos/lib/rtl/unicodeprefix.c | 151 ++++++++++++++++++++++++++++++-- 1 file changed, 144 insertions(+), 7 deletions(-) diff --git a/reactos/lib/rtl/unicodeprefix.c b/reactos/lib/rtl/unicodeprefix.c index 1d31e69fe57..4d8a15c6b1a 100644 --- a/reactos/lib/rtl/unicodeprefix.c +++ b/reactos/lib/rtl/unicodeprefix.c @@ -44,6 +44,73 @@ ComputeUnicodeNameLength(IN PUNICODE_STRING UnicodeName) return NamesFound; } + +STATIC +RTL_GENERIC_COMPARE_RESULTS +NTAPI +CompareUnicodeStrings(IN PUNICODE_STRING String, + IN PUNICODE_STRING Prefix, + IN ULONG CaseCheckChar) +{ + ULONG StringLength = String->Length / sizeof(WCHAR); + ULONG PrefixLength = Prefix->Length / sizeof(WCHAR); + ULONG ScanLength = min(StringLength, PrefixLength); + ULONG i; + WCHAR FoundPrefix, FoundString; + + /* Validate the Case Check Character Position */ + if (CaseCheckChar > ScanLength) CaseCheckChar = ScanLength; + + /* Do the case sensitive comparison first */ + for (i = 0; i < CaseCheckChar; i++) + { + /* Compare the two characters */ + if (Prefix->Buffer[i] != String->Buffer[i]) break; + } + + /* Save the characters we found */ + FoundPrefix = Prefix->Buffer[i]; + FoundString = String->Buffer[i]; + + /* Check if we exausted the search above */ + if (i == CaseCheckChar) + { + /* FIXME: Do a case-insensitive search */ + } + + /* Check if we weren't able to find a match in the loops */ + if (i < ScanLength) + { + /* If the prefix character found was a backslash, this is a less */ + if (FoundPrefix == '\\') return GenericLessThan; + + /* If the string character found was a backslack, then this is a more */ + if (FoundString == '\\') return GenericGreaterThan; + + /* None of those two special cases, do a normal check */ + if (FoundPrefix < FoundString) return GenericLessThan; + + /* The only choice left is that Prefix > String */ + return GenericGreaterThan; + } + + /* If we got here, a match was found. Check if the prefix is smaller */ + if (PrefixLength < StringLength) + { + /* Check if the string is actually a prefix */ + if (String->Buffer[PrefixLength] == '\\') return -1; + + /* It's not a prefix, and it's shorter, so it's a less */ + return GenericLessThan; + } + + /* Check if the prefix is longer */ + if (PrefixLength > StringLength) return GenericGreaterThan; + + /* If we got here, then they are 100% equal */ + return GenericEqual; +} + /* * @unimplemented */ @@ -86,13 +153,15 @@ RtlInsertUnicodePrefix(PUNICODE_PREFIX_TABLE PrefixTable, * - init splay links DONE * - find a matching tree DONE * - if !found, insert a new NTC_ROOT entry and return TRUE; DONE - * - if found, loop tree and compare strings: - * if equal, handle casematch/nomatch + * - if found, loop tree and compare strings: DONE + * if equal, handle casematch/nomatch DONE * if greater or lesser equal, then add left/right childs accordingly - * - splay the tree + * - splay the tree DONE */ - PUNICODE_PREFIX_TABLE_ENTRY CurrentEntry, PreviousEntry; + PUNICODE_PREFIX_TABLE_ENTRY CurrentEntry, PreviousEntry, Entry, NextEntry; ULONG NameCount; + RTL_GENERIC_COMPARE_RESULTS Result; + PRTL_SPLAY_LINKS SplayLinks; /* Find out how many names there are */ NameCount = ComputeUnicodeNameLength(Prefix); @@ -127,9 +196,77 @@ RtlInsertUnicodePrefix(PUNICODE_PREFIX_TABLE PrefixTable, return TRUE; } - /* FIXME */ - UNIMPLEMENTED; - return FALSE; + /* We found a tree, so star thte search loop */ + Entry = CurrentEntry; + while (TRUE) + { + /* Do a case-insensitive comparison to find out the match level */ + Result = CompareUnicodeStrings(Entry->Prefix, Prefix, 0); + if (Result == GenericEqual) + { + /* We have a match, start doing a case-sensitive search */ + NextEntry = Entry; + + /* Search the circular case-match list */ + do + { + /* Check if we found a match */ + if (CompareUnicodeStrings(NextEntry->Prefix, Prefix, -1) == + (GenericEqual)) + { + /* We must fail the insert: it already exists */ + return FALSE; + } + + /* Move to the next entry in the circular list */ + NextEntry = NextEntry->CaseMatch; + } + while (NextEntry != Entry); + + /* + * No match found, so we can safely insert it. Remember that a + * case insensitive match was found, so this is not a ROOT NTC + * but a Case Match NTC instead. + */ + PrefixTableEntry->NodeTypeCode = PFX_NTC_CASE_MATCH; + PrefixTableEntry->NextPrefixTree = NULL; + + /* Insert it into the circular list */ + PrefixTableEntry->CaseMatch = Entry->CaseMatch; + Entry->CaseMatch = PrefixTableEntry; + } + else if (Result == GenericGreaterThan) + { + /* TODO: Check out the left child and add us */ + } + else + { + /* TODO: Check out the right child and add us */ + } + } + + /* Get the next tree entry */ + NextEntry = CurrentEntry->NextPrefixTree; + + /* Set what was the current entry to a child entry */ + CurrentEntry->NodeTypeCode = PFX_NTC_CHILD; + CurrentEntry->NextPrefixTree = NULL; + + /* Splay the tree */ + SplayLinks = RtlSplay(&Entry->Links); + + /* The link points to the root, get it */ + Entry = CONTAINING_RECORD(SplayLinks, UNICODE_PREFIX_TABLE_ENTRY, Links); + + /* Mark the root as a root entry */ + Entry->NodeTypeCode = PFX_NTC_ROOT; + + /* Add it to the tree list */ + PreviousEntry->NextPrefixTree = Entry; + Entry->NextPrefixTree = NextEntry; + + /* Return success */ + return TRUE; } /*