xref: /reactos/dll/win32/kernel32/client/atom.c (revision c2c66aff)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS system libraries
4  * FILE:            dll/win32/kernel32/client/atom.c
5  * PURPOSE:         Atom functions
6  * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
7  */
8 
9 /* INCLUDES ******************************************************************/
10 #include <k32.h>
11 
12 #define NDEBUG
13 #include <debug.h>
14 
15 /* GLOBALS *******************************************************************/
16 
17 PRTL_ATOM_TABLE BaseLocalAtomTable = NULL;
18 
19 /* FUNCTIONS *****************************************************************/
20 
21 PVOID
22 WINAPI
InternalInitAtomTable(VOID)23 InternalInitAtomTable(VOID)
24 {
25     /* Create or return the local table */
26     if (!BaseLocalAtomTable) RtlCreateAtomTable(0, &BaseLocalAtomTable);
27     return BaseLocalAtomTable;
28 }
29 
30 ATOM
31 WINAPI
InternalAddAtom(BOOLEAN Local,BOOLEAN Unicode,LPCSTR AtomName)32 InternalAddAtom(BOOLEAN Local,
33                 BOOLEAN Unicode,
34                 LPCSTR AtomName)
35 {
36     NTSTATUS Status;
37     ANSI_STRING AnsiString;
38     UNICODE_STRING UnicodeString;
39     PUNICODE_STRING AtomNameString;
40     ATOM Atom = INVALID_ATOM;
41 
42     /* Check if it's an integer atom */
43     if ((ULONG_PTR)AtomName <= 0xFFFF)
44     {
45         /* Convert the name to an atom */
46         Atom = (ATOM)PtrToShort((PVOID)AtomName);
47         if (Atom >= MAXINTATOM)
48         {
49             /* Fail, atom number too large */
50             BaseSetLastNTError(STATUS_INVALID_PARAMETER);
51             return INVALID_ATOM;
52         }
53 
54         /* Return it */
55         return Atom;
56     }
57     else
58     {
59         /* Check if this is a unicode atom */
60         if (Unicode)
61         {
62             /* Use a unicode string */
63             AtomNameString = &UnicodeString;
64             RtlInitUnicodeString(AtomNameString, (LPWSTR)AtomName);
65             Status = STATUS_SUCCESS;
66         }
67         else
68         {
69             /* Use an ansi string */
70             RtlInitAnsiString(&AnsiString, AtomName );
71 
72             /* Check if we can abuse the TEB */
73             if (AnsiString.MaximumLength > 260)
74             {
75                 /* We can't, allocate a new string */
76                 AtomNameString = &UnicodeString;
77                 Status = RtlAnsiStringToUnicodeString(AtomNameString,
78                                                       &AnsiString,
79                                                       TRUE);
80             }
81             else
82             {
83                 /* We can! Get the TEB String */
84                 AtomNameString = &NtCurrentTeb()->StaticUnicodeString;
85 
86                 /* Convert it into the TEB */
87                 Status = RtlAnsiStringToUnicodeString(AtomNameString,
88                                                       &AnsiString,
89                                                       FALSE);
90             }
91         }
92 
93         /* Check for failure */
94         if (!NT_SUCCESS(Status))
95         {
96             BaseSetLastNTError(Status);
97             return Atom;
98         }
99     }
100 
101     /* Check if we're doing local add */
102     if (Local)
103     {
104         /* Do a local add */
105         Status = RtlAddAtomToAtomTable(InternalInitAtomTable(),
106                                        AtomNameString->Buffer,
107                                        &Atom);
108     }
109     else
110     {
111         /* Do a global add */
112         Status = NtAddAtom(AtomNameString->Buffer,
113                            AtomNameString->Length,
114                            &Atom);
115     }
116 
117     /* Check for failure */
118     if (!NT_SUCCESS(Status)) BaseSetLastNTError(Status);
119 
120     /* Check if we were non-static ANSI */
121     if (!(Unicode) && (AtomNameString == &UnicodeString))
122     {
123         /* Free the allocated buffer */
124         RtlFreeUnicodeString(AtomNameString);
125     }
126 
127     /* Return the atom */
128     return Atom;
129 }
130 
131 ATOM
132 WINAPI
InternalFindAtom(BOOLEAN Local,BOOLEAN Unicode,LPCSTR AtomName)133 InternalFindAtom(BOOLEAN Local,
134                  BOOLEAN Unicode,
135                  LPCSTR AtomName)
136 {
137     NTSTATUS Status;
138     ANSI_STRING AnsiString;
139     UNICODE_STRING UnicodeString;
140     PUNICODE_STRING AtomNameString;
141     ATOM Atom = INVALID_ATOM;
142 
143     /* Check if it's an integer atom */
144     if ((ULONG_PTR)AtomName <= 0xFFFF)
145     {
146         /* Convert the name to an atom */
147         Atom = (ATOM)PtrToShort((PVOID)AtomName);
148         if (Atom >= MAXINTATOM)
149         {
150             /* Fail, atom number too large */
151             BaseSetLastNTError(STATUS_INVALID_PARAMETER);
152             DPRINT1("Invalid atom\n");
153         }
154 
155         /* Return it */
156         return Atom;
157     }
158     else
159     {
160         /* Check if this is a unicode atom */
161         if (Unicode)
162         {
163             /* Use a unicode string */
164             AtomNameString = &UnicodeString;
165             RtlInitUnicodeString(AtomNameString, (LPWSTR)AtomName);
166             Status = STATUS_SUCCESS;
167         }
168         else
169         {
170             /* Use an ansi string */
171             RtlInitAnsiString(&AnsiString, AtomName);
172 
173             /* Check if we can abuse the TEB */
174             if (AnsiString.MaximumLength > 260)
175             {
176                 /* We can't, allocate a new string */
177                 AtomNameString = &UnicodeString;
178                 Status = RtlAnsiStringToUnicodeString(AtomNameString,
179                                                       &AnsiString,
180                                                       TRUE);
181             }
182             else
183             {
184                 /* We can! Get the TEB String */
185                 AtomNameString = &NtCurrentTeb()->StaticUnicodeString;
186 
187                 /* Convert it into the TEB */
188                 Status = RtlAnsiStringToUnicodeString(AtomNameString,
189                                                       &AnsiString,
190                                                       FALSE);
191             }
192         }
193 
194         /* Check for failure */
195         if (!NT_SUCCESS(Status))
196         {
197             DPRINT1("Failed\n");
198             BaseSetLastNTError(Status);
199             return Atom;
200         }
201     }
202 
203     /* Check if we're doing local lookup */
204     if (Local)
205     {
206         /* Do a local lookup */
207         Status = RtlLookupAtomInAtomTable(InternalInitAtomTable(),
208                                           AtomNameString->Buffer,
209                                           &Atom);
210     }
211     else
212     {
213         /* Do a global search */
214         if (!AtomNameString->Length)
215         {
216             /* This is illegal in win32 */
217             DPRINT1("No name given\n");
218             Status = STATUS_OBJECT_NAME_NOT_FOUND;
219         }
220         else
221         {
222             /* Call the global function */
223             Status = NtFindAtom(AtomNameString->Buffer,
224                                 AtomNameString->Length,
225                                 &Atom);
226         }
227     }
228 
229     /* Check for failure */
230     if (!NT_SUCCESS(Status)) BaseSetLastNTError(Status);
231 
232     /* Check if we were non-static ANSI */
233     if (!(Unicode) && (AtomNameString == &UnicodeString))
234     {
235         /* Free the allocated buffer */
236         RtlFreeUnicodeString(AtomNameString);
237     }
238 
239     /* Return the atom */
240     return Atom;
241 }
242 
243 ATOM
244 WINAPI
InternalDeleteAtom(BOOLEAN Local,ATOM Atom)245 InternalDeleteAtom(BOOLEAN Local,
246                    ATOM Atom)
247 {
248     NTSTATUS Status;
249 
250     /* Validate it */
251     if (Atom >= MAXINTATOM)
252     {
253         /* Check if it's a local delete */
254         if (Local)
255         {
256             /* Delete it locally */
257             Status = RtlDeleteAtomFromAtomTable(InternalInitAtomTable(), Atom);
258         }
259         else
260         {
261             /* Delete it globall */
262             Status = NtDeleteAtom(Atom);
263         }
264 
265         /* Check for success */
266         if (!NT_SUCCESS(Status))
267         {
268             /* Fail */
269             BaseSetLastNTError(Status);
270             return INVALID_ATOM;
271         }
272     }
273 
274     /* Return failure */
275     return 0;
276 }
277 
278 UINT
279 WINAPI
InternalGetAtomName(BOOLEAN Local,BOOLEAN Unicode,ATOM Atom,LPSTR AtomName,DWORD Size)280 InternalGetAtomName(BOOLEAN Local,
281                     BOOLEAN Unicode,
282                     ATOM Atom,
283                     LPSTR AtomName,
284                     DWORD Size)
285 {
286     NTSTATUS Status;
287     DWORD RetVal = 0;
288     ANSI_STRING AnsiString;
289     UNICODE_STRING UnicodeString;
290     PVOID TempBuffer = NULL;
291     PWSTR AtomNameString;
292     ULONG AtomInfoLength;
293     ULONG AtomNameLength;
294     PATOM_BASIC_INFORMATION AtomInfo;
295 
296     /* Normalize the size as not to overflow */
297     if (!Unicode && Size > 0x7000) Size = 0x7000;
298 
299     /* Make sure it's valid too */
300     if (!Size)
301     {
302         BaseSetLastNTError(STATUS_BUFFER_OVERFLOW);
303         return 0;
304     }
305     if (!Atom)
306     {
307         BaseSetLastNTError(STATUS_INVALID_PARAMETER);
308         return 0;
309     }
310 
311     /* Check if this is a global query */
312     if (Local)
313     {
314         /* Set the query length */
315         AtomNameLength = Size * sizeof(WCHAR);
316 
317         /* If it's unicode, just keep the name */
318         if (Unicode)
319         {
320             AtomNameString = (PWSTR)AtomName;
321         }
322         else
323         {
324             /* Allocate memory for the ansi buffer */
325             TempBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
326                                          0,
327                                          AtomNameLength);
328             AtomNameString = TempBuffer;
329         }
330 
331         /* Query the name */
332         Status = RtlQueryAtomInAtomTable(InternalInitAtomTable(),
333                                          Atom,
334                                          NULL,
335                                          NULL,
336                                          AtomNameString,
337                                          &AtomNameLength);
338     }
339     else
340     {
341         /* We're going to do a global query, so allocate a buffer */
342         AtomInfoLength = sizeof(ATOM_BASIC_INFORMATION) +
343                          (Size * sizeof(WCHAR));
344         AtomInfo = TempBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
345                                                 0,
346                                                 AtomInfoLength);
347 
348         if (!AtomInfo)
349         {
350             BaseSetLastNTError(STATUS_NO_MEMORY);
351             return 0;
352         }
353 
354         /* Query the name */
355         Status = NtQueryInformationAtom(Atom,
356                                         AtomBasicInformation,
357                                         AtomInfo,
358                                         AtomInfoLength,
359                                         &AtomInfoLength);
360         if (NT_SUCCESS(Status))
361         {
362             /* Success. Update the length and get the name */
363             AtomNameLength = (ULONG)AtomInfo->NameLength;
364             AtomNameString = AtomInfo->Name;
365         }
366     }
367 
368     /* Check for global success */
369     if (NT_SUCCESS(Status))
370     {
371         /* Check if it was unicode */
372         if (Unicode)
373         {
374             /* We return the length in chars */
375             RetVal = AtomNameLength / sizeof(WCHAR);
376 
377             /* Copy the memory if this was a global query */
378             if (AtomNameString != (PWSTR)AtomName)
379             {
380                 RtlMoveMemory(AtomName, AtomNameString, AtomNameLength);
381             }
382 
383             /* And null-terminate it if the buffer was too large */
384             if (RetVal < Size)
385             {
386                 ((PWCHAR)AtomName)[RetVal] = UNICODE_NULL;
387             }
388         }
389         else
390         {
391             /* First create a unicode string with our data */
392             UnicodeString.Buffer = AtomNameString;
393             UnicodeString.Length = (USHORT)AtomNameLength;
394             UnicodeString.MaximumLength = (USHORT)(UnicodeString.Length +
395                                                    sizeof(WCHAR));
396 
397             /* Now prepare an ansi string for conversion */
398             AnsiString.Buffer = AtomName;
399             AnsiString.Length = 0;
400             AnsiString.MaximumLength = (USHORT)Size;
401 
402             /* Convert it */
403             Status = RtlUnicodeStringToAnsiString(&AnsiString,
404                                                   &UnicodeString,
405                                                   FALSE);
406 
407             /* Return the length */
408             if (NT_SUCCESS(Status)) RetVal = AnsiString.Length;
409         }
410     }
411 
412     /* Free the temporary buffer if we have one */
413     if (TempBuffer) RtlFreeHeap(RtlGetProcessHeap(), 0, TempBuffer);
414 
415     /* Check for failure */
416     if (!NT_SUCCESS(Status))
417     {
418         /* Fail */
419         DPRINT("Failed: %lx\n", Status);
420         BaseSetLastNTError(Status);
421     }
422 
423     /* Return length */
424     return RetVal;
425 }
426 
427 /* FUNCTIONS *****************************************************************/
428 
429 /*
430  * @implemented
431  */
432 ATOM
433 WINAPI
GlobalAddAtomA(LPCSTR lpString)434 GlobalAddAtomA(LPCSTR lpString)
435 {
436     return InternalAddAtom(FALSE, FALSE, lpString);
437 }
438 
439 /*
440  * @implemented
441  */
442 ATOM
443 WINAPI
GlobalAddAtomW(LPCWSTR lpString)444 GlobalAddAtomW(LPCWSTR lpString)
445 {
446     return InternalAddAtom(FALSE, TRUE, (LPSTR)lpString);
447 }
448 
449 /*
450  * @implemented
451  */
452 ATOM
453 WINAPI
GlobalDeleteAtom(ATOM nAtom)454 GlobalDeleteAtom(ATOM nAtom)
455 {
456     return InternalDeleteAtom(FALSE, nAtom);
457 }
458 
459 /*
460  * @implemented
461  */
462 ATOM
463 WINAPI
GlobalFindAtomA(LPCSTR lpString)464 GlobalFindAtomA(LPCSTR lpString)
465 {
466     return InternalFindAtom(FALSE, FALSE, lpString);
467 }
468 
469 /*
470  * @implemented
471  */
472 ATOM
473 WINAPI
GlobalFindAtomW(LPCWSTR lpString)474 GlobalFindAtomW(LPCWSTR lpString)
475 {
476     return InternalFindAtom(FALSE, TRUE, (LPSTR)lpString);
477 }
478 
479 /*
480  * @implemented
481  */
482 UINT
483 WINAPI
GlobalGetAtomNameA(ATOM nAtom,LPSTR lpBuffer,int nSize)484 GlobalGetAtomNameA(ATOM nAtom,
485                    LPSTR lpBuffer,
486                    int nSize)
487 {
488     return InternalGetAtomName(FALSE, FALSE, nAtom, lpBuffer, (DWORD)nSize);
489 }
490 
491 /*
492  * @implemented
493  */
494 UINT
495 WINAPI
GlobalGetAtomNameW(ATOM nAtom,LPWSTR lpBuffer,int nSize)496 GlobalGetAtomNameW(ATOM nAtom,
497                    LPWSTR lpBuffer,
498                    int nSize)
499 {
500     return InternalGetAtomName(FALSE,
501                                TRUE,
502                                nAtom,
503                                (LPSTR)lpBuffer,
504                                (DWORD)nSize);
505 }
506 
507 /*
508  * @implemented
509  */
510 BOOL
511 WINAPI
InitAtomTable(DWORD nSize)512 InitAtomTable(DWORD nSize)
513 {
514     /* Normalize size */
515     if (nSize < 4 || nSize > 511) nSize = 37;
516 
517     DPRINT("Here\n");
518     return NT_SUCCESS(RtlCreateAtomTable(nSize, &BaseLocalAtomTable));
519 }
520 
521 /*
522  * @implemented
523  */
524 ATOM
525 WINAPI
AddAtomA(LPCSTR lpString)526 AddAtomA(LPCSTR lpString)
527 {
528     return InternalAddAtom(TRUE, FALSE, lpString);
529 }
530 
531 /*
532  * @implemented
533  */
534 ATOM
535 WINAPI
AddAtomW(LPCWSTR lpString)536 AddAtomW(LPCWSTR lpString)
537 {
538     return InternalAddAtom(TRUE, TRUE, (LPSTR)lpString);
539 }
540 
541 /*
542  * @implemented
543  */
544 ATOM
545 WINAPI
DeleteAtom(ATOM nAtom)546 DeleteAtom(ATOM nAtom)
547 {
548     return InternalDeleteAtom(TRUE, nAtom);
549 }
550 
551 /*
552  * @implemented
553  */
554 ATOM
555 WINAPI
FindAtomA(LPCSTR lpString)556 FindAtomA(LPCSTR lpString)
557 {
558     return InternalFindAtom(TRUE, FALSE, lpString);
559 }
560 
561 /*
562  * @implemented
563  */
564 ATOM
565 WINAPI
FindAtomW(LPCWSTR lpString)566 FindAtomW(LPCWSTR lpString)
567 {
568     return InternalFindAtom(TRUE, TRUE, (LPSTR)lpString);
569 
570 }
571 
572 /*
573  * @implemented
574  */
575 UINT
576 WINAPI
GetAtomNameA(ATOM nAtom,LPSTR lpBuffer,int nSize)577 GetAtomNameA(ATOM nAtom,
578              LPSTR lpBuffer,
579              int nSize)
580 {
581     return InternalGetAtomName(TRUE, FALSE, nAtom, lpBuffer, (DWORD)nSize);
582 }
583 
584 /*
585  * @implemented
586  */
587 UINT
588 WINAPI
GetAtomNameW(ATOM nAtom,LPWSTR lpBuffer,int nSize)589 GetAtomNameW(ATOM nAtom,
590              LPWSTR lpBuffer,
591              int nSize)
592 {
593     return InternalGetAtomName(TRUE,
594                                TRUE,
595                                nAtom,
596                                (LPSTR)lpBuffer,
597                                (DWORD)nSize);
598 }
599 /* EOF */
600