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