Reactos
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
17PRTL_ATOM_TABLE BaseLocalAtomTable = NULL;
18
19/* FUNCTIONS *****************************************************************/
20
21PVOID
22WINAPI
23InternalInitAtomTable(VOID)
24{
25 /* Create or return the local table */
26 if (!BaseLocalAtomTable) RtlCreateAtomTable(0, &BaseLocalAtomTable);
27 return BaseLocalAtomTable;
28}
29
30ATOM
31WINAPI
32InternalAddAtom(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
131ATOM
132WINAPI
133InternalFindAtom(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
243ATOM
244WINAPI
245InternalDeleteAtom(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
278UINT
279WINAPI
280InternalGetAtomName(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 */
432ATOM
433WINAPI
434GlobalAddAtomW(LPCWSTR lpString)
435{
436 return InternalAddAtom(FALSE, TRUE, (LPSTR)lpString);
437}
438
439/*
440 * @implemented
441 */
442ATOM
443WINAPI
444GlobalDeleteAtom(ATOM nAtom)
445{
446 return InternalDeleteAtom(FALSE, nAtom);
447}
448
449/*
450 * @implemented
451 */
452ATOM
453WINAPI
454GlobalFindAtomW(LPCWSTR lpString)
455{
456 return InternalFindAtom(FALSE, TRUE, (LPSTR)lpString);
457}
458
459/*
460 * @implemented
461 */
462UINT
463WINAPI
464GlobalGetAtomNameA(ATOM nAtom,
465 LPSTR lpBuffer,
466 int nSize)
467{
468 return InternalGetAtomName(FALSE, FALSE, nAtom, lpBuffer, (DWORD)nSize);
469}
470
471/*
472 * @implemented
473 */
474UINT
475WINAPI
476GlobalGetAtomNameW(ATOM nAtom,
477 LPWSTR lpBuffer,
478 int nSize)
479{
480 return InternalGetAtomName(FALSE,
481 TRUE,
482 nAtom,
483 (LPSTR)lpBuffer,
484 (DWORD)nSize);
485}
486
487/*
488 * @implemented
489 */
490BOOL
491WINAPI
492InitAtomTable(DWORD nSize)
493{
494 /* Normalize size */
495 if (nSize < 4 || nSize > 511) nSize = 37;
496
497 DPRINT("Here\n");
498 return NT_SUCCESS(RtlCreateAtomTable(nSize, &BaseLocalAtomTable));
499}
500
501/*
502 * @implemented
503 */
504ATOM
505WINAPI
506AddAtomA(LPCSTR lpString)
507{
508 return InternalAddAtom(TRUE, FALSE, lpString);
509}
510
511/*
512 * @implemented
513 */
514ATOM
515WINAPI
516AddAtomW(LPCWSTR lpString)
517{
518 return InternalAddAtom(TRUE, TRUE, (LPSTR)lpString);
519}
520
521/*
522 * @implemented
523 */
524ATOM
525WINAPI
526DeleteAtom(ATOM nAtom)
527{
528 return InternalDeleteAtom(TRUE, nAtom);
529}
530
531/*
532 * @implemented
533 */
534ATOM
535WINAPI
536FindAtomA(LPCSTR lpString)
537{
538 return InternalFindAtom(TRUE, FALSE, lpString);
539}
540
541/*
542 * @implemented
543 */
544ATOM
545WINAPI
546FindAtomW(LPCWSTR lpString)
547{
548 return InternalFindAtom(TRUE, TRUE, (LPSTR)lpString);
549
550}
551
552/*
553 * @implemented
554 */
555UINT
556WINAPI
557GetAtomNameA(ATOM nAtom,
558 LPSTR lpBuffer,
559 int nSize)
560{
561 return InternalGetAtomName(TRUE, FALSE, nAtom, lpBuffer, (DWORD)nSize);
562}
563
564/*
565 * @implemented
566 */
567UINT
568WINAPI
569GetAtomNameW(ATOM nAtom,
570 LPWSTR lpBuffer,
571 int nSize)
572{
573 return InternalGetAtomName(TRUE,
574 TRUE,
575 nAtom,
576 (LPSTR)lpBuffer,
577 (DWORD)nSize);
578}
579/* EOF */