2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * PURPOSE: Unicode Prefix implementation
5 * FILE: lib/rtl/unicodeprefix.c
6 * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
9 /* INCLUDES *****************************************************************/
17 * FIXME: Try to find the official names and add to NDK
18 * Definitions come from fastfat driver.
20 typedef USHORT NODE_TYPE_CODE
;
21 #define PFX_NTC_TABLE ((NODE_TYPE_CODE)0x0800)
22 #define PFX_NTC_ROOT ((NODE_TYPE_CODE)0x0801)
23 #define PFX_NTC_CHILD ((NODE_TYPE_CODE)0x0802)
24 #define PFX_NTC_CASE_MATCH ((NODE_TYPE_CODE)0x0803)
26 /* FUNCTIONS ***************************************************************/
31 ComputeUnicodeNameLength(IN PUNICODE_STRING UnicodeName
)
33 ULONG Chars
= UnicodeName
->Length
/ sizeof(WCHAR
);
34 ULONG i
, NamesFound
= 1;
37 for (i
= 0; i
< (Chars
- 1); i
++)
39 /* Check if we found a backslash, meaning another name */
40 if (UnicodeName
->Buffer
[i
] == '\\') NamesFound
++;
43 /* Return the number of names found */
50 PUNICODE_PREFIX_TABLE_ENTRY
52 RtlFindUnicodePrefix(PUNICODE_PREFIX_TABLE PrefixTable
,
53 PUNICODE_STRING FullName
,
54 ULONG CaseInsensitiveIndex
)
65 RtlInitializeUnicodePrefix(PUNICODE_PREFIX_TABLE PrefixTable
)
68 PrefixTable
->NameLength
= 0;
69 PrefixTable
->LastNextEntry
= NULL
;
70 PrefixTable
->NodeTypeCode
= PFX_NTC_TABLE
;
71 PrefixTable
->NextPrefixTree
= (PUNICODE_PREFIX_TABLE_ENTRY
)PrefixTable
;
79 RtlInsertUnicodePrefix(PUNICODE_PREFIX_TABLE PrefixTable
,
80 PUNICODE_STRING Prefix
,
81 PUNICODE_PREFIX_TABLE_ENTRY PrefixTableEntry
)
84 * implementation notes:
85 * - get name length (number of names) DONE
86 * - init splay links DONE
87 * - find a matching tree DONE
88 * - if !found, insert a new NTC_ROOT entry and return TRUE; DONE
89 * - if found, loop tree and compare strings:
90 * if equal, handle casematch/nomatch
91 * if greater or lesser equal, then add left/right childs accordingly
94 PUNICODE_PREFIX_TABLE_ENTRY CurrentEntry
, PreviousEntry
;
97 /* Find out how many names there are */
98 NameCount
= ComputeUnicodeNameLength(Prefix
);
100 /* Set up the initial entry data */
101 PrefixTableEntry
->NameLength
= NameCount
;
102 PrefixTableEntry
->Prefix
= Prefix
;
103 RtlInitializeSplayLinks(&PrefixTableEntry
->Links
);
105 /* Find the right spot where to insert this entry */
106 PreviousEntry
= (PUNICODE_PREFIX_TABLE_ENTRY
)PrefixTable
;
107 CurrentEntry
= PreviousEntry
->NextPrefixTree
;
108 while (CurrentEntry
->NameLength
> NameCount
)
110 /* Not a match, move to the next entry */
111 PreviousEntry
= CurrentEntry
;
112 CurrentEntry
= CurrentEntry
->NextPrefixTree
;
115 /* Check if we did find a tree by now */
116 if (CurrentEntry
->NameLength
!= NameCount
)
118 /* We didn't, so insert a new entry in the list */
119 PreviousEntry
->NextPrefixTree
= PrefixTableEntry
;
120 PrefixTableEntry
->NextPrefixTree
= CurrentEntry
;
122 /* This is now a root entry with case match */
123 PrefixTableEntry
->NodeTypeCode
= PFX_NTC_ROOT
;
124 PrefixTableEntry
->CaseMatch
= PrefixTableEntry
;
138 PUNICODE_PREFIX_TABLE_ENTRY
140 RtlNextUnicodePrefix(PUNICODE_PREFIX_TABLE PrefixTable
,
143 PRTL_SPLAY_LINKS SplayLinks
;
144 PUNICODE_PREFIX_TABLE_ENTRY Entry
, CaseMatchEntry
;
146 /* We might need this entry 2/3rd of the time, so cache it now */
147 CaseMatchEntry
= PrefixTable
->LastNextEntry
->CaseMatch
;
149 /* Check if this is a restart or if we don't have a last entry */
150 if ((Restart
) || !(PrefixTable
->LastNextEntry
))
152 /* Get the next entry and validate it */
153 Entry
= PrefixTable
->NextPrefixTree
;
154 if (Entry
->NodeTypeCode
== PFX_NTC_TABLE
) return NULL
;
156 /* Now get the Splay Tree Links */
157 SplayLinks
= &Entry
->Links
;
159 /* Loop until we get the first node in the tree */
160 while (RtlLeftChild(SplayLinks
)) SplayLinks
= RtlLeftChild(SplayLinks
);
162 /* Get the entry from it */
163 Entry
= CONTAINING_RECORD(SplayLinks
,
164 UNICODE_PREFIX_TABLE_ENTRY
,
167 else if (CaseMatchEntry
->NodeTypeCode
== PFX_NTC_CASE_MATCH
)
169 /* If the last entry was a Case Match, then return it */
170 Entry
= CaseMatchEntry
;
174 /* Find the successor */
175 SplayLinks
= RtlRealSuccessor(&CaseMatchEntry
->Links
);
178 /* Didn't find one, we'll have to search the tree */
179 SplayLinks
= &PrefixTable
->LastNextEntry
->Links
;
181 /* Get the topmost node (root) */
182 while (!RtlIsRoot(SplayLinks
)) SplayLinks
= RtlParent(SplayLinks
);
183 Entry
= CONTAINING_RECORD(SplayLinks
,
184 UNICODE_PREFIX_TABLE_ENTRY
,
187 /* Get its tree and make sure somethign is in it */
188 Entry
= Entry
->NextPrefixTree
;
189 if (Entry
->NameLength
<= 0) return NULL
;
191 /* Select these new links and find the first node */
192 while (RtlLeftChild(SplayLinks
)) SplayLinks
= RtlLeftChild(SplayLinks
);
195 /* Get the entry from it */
196 Entry
= CONTAINING_RECORD(SplayLinks
,
197 UNICODE_PREFIX_TABLE_ENTRY
,
201 /* Save this entry as the last one returned, and return it */
202 PrefixTable
->LastNextEntry
= Entry
;
211 RtlRemoveUnicodePrefix(PUNICODE_PREFIX_TABLE PrefixTable
,
212 PUNICODE_PREFIX_TABLE_ENTRY PrefixTableEntry
)
214 PUNICODE_PREFIX_TABLE_ENTRY Entry
, RefEntry
, NewEntry
;
215 PRTL_SPLAY_LINKS SplayLinks
;
217 /* Erase the last entry */
218 PrefixTable
->LastNextEntry
= NULL
;
220 /* Check if this was a Case Match Entry */
221 if (PrefixTableEntry
->NodeTypeCode
== PFX_NTC_CASE_MATCH
)
223 /* Get the case match entry */
224 Entry
= PrefixTableEntry
->CaseMatch
;
226 /* Now loop until we find one referencing what the caller sent */
227 while (Entry
->CaseMatch
!= PrefixTableEntry
) Entry
= Entry
->CaseMatch
;
229 /* We found the entry that was sent, link them to delete this entry */
230 Entry
->CaseMatch
= PrefixTableEntry
->CaseMatch
;
232 else if ((PrefixTableEntry
->NodeTypeCode
== PFX_NTC_ROOT
) ||
233 (PrefixTableEntry
->NodeTypeCode
== PFX_NTC_CHILD
))
235 /* Check if this entry is a case match */
236 if (PrefixTableEntry
->CaseMatch
!= PrefixTableEntry
)
238 /* Get the case match entry */
239 Entry
= PrefixTableEntry
->CaseMatch
;
241 /* Now loop until we find one referencing what the caller sent */
242 while (Entry
->CaseMatch
!= PrefixTableEntry
) Entry
= Entry
->CaseMatch
;
244 /* We found the entry that was sent, link them to delete this entry */
245 Entry
->CaseMatch
= PrefixTableEntry
->CaseMatch
;
248 Entry
->NodeTypeCode
= PrefixTableEntry
->NodeTypeCode
;
249 Entry
->NextPrefixTree
= PrefixTableEntry
->NextPrefixTree
;
250 Entry
->Links
= PrefixTableEntry
->Links
;
252 /* Now check if we are a root entry */
253 if (RtlIsRoot(&PrefixTableEntry
->Links
))
255 /* We are, so make this entry root as well */
256 Entry
->Links
.Parent
= &Entry
->Links
;
258 /* Find the entry referencing us */
259 RefEntry
= Entry
->NextPrefixTree
;
260 while (RefEntry
->NextPrefixTree
!= Entry
)
262 /* Not this one, move to the next entry */
263 RefEntry
= RefEntry
->NextPrefixTree
;
266 /* Link them to us now */
267 RefEntry
->NextPrefixTree
= Entry
;
269 else if (RtlIsLeftChild(&PrefixTableEntry
->Links
))
271 /* We were the left child, so make us as well */
272 Entry
->Links
.LeftChild
= &Entry
->Links
;
276 /* We were the right child, so make us as well */
277 Entry
->Links
.RightChild
= &Entry
->Links
;
280 /* Check if we have a left child */
281 if (RtlLeftChild(&Entry
->Links
))
283 /* Update its parent link */
284 RtlLeftChild(&Entry
->Links
)->Parent
= &Entry
->Links
;
286 /* Check if we have a right child */
287 if (RtlRightChild(&Entry
->Links
))
289 /* Update its parent link */
290 RtlRightChild(&Entry
->Links
)->Parent
= &Entry
->Links
;
295 /* It's not a case match, so we'll delete the actual entry */
296 SplayLinks
= &PrefixTableEntry
->Links
;
298 /* Find the root entry */
299 while (!RtlIsRoot(SplayLinks
)) SplayLinks
= RtlParent(SplayLinks
);
300 Entry
= CONTAINING_RECORD(SplayLinks
,
301 UNICODE_PREFIX_TABLE_ENTRY
,
304 /* Delete the entry and check if the whole tree is gone */
305 SplayLinks
= RtlDelete(&PrefixTableEntry
->Links
);
308 /* The tree is also gone now, find the entry referencing us */
309 RefEntry
= Entry
->NextPrefixTree
;
310 while (RefEntry
->NextPrefixTree
!= Entry
)
312 /* Not this one, move to the next entry */
313 RefEntry
= RefEntry
->NextPrefixTree
;
316 /* Link them so this entry stops being referenced */
317 RefEntry
->NextPrefixTree
= Entry
->NextPrefixTree
;
319 else if (&Entry
->Links
!= SplayLinks
)
321 /* The tree is still here, but we got moved to a new one */
322 NewEntry
= CONTAINING_RECORD(SplayLinks
,
323 UNICODE_PREFIX_TABLE_ENTRY
,
326 /* Find the entry referencing us */
327 RefEntry
= Entry
->NextPrefixTree
;
328 while (RefEntry
->NextPrefixTree
!= Entry
)
330 /* Not this one, move to the next entry */
331 RefEntry
= RefEntry
->NextPrefixTree
;
334 /* Since we got moved, make us the new root entry */
335 NewEntry
->NodeTypeCode
= PFX_NTC_ROOT
;
337 /* Link us with the entry referencing the old root */
338 RefEntry
->NextPrefixTree
= NewEntry
;
340 /* And link us with the old tree */
341 NewEntry
->NextPrefixTree
= Entry
->NextPrefixTree
;
343 /* Set the old tree as a child */
344 Entry
->NodeTypeCode
= PFX_NTC_CHILD
;
345 Entry
->NextPrefixTree
= NULL
;