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