- Update to r53061
[reactos.git] / dll / win32 / kernel32 / client / 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 <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 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
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
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
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
434 GlobalAddAtomA(LPCSTR lpString)
435 {
436 return InternalAddAtom(FALSE, FALSE, lpString);
437 }
438
439 /*
440 * @implemented
441 */
442 ATOM
443 WINAPI
444 GlobalAddAtomW(LPCWSTR lpString)
445 {
446 return InternalAddAtom(FALSE, TRUE, (LPSTR)lpString);
447 }
448
449 /*
450 * @implemented
451 */
452 ATOM
453 WINAPI
454 GlobalDeleteAtom(ATOM nAtom)
455 {
456 return InternalDeleteAtom(FALSE, nAtom);
457 }
458
459 /*
460 * @implemented
461 */
462 ATOM
463 WINAPI
464 GlobalFindAtomA(LPCSTR lpString)
465 {
466 return InternalFindAtom(FALSE, FALSE, lpString);
467 }
468
469 /*
470 * @implemented
471 */
472 ATOM
473 WINAPI
474 GlobalFindAtomW(LPCWSTR lpString)
475 {
476 return InternalFindAtom(FALSE, TRUE, (LPSTR)lpString);
477 }
478
479 /*
480 * @implemented
481 */
482 UINT
483 WINAPI
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
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
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
526 AddAtomA(LPCSTR lpString)
527 {
528 return InternalAddAtom(TRUE, FALSE, lpString);
529 }
530
531 /*
532 * @implemented
533 */
534 ATOM
535 WINAPI
536 AddAtomW(LPCWSTR lpString)
537 {
538 return InternalAddAtom(TRUE, TRUE, (LPSTR)lpString);
539 }
540
541 /*
542 * @implemented
543 */
544 ATOM
545 WINAPI
546 DeleteAtom(ATOM nAtom)
547 {
548 return InternalDeleteAtom(TRUE, nAtom);
549 }
550
551 /*
552 * @implemented
553 */
554 ATOM
555 WINAPI
556 FindAtomA(LPCSTR lpString)
557 {
558 return InternalFindAtom(TRUE, FALSE, lpString);
559 }
560
561 /*
562 * @implemented
563 */
564 ATOM
565 WINAPI
566 FindAtomW(LPCWSTR lpString)
567 {
568 return InternalFindAtom(TRUE, TRUE, (LPSTR)lpString);
569
570 }
571
572 /*
573 * @implemented
574 */
575 UINT
576 WINAPI
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
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 */