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 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 */ 600