Reactos
at master 1501 lines 33 kB view raw
1/* 2 * Copyright 2019 Nikolay Sivov for CodeWeavers 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 */ 18 19#include <stdarg.h> 20 21#include "windef.h" 22#include "winbase.h" 23#include "winnls.h" 24#include "shlwapi.h" 25#include "winternl.h" 26 27#include "kernelbase.h" 28#include "wine/debug.h" 29#include "wine/exception.h" 30 31WINE_DEFAULT_DEBUG_CHANNEL(string); 32 33static BOOL char_compare(WORD ch1, WORD ch2, DWORD flags) 34{ 35 char str1[3], str2[3]; 36 37 str1[0] = LOBYTE(ch1); 38 if (IsDBCSLeadByte(str1[0])) 39 { 40 str1[1] = HIBYTE(ch1); 41 str1[2] = '\0'; 42 } 43 else 44 str1[1] = '\0'; 45 46 str2[0] = LOBYTE(ch2); 47 if (IsDBCSLeadByte(str2[0])) 48 { 49 str2[1] = HIBYTE(ch2); 50 str2[2] = '\0'; 51 } 52 else 53 str2[1] = '\0'; 54 55 return CompareStringA(GetThreadLocale(), flags, str1, -1, str2, -1) - CSTR_EQUAL; 56} 57 58int WINAPI lstrcmpA( LPCSTR str1, LPCSTR str2 ) 59{ 60 if (!str1 && !str2) return 0; 61 if (!str1) return -1; 62 if (!str2) return 1; 63 return CompareStringA( GetThreadLocale(), LOCALE_USE_CP_ACP, str1, -1, str2, -1 ) - 2; 64} 65 66int WINAPI lstrcmpW(LPCWSTR str1, LPCWSTR str2) 67{ 68 if (!str1 && !str2) return 0; 69 if (!str1) return -1; 70 if (!str2) return 1; 71 return CompareStringW( GetThreadLocale(), 0, str1, -1, str2, -1 ) - 2; 72} 73 74int WINAPI lstrcmpiA(LPCSTR str1, LPCSTR str2) 75{ 76 if (!str1 && !str2) return 0; 77 if (!str1) return -1; 78 if (!str2) return 1; 79 return CompareStringA( GetThreadLocale(), NORM_IGNORECASE|LOCALE_USE_CP_ACP, str1, -1, str2, -1 ) - 2; 80} 81 82int WINAPI lstrcmpiW(LPCWSTR str1, LPCWSTR str2) 83{ 84 if (!str1 && !str2) return 0; 85 if (!str1) return -1; 86 if (!str2) return 1; 87 return CompareStringW( GetThreadLocale(), NORM_IGNORECASE, str1, -1, str2, -1 ) - 2; 88} 89 90LPSTR WINAPI KERNELBASE_lstrcpynA( LPSTR dst, LPCSTR src, INT n ) 91{ 92 /* Note: this function differs from the UNIX strncpy, it _always_ writes 93 * a terminating \0. 94 * 95 * Note: n is an INT but Windows treats it as unsigned, and will happily 96 * copy a gazillion chars if n is negative. 97 */ 98 __TRY 99 { 100 LPSTR d = dst; 101 LPCSTR s = src; 102 UINT count = n; 103 104 while ((count > 1) && *s) 105 { 106 count--; 107 *d++ = *s++; 108 } 109 if (count) *d = 0; 110 } 111 __EXCEPT_PAGE_FAULT 112 { 113 SetLastError( ERROR_INVALID_PARAMETER ); 114 return 0; 115 } 116 __ENDTRY 117 return dst; 118} 119 120LPWSTR WINAPI KERNELBASE_lstrcpynW( LPWSTR dst, LPCWSTR src, INT n ) 121{ 122 /* Note: this function differs from the UNIX strncpy, it _always_ writes 123 * a terminating \0 124 * 125 * Note: n is an INT but Windows treats it as unsigned, and will happily 126 * copy a gazillion chars if n is negative. 127 */ 128 __TRY 129 { 130 LPWSTR d = dst; 131 LPCWSTR s = src; 132 UINT count = n; 133 134 while ((count > 1) && *s) 135 { 136 count--; 137 *d++ = *s++; 138 } 139 if (count) *d = 0; 140 } 141 __EXCEPT_PAGE_FAULT 142 { 143 SetLastError( ERROR_INVALID_PARAMETER ); 144 return 0; 145 } 146 __ENDTRY 147 return dst; 148} 149 150INT WINAPI KERNELBASE_lstrlenA( LPCSTR str ) 151{ 152 INT ret; 153 __TRY 154 { 155 ret = strlen(str); 156 } 157 __EXCEPT_PAGE_FAULT 158 { 159 SetLastError( ERROR_INVALID_PARAMETER ); 160 return 0; 161 } 162 __ENDTRY 163 return ret; 164} 165 166INT WINAPI KERNELBASE_lstrlenW( LPCWSTR str ) 167{ 168 INT ret; 169 __TRY 170 { 171 ret = wcslen(str); 172 } 173 __EXCEPT_PAGE_FAULT 174 { 175 SetLastError( ERROR_INVALID_PARAMETER ); 176 return 0; 177 } 178 __ENDTRY 179 return ret; 180} 181 182DWORD WINAPI StrCmpCA(const char *str, const char *cmp) 183{ 184 return lstrcmpA(str, cmp); 185} 186 187DWORD WINAPI StrCmpCW(const WCHAR *str, const WCHAR *cmp) 188{ 189 return lstrcmpW(str, cmp); 190} 191 192DWORD WINAPI StrCmpICA(const char *str, const char *cmp) 193{ 194 return lstrcmpiA(str, cmp); 195} 196 197DWORD WINAPI StrCmpICW(const WCHAR *str, const WCHAR *cmp) 198{ 199 return lstrcmpiW(str, cmp); 200} 201 202DWORD WINAPI StrCmpNICA(const char *str, const char *cmp, DWORD len) 203{ 204 return StrCmpNIA(str, cmp, len); 205} 206 207DWORD WINAPI StrCmpNICW(const WCHAR *str, const WCHAR *cmp, DWORD len) 208{ 209 return StrCmpNIW(str, cmp, len); 210} 211 212char * WINAPI StrChrA(const char *str, WORD ch) 213{ 214 TRACE("%s, %#x\n", wine_dbgstr_a(str), ch); 215 216 if (!str) 217 return NULL; 218 219 while (*str) 220 { 221 if (!char_compare(*str, ch, 0)) 222 return (char *)str; 223 str = CharNextA(str); 224 } 225 226 return NULL; 227} 228 229WCHAR * WINAPI StrChrW(const WCHAR *str, WCHAR ch) 230{ 231 TRACE("%s, %#x\n", wine_dbgstr_w(str), ch); 232 233 if (!str) 234 return NULL; 235 236 return wcschr(str, ch); 237} 238 239char * WINAPI StrChrIA(const char *str, WORD ch) 240{ 241 TRACE("%s, %i\n", wine_dbgstr_a(str), ch); 242 243 if (!str) 244 return NULL; 245 246 while (*str) 247 { 248 if (!ChrCmpIA(*str, ch)) 249 return (char *)str; 250 str = CharNextA(str); 251 } 252 253 return NULL; 254} 255 256WCHAR * WINAPI StrChrIW(const WCHAR *str, WCHAR ch) 257{ 258 TRACE("%s, %#x\n", wine_dbgstr_w(str), ch); 259 260 if (!str) 261 return NULL; 262 263 ch = towupper(ch); 264 while (*str) 265 { 266 if (towupper(*str) == ch) 267 return (WCHAR *)str; 268 str++; 269 } 270 str = NULL; 271 272 return (WCHAR *)str; 273} 274 275WCHAR * WINAPI StrChrNW(const WCHAR *str, WCHAR ch, UINT max_len) 276{ 277 TRACE("%s, %#x, %u\n", wine_dbgstr_wn(str, max_len), ch, max_len); 278 279 if (!str) 280 return NULL; 281 282 while (*str && max_len-- > 0) 283 { 284 if (*str == ch) 285 return (WCHAR *)str; 286 str++; 287 } 288 289 return NULL; 290} 291 292char * WINAPI StrDupA(const char *str) 293{ 294 unsigned int len; 295 char *ret; 296 297 TRACE("%s\n", wine_dbgstr_a(str)); 298 299 len = str ? strlen(str) + 1 : 1; 300 ret = LocalAlloc(LMEM_FIXED, len); 301 302 if (ret) 303 { 304 if (str) 305 memcpy(ret, str, len); 306 else 307 *ret = '\0'; 308 } 309 310 return ret; 311} 312 313WCHAR * WINAPI StrDupW(const WCHAR *str) 314{ 315 unsigned int len; 316 WCHAR *ret; 317 318 TRACE("%s\n", wine_dbgstr_w(str)); 319 320 len = (str ? lstrlenW(str) + 1 : 1) * sizeof(WCHAR); 321 ret = LocalAlloc(LMEM_FIXED, len); 322 323 if (ret) 324 { 325 if (str) 326 memcpy(ret, str, len); 327 else 328 *ret = '\0'; 329 } 330 331 return ret; 332} 333 334BOOL WINAPI ChrCmpIA(WORD ch1, WORD ch2) 335{ 336 TRACE("%#x, %#x\n", ch1, ch2); 337 338 return char_compare(ch1, ch2, NORM_IGNORECASE); 339} 340 341BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2) 342{ 343 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE, &ch1, 1, &ch2, 1) - CSTR_EQUAL; 344} 345 346char * WINAPI StrStrA(const char *str, const char *search) 347{ 348 const char *end; 349 size_t len; 350 351 TRACE("%s, %s\n", wine_dbgstr_a(str), wine_dbgstr_a(search)); 352 353 if (!str || !search || !*search) return NULL; 354 355 len = strlen(search); 356 end = str + strlen(str); 357 358 while (str + len <= end) 359 { 360 if (!StrCmpNA(str, search, len)) return (char *)str; 361 str = CharNextA(str); 362 } 363 return NULL; 364} 365 366WCHAR * WINAPI StrStrW(const WCHAR *str, const WCHAR *search) 367{ 368 TRACE("%s, %s\n", wine_dbgstr_w(str), wine_dbgstr_w(search)); 369 370 if (!str || !search || !*search) 371 return NULL; 372 373 return wcsstr(str, search); 374} 375 376WCHAR * WINAPI StrStrNW(const WCHAR *str, const WCHAR *search, UINT max_len) 377{ 378 unsigned int i, len; 379 380 TRACE("%s, %s, %u\n", wine_dbgstr_w(str), wine_dbgstr_w(search), max_len); 381 382 if (!str || !search || !*search || !max_len) 383 return NULL; 384 385 len = lstrlenW(search); 386 387 for (i = max_len; *str && (i > 0); i--, str++) 388 { 389 if (!wcsncmp(str, search, len)) 390 return (WCHAR *)str; 391 } 392 393 return NULL; 394} 395 396int WINAPI StrCmpNIA(const char *str, const char *cmp, int len) 397{ 398 TRACE("%s, %s, %i\n", wine_dbgstr_a(str), wine_dbgstr_a(cmp), len); 399 return CompareStringA(GetThreadLocale(), NORM_IGNORECASE, str, len, cmp, len) - CSTR_EQUAL; 400} 401 402WCHAR * WINAPI StrStrNIW(const WCHAR *str, const WCHAR *search, UINT max_len) 403{ 404 unsigned int i, len; 405 406 TRACE("%s, %s, %u\n", wine_dbgstr_w(str), wine_dbgstr_w(search), max_len); 407 408 if (!str || !search || !*search || !max_len) 409 return NULL; 410 411 len = lstrlenW(search); 412 413 for (i = max_len; *str && (i > 0); i--, str++) 414 { 415 if (!StrCmpNIW(str, search, len)) 416 return (WCHAR *)str; 417 } 418 419 return NULL; 420} 421 422int WINAPI StrCmpNA(const char *str, const char *comp, int len) 423{ 424 TRACE("%s, %s, %i\n", wine_dbgstr_a(str), wine_dbgstr_a(comp), len); 425 return CompareStringA(GetThreadLocale(), 0, str, len, comp, len) - CSTR_EQUAL; 426} 427 428int WINAPI StrCmpNW(const WCHAR *str, const WCHAR *comp, int len) 429{ 430 TRACE("%s, %s, %i\n", wine_dbgstr_w(str), wine_dbgstr_w(comp), len); 431 return CompareStringW(GetThreadLocale(), 0, str, len, comp, len) - CSTR_EQUAL; 432} 433 434DWORD WINAPI StrCmpNCA(const char *str, const char *comp, int len) 435{ 436 return StrCmpNA(str, comp, len); 437} 438 439DWORD WINAPI StrCmpNCW(const WCHAR *str, const WCHAR *comp, int len) 440{ 441 return StrCmpNW(str, comp, len); 442} 443 444int WINAPI StrCmpNIW(const WCHAR *str, const WCHAR *comp, int len) 445{ 446 TRACE("%s, %s, %i\n", wine_dbgstr_w(str), wine_dbgstr_w(comp), len); 447 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE, str, len, comp, len) - CSTR_EQUAL; 448} 449 450int WINAPI StrCmpW(const WCHAR *str, const WCHAR *comp) 451{ 452 TRACE("%s, %s\n", wine_dbgstr_w(str), wine_dbgstr_w(comp)); 453 return CompareStringW(GetThreadLocale(), 0, str, -1, comp, -1) - CSTR_EQUAL; 454} 455 456int WINAPI StrCmpIW(const WCHAR *str, const WCHAR *comp) 457{ 458 TRACE("%s, %s\n", wine_dbgstr_w(str), wine_dbgstr_w(comp)); 459 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE, str, -1, comp, -1) - CSTR_EQUAL; 460} 461 462WCHAR * WINAPI StrCpyNW(WCHAR *dst, const WCHAR *src, int count) 463{ 464 const WCHAR *s = src; 465 WCHAR *d = dst; 466 467 TRACE("%p, %s, %i\n", dst, wine_dbgstr_w(src), count); 468 469 if (s) 470 { 471 while ((count > 1) && *s) 472 { 473 count--; 474 *d++ = *s++; 475 } 476 } 477 if (count) *d = 0; 478 479 return dst; 480} 481 482char * WINAPI StrStrIA(const char *str, const char *search) 483{ 484 const char *end; 485 size_t len; 486 487 TRACE("%s, %s\n", wine_dbgstr_a(str), debugstr_a(search)); 488 489 if (!str || !search || !*search) return NULL; 490 491 len = strlen(search); 492 end = str + strlen(str); 493 494 while (str + len <= end) 495 { 496 if (!StrCmpNIA(str, search, len)) return (char *)str; 497 str = CharNextA(str); 498 } 499 return NULL; 500} 501 502WCHAR * WINAPI StrStrIW(const WCHAR *str, const WCHAR *search) 503{ 504 unsigned int len; 505 const WCHAR *end; 506 507 TRACE("%s, %s\n", wine_dbgstr_w(str), wine_dbgstr_w(search)); 508 509 if (!str || !search || !*search) 510 return NULL; 511 512 len = lstrlenW(search); 513 end = str + lstrlenW(str); 514 515 while (str + len <= end) 516 { 517 if (!StrCmpNIW(str, search, len)) 518 return (WCHAR *)str; 519 str++; 520 } 521 522 return NULL; 523} 524 525int WINAPI StrSpnA(const char *str, const char *match) 526{ 527 const char *ptr = str; 528 529 TRACE("%s, %s\n", wine_dbgstr_a(str), wine_dbgstr_a(match)); 530 531 if (!str || !match) return 0; 532 533 while (*ptr) 534 { 535 if (!StrChrA(match, *ptr)) break; 536 ptr = CharNextA(ptr); 537 } 538 return ptr - str; 539} 540 541int WINAPI StrSpnW(const WCHAR *str, const WCHAR *match) 542{ 543 if (!str || !match) return 0; 544 return wcsspn(str, match); 545} 546 547int WINAPI StrCSpnA(const char *str, const char *match) 548{ 549 const char *ptr = str; 550 551 TRACE("%s, %s\n", wine_dbgstr_a(str), wine_dbgstr_a(match)); 552 553 if (!str || !match) return 0; 554 555 while (*ptr) 556 { 557 if (StrChrA(match, *ptr)) break; 558 ptr = CharNextA(ptr); 559 } 560 return ptr - str; 561} 562 563int WINAPI StrCSpnW(const WCHAR *str, const WCHAR *match) 564{ 565 if (!str || !match) 566 return 0; 567 568 return wcscspn(str, match); 569} 570 571int WINAPI StrCSpnIA(const char *str, const char *match) 572{ 573 const char *ptr = str; 574 575 TRACE("%s, %s\n", wine_dbgstr_a(str), wine_dbgstr_a(match)); 576 577 if (!str || !match) return 0; 578 579 while (*ptr) 580 { 581 if (StrChrIA(match, *ptr)) break; 582 ptr = CharNextA(ptr); 583 } 584 return ptr - str; 585} 586 587int WINAPI StrCSpnIW(const WCHAR *str, const WCHAR *match) 588{ 589 const WCHAR *ptr = str; 590 591 TRACE("%s, %s\n", wine_dbgstr_w(str), wine_dbgstr_w(match)); 592 593 if (!str || !*str || !match) 594 return 0; 595 596 while (*ptr) 597 { 598 if (StrChrIW(match, *ptr)) break; 599 ptr++; 600 } 601 602 return ptr - str; 603} 604 605char * WINAPI StrRChrA(const char *str, const char *end, WORD ch) 606{ 607 const char *ret = NULL; 608 609 TRACE("%s, %s, %#x\n", wine_dbgstr_a(str), wine_dbgstr_a(end), ch); 610 611 if (!str) return NULL; 612 if (!end) end = str + lstrlenA(str); 613 while (*str && str <= end) 614 { 615 WORD ch2 = IsDBCSLeadByte(*str) ? *str << 8 | str[1] : *str; 616 if (!char_compare(ch, ch2, 0)) ret = str; 617 str = CharNextA(str); 618 } 619 return (char *)ret; 620} 621 622WCHAR * WINAPI StrRChrW(const WCHAR *str, const WCHAR *end, WORD ch) 623{ 624 WCHAR *ret = NULL; 625 626 if (!str) return NULL; 627 if (!end) end = str + lstrlenW(str); 628 while (str < end) 629 { 630 if (*str == ch) ret = (WCHAR *)str; 631 str++; 632 } 633 return ret; 634} 635 636char * WINAPI StrRChrIA(const char *str, const char *end, WORD ch) 637{ 638 const char *ret = NULL; 639 640 TRACE("%s, %s, %#x\n", wine_dbgstr_a(str), wine_dbgstr_a(end), ch); 641 642 if (!str) return NULL; 643 if (!end) end = str + lstrlenA(str); 644 645 while (*str && str <= end) 646 { 647 WORD ch2 = IsDBCSLeadByte(*str) ? *str << 8 | str[1] : *str; 648 if (!ChrCmpIA(ch, ch2)) ret = str; 649 str = CharNextA(str); 650 } 651 return (char *)ret; 652} 653 654WCHAR * WINAPI StrRChrIW(const WCHAR *str, const WCHAR *end, WORD ch) 655{ 656 WCHAR *ret = NULL; 657 658 if (!str) return NULL; 659 if (!end) end = str + lstrlenW(str); 660 while (str < end) 661 { 662 if (!ChrCmpIW(*str, ch)) ret = (WCHAR *)str; 663 str++; 664 } 665 return ret; 666} 667 668char * WINAPI StrRStrIA(const char *str, const char *end, const char *search) 669{ 670 char *ret = NULL; 671 WORD ch1, ch2; 672 int len; 673 674 TRACE("%s, %s\n", wine_dbgstr_a(str), wine_dbgstr_a(search)); 675 676 if (!str || !search || !*search) 677 return NULL; 678 679 if (IsDBCSLeadByte(*search)) 680 ch1 = *search << 8 | (UCHAR)search[1]; 681 else 682 ch1 = *search; 683 len = lstrlenA(search); 684 685 if (!end) 686 end = str + lstrlenA(str); 687 else /* reproduce the broken behaviour on Windows */ 688 end += min(len - 1, lstrlenA(end)); 689 690 while (str + len <= end && *str) 691 { 692 ch2 = IsDBCSLeadByte(*str) ? *str << 8 | (UCHAR)str[1] : *str; 693 if (!ChrCmpIA(ch1, ch2)) 694 { 695 if (!StrCmpNIA(str, search, len)) 696 ret = (char *)str; 697 } 698 699 str = CharNextA(str); 700 } 701 702 return ret; 703} 704 705WCHAR * WINAPI StrRStrIW(const WCHAR *str, const WCHAR *end, const WCHAR *search) 706{ 707 WCHAR *ret = NULL; 708 int len; 709 710 TRACE("%s, %s\n", wine_dbgstr_w(str), wine_dbgstr_w(search)); 711 712 if (!str || !search || !*search) 713 return NULL; 714 715 len = lstrlenW(search); 716 717 if (!end) 718 end = str + lstrlenW(str); 719 else 720 end += min(len - 1, lstrlenW(end)); 721 722 while (str + len <= end && *str) 723 { 724 if (!ChrCmpIW(*search, *str)) 725 { 726 if (!StrCmpNIW(str, search, len)) 727 ret = (WCHAR *)str; 728 } 729 str++; 730 } 731 732 return ret; 733} 734 735char * WINAPI StrPBrkA(const char *str, const char *match) 736{ 737 TRACE("%s, %s\n", wine_dbgstr_a(str), wine_dbgstr_a(match)); 738 739 if (!str || !match || !*match) 740 return NULL; 741 742 while (*str) 743 { 744 if (StrChrA(match, *str)) 745 return (char *)str; 746 str = CharNextA(str); 747 } 748 749 return NULL; 750} 751 752WCHAR * WINAPI StrPBrkW(const WCHAR *str, const WCHAR *match) 753{ 754 if (!str || !match) return NULL; 755 return wcspbrk(str, match); 756} 757 758BOOL WINAPI StrTrimA(char *str, const char *trim) 759{ 760 unsigned int len; 761 BOOL ret = FALSE; 762 char *ptr = str; 763 764 TRACE("%s, %s\n", debugstr_a(str), debugstr_a(trim)); 765 766 if (!str || !*str) 767 return FALSE; 768 769 while (*ptr && StrChrA(trim, *ptr)) 770 ptr = CharNextA(ptr); /* Skip leading matches */ 771 772 len = strlen(ptr); 773 774 if (ptr != str) 775 { 776 memmove(str, ptr, len + 1); 777 ret = TRUE; 778 } 779 780 if (len > 0) 781 { 782 ptr = str + len; 783 while (StrChrA(trim, ptr[-1])) 784 ptr = CharPrevA(str, ptr); /* Skip trailing matches */ 785 786 if (ptr != str + len) 787 { 788 *ptr = '\0'; 789 ret = TRUE; 790 } 791 } 792 793 return ret; 794} 795 796BOOL WINAPI StrTrimW(WCHAR *str, const WCHAR *trim) 797{ 798 unsigned int len; 799 WCHAR *ptr = str; 800 BOOL ret = FALSE; 801 802 TRACE("%s, %s\n", wine_dbgstr_w(str), wine_dbgstr_w(trim)); 803 804 if (!str || !*str) 805 return FALSE; 806 807 while (*ptr && StrChrW(trim, *ptr)) 808 ptr++; 809 810 len = lstrlenW(ptr); 811 812 if (ptr != str) 813 { 814 memmove(str, ptr, (len + 1) * sizeof(WCHAR)); 815 ret = TRUE; 816 } 817 818 if (len > 0) 819 { 820 ptr = str + len; 821 while (StrChrW(trim, ptr[-1])) 822 ptr--; /* Skip trailing matches */ 823 824 if (ptr != str + len) 825 { 826 *ptr = '\0'; 827 ret = TRUE; 828 } 829 } 830 831 return ret; 832} 833 834BOOL WINAPI StrToInt64ExA(const char *str, DWORD flags, LONGLONG *ret) 835{ 836 BOOL negative = FALSE; 837 LONGLONG value = 0; 838 839 TRACE("%s, %#lx, %p\n", wine_dbgstr_a(str), flags, ret); 840 841 if (!str || !ret) 842 return FALSE; 843 844 if (flags > STIF_SUPPORT_HEX) 845 WARN("Unknown flags %#lx\n", flags); 846 847 /* Skip leading space, '+', '-' */ 848 while (*str == ' ' || *str == '\t' || *str == '\n') str++; 849 850 if (*str == '-') 851 { 852 negative = TRUE; 853 str++; 854 } 855 else if (*str == '+') 856 str++; 857 858 if (flags & STIF_SUPPORT_HEX && *str == '0' && (str[1] == 'x' || str[1] == 'X')) 859 { 860 /* Read hex number */ 861 str += 2; 862 863 if (!isxdigit(*str)) 864 return FALSE; 865 866 while (isxdigit(*str)) 867 { 868 value *= 16; 869 if (*str >= '0' && *str <= '9') 870 value += (*str - '0'); 871 else if (*str >= 'A' && *str <= 'F') 872 value += 10 + *str - 'A'; 873 else 874 value += 10 + *str - 'a'; 875 str++; 876 } 877 878 *ret = value; 879 return TRUE; 880 } 881 882 /* Read decimal number */ 883 if (*str < '0' || *str > '9') 884 return FALSE; 885 886 while (*str >= '0' && *str <= '9') 887 { 888 value *= 10; 889 value += (*str - '0'); 890 str++; 891 } 892 893 *ret = negative ? -value : value; 894 return TRUE; 895} 896 897BOOL WINAPI StrToInt64ExW(const WCHAR *str, DWORD flags, LONGLONG *ret) 898{ 899 BOOL negative = FALSE; 900 LONGLONG value = 0; 901 902 TRACE("%s, %#lx, %p\n", wine_dbgstr_w(str), flags, ret); 903 904 if (!str || !ret) 905 return FALSE; 906 907 if (flags > STIF_SUPPORT_HEX) 908 WARN("Unknown flags %#lx.\n", flags); 909 910 /* Skip leading space, '+', '-' */ 911 while (*str == ' ' || *str == '\t' || *str == '\n') str++; 912 913 if (*str == '-') 914 { 915 negative = TRUE; 916 str++; 917 } 918 else if (*str == '+') 919 str++; 920 921 if (flags & STIF_SUPPORT_HEX && *str == '0' && (str[1] == 'x' || str[1] == 'X')) 922 { 923 /* Read hex number */ 924 str += 2; 925 926 if (!isxdigit(*str)) 927 return FALSE; 928 929 while (isxdigit(*str)) 930 { 931 value *= 16; 932 if (*str >= '0' && *str <= '9') 933 value += (*str - '0'); 934 else if (*str >= 'A' && *str <= 'Z') 935 value += 10 + (*str - 'A'); 936 else 937 value += 10 + (*str - 'a'); 938 str++; 939 } 940 941 *ret = value; 942 return TRUE; 943 } 944 945 /* Read decimal number */ 946 if (*str < '0' || *str > '9') 947 return FALSE; 948 949 while (*str >= '0' && *str <= '9') 950 { 951 value *= 10; 952 value += (*str - '0'); 953 str++; 954 } 955 956 *ret = negative ? -value : value; 957 return TRUE; 958} 959 960BOOL WINAPI StrToIntExA(const char *str, DWORD flags, INT *ret) 961{ 962 LONGLONG value; 963 BOOL res; 964 965 TRACE("%s, %#lx, %p\n", wine_dbgstr_a(str), flags, ret); 966 967 res = StrToInt64ExA(str, flags, &value); 968 if (res) *ret = value; 969 return res; 970} 971 972BOOL WINAPI StrToIntExW(const WCHAR *str, DWORD flags, INT *ret) 973{ 974 LONGLONG value; 975 BOOL res; 976 977 TRACE("%s, %#lx, %p\n", wine_dbgstr_w(str), flags, ret); 978 979 res = StrToInt64ExW(str, flags, &value); 980 if (res) *ret = value; 981 return res; 982} 983 984int WINAPI StrToIntA(const char *str) 985{ 986 int value = 0; 987 988 TRACE("%s\n", wine_dbgstr_a(str)); 989 990 if (!str) 991 return 0; 992 993 if (*str == '-' || (*str >= '0' && *str <= '9')) 994 StrToIntExA(str, 0, &value); 995 996 return value; 997} 998 999int WINAPI StrToIntW(const WCHAR *str) 1000{ 1001 int value = 0; 1002 1003 TRACE("%s\n", wine_dbgstr_w(str)); 1004 1005 if (!str) 1006 return 0; 1007 1008 if (*str == '-' || (*str >= '0' && *str <= '9')) 1009 StrToIntExW(str, 0, &value); 1010 return value; 1011} 1012 1013char * WINAPI StrCpyNXA(char *dst, const char *src, int len) 1014{ 1015 TRACE("%p, %s, %i\n", dst, wine_dbgstr_a(src), len); 1016 1017 if (dst && src && len > 0) 1018 { 1019 while ((len-- > 1) && *src) 1020 *dst++ = *src++; 1021 if (len >= 0) 1022 *dst = '\0'; 1023 } 1024 1025 return dst; 1026} 1027 1028WCHAR * WINAPI StrCpyNXW(WCHAR *dst, const WCHAR *src, int len) 1029{ 1030 TRACE("%p, %s, %i\n", dst, wine_dbgstr_w(src), len); 1031 1032 if (dst && src && len > 0) 1033 { 1034 while ((len-- > 1) && *src) 1035 *dst++ = *src++; 1036 if (len >= 0) 1037 *dst = '\0'; 1038 } 1039 1040 return dst; 1041} 1042 1043LPSTR WINAPI CharLowerA(char *str) 1044{ 1045 if (IS_INTRESOURCE(str)) 1046 { 1047 char ch = LOWORD(str); 1048 CharLowerBuffA( &ch, 1 ); 1049 return (LPSTR)(UINT_PTR)(BYTE)ch; 1050 } 1051 1052 __TRY 1053 { 1054 CharLowerBuffA( str, strlen(str) ); 1055 } 1056 __EXCEPT_PAGE_FAULT 1057 { 1058 SetLastError( ERROR_INVALID_PARAMETER ); 1059 return NULL; 1060 } 1061 __ENDTRY 1062 return str; 1063} 1064 1065DWORD WINAPI CharLowerBuffA(char *str, DWORD len) 1066{ 1067 DWORD lenW; 1068 WCHAR buffer[32]; 1069 WCHAR *strW = buffer; 1070 1071 if (!str) return 0; /* YES */ 1072 1073 lenW = MultiByteToWideChar(CP_ACP, 0, str, len, NULL, 0); 1074 if (lenW > ARRAY_SIZE(buffer)) 1075 { 1076 strW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR)); 1077 if (!strW) return 0; 1078 } 1079 MultiByteToWideChar(CP_ACP, 0, str, len, strW, lenW); 1080 CharLowerBuffW(strW, lenW); 1081 len = WideCharToMultiByte(CP_ACP, 0, strW, lenW, str, len, NULL, NULL); 1082 if (strW != buffer) HeapFree(GetProcessHeap(), 0, strW); 1083 return len; 1084} 1085 1086DWORD WINAPI CharLowerBuffW(WCHAR *str, DWORD len) 1087{ 1088 if (!str) return 0; /* YES */ 1089 return LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, str, len, str, len); 1090} 1091 1092LPWSTR WINAPI CharLowerW(WCHAR *str) 1093{ 1094 if (!IS_INTRESOURCE(str)) 1095 { 1096 CharLowerBuffW(str, lstrlenW(str)); 1097 return str; 1098 } 1099 else 1100 { 1101 WCHAR ch = LOWORD(str); 1102 CharLowerBuffW(&ch, 1); 1103 return (LPWSTR)(UINT_PTR)ch; 1104 } 1105} 1106 1107LPSTR WINAPI CharNextA(const char *ptr) 1108{ 1109 if (!*ptr) return (LPSTR)ptr; 1110 if (IsDBCSLeadByte( ptr[0] ) && ptr[1]) return (LPSTR)(ptr + 2); 1111 return (LPSTR)(ptr + 1); 1112} 1113 1114LPSTR WINAPI CharNextExA(WORD codepage, const char *ptr, DWORD flags) 1115{ 1116 if (!*ptr) return (LPSTR)ptr; 1117 if (IsDBCSLeadByteEx( codepage, ptr[0] ) && ptr[1]) return (LPSTR)(ptr + 2); 1118 return (LPSTR)(ptr + 1); 1119} 1120 1121LPWSTR WINAPI CharNextW(const WCHAR *x) 1122{ 1123 if (*x) x++; 1124 1125 return (WCHAR *)x; 1126} 1127 1128LPSTR WINAPI CharPrevA(const char *start, const char *ptr) 1129{ 1130 while (*start && (start < ptr)) 1131 { 1132 LPCSTR next = CharNextA(start); 1133 if (next >= ptr) break; 1134 start = next; 1135 } 1136 return (LPSTR)start; 1137} 1138 1139LPSTR WINAPI CharPrevExA(WORD codepage, const char *start, const char *ptr, DWORD flags) 1140{ 1141 while (*start && (start < ptr)) 1142 { 1143 LPCSTR next = CharNextExA(codepage, start, flags); 1144 if (next >= ptr) break; 1145 start = next; 1146 } 1147 return (LPSTR)start; 1148} 1149 1150LPWSTR WINAPI CharPrevW(const WCHAR *start, const WCHAR *x) 1151{ 1152 if (x > start) return (LPWSTR)(x - 1); 1153 else return (LPWSTR)x; 1154} 1155 1156LPSTR WINAPI CharUpperA(LPSTR str) 1157{ 1158 if (IS_INTRESOURCE(str)) 1159 { 1160 char ch = LOWORD(str); 1161 CharUpperBuffA(&ch, 1); 1162 return (LPSTR)(UINT_PTR)(BYTE)ch; 1163 } 1164 1165 __TRY 1166 { 1167 CharUpperBuffA(str, strlen(str)); 1168 } 1169 __EXCEPT_PAGE_FAULT 1170 { 1171 SetLastError(ERROR_INVALID_PARAMETER); 1172 return NULL; 1173 } 1174 __ENDTRY 1175 return str; 1176} 1177 1178DWORD WINAPI CharUpperBuffA(LPSTR str, DWORD len) 1179{ 1180 DWORD lenW; 1181 WCHAR buffer[32]; 1182 WCHAR *strW = buffer; 1183 1184 if (!str) return 0; /* YES */ 1185 1186 lenW = MultiByteToWideChar(CP_ACP, 0, str, len, NULL, 0); 1187 if (lenW > ARRAY_SIZE(buffer)) 1188 { 1189 strW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR)); 1190 if (!strW) return 0; 1191 } 1192 MultiByteToWideChar(CP_ACP, 0, str, len, strW, lenW); 1193 CharUpperBuffW(strW, lenW); 1194 len = WideCharToMultiByte(CP_ACP, 0, strW, lenW, str, len, NULL, NULL); 1195 if (strW != buffer) HeapFree(GetProcessHeap(), 0, strW); 1196 return len; 1197} 1198 1199DWORD WINAPI CharUpperBuffW(WCHAR *str, DWORD len) 1200{ 1201 if (!str) return 0; /* YES */ 1202 return LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE, str, len, str, len); 1203} 1204 1205LPWSTR WINAPI CharUpperW(WCHAR *str) 1206{ 1207 if (!IS_INTRESOURCE(str)) 1208 { 1209 CharUpperBuffW(str, lstrlenW(str)); 1210 return str; 1211 } 1212 else 1213 { 1214 WCHAR ch = LOWORD(str); 1215 CharUpperBuffW(&ch, 1); 1216 return (LPWSTR)(UINT_PTR)ch; 1217 } 1218} 1219 1220INT WINAPI DECLSPEC_HOTPATCH LoadStringW(HINSTANCE instance, UINT resource_id, LPWSTR buffer, INT buflen) 1221{ 1222 int string_num, i; 1223 HGLOBAL hmem; 1224 HRSRC hrsrc; 1225 WCHAR *p; 1226 1227 TRACE("instance = %p, id = %04x, buffer = %p, length = %d\n", instance, resource_id, buffer, buflen); 1228 1229 if (!buffer) 1230 return 0; 1231 1232 if (!(hrsrc = FindResourceW(instance, MAKEINTRESOURCEW((LOWORD(resource_id) >> 4) + 1), (LPWSTR)RT_STRING)) || 1233 !(hmem = LoadResource(instance, hrsrc))) 1234 { 1235 TRACE( "Failed to load string.\n" ); 1236 if (buflen > 0) buffer[0] = 0; 1237 return 0; 1238 } 1239 1240 p = LockResource(hmem); 1241 string_num = resource_id & 0x000f; 1242 for (i = 0; i < string_num; i++) 1243 p += *p + 1; 1244 1245 TRACE("strlen = %d\n", (int)*p ); 1246 1247 /*if buflen == 0, then return a read-only pointer to the resource itself in buffer 1248 it is assumed that buffer is actually a (LPWSTR *) */ 1249 if (buflen == 0) 1250 { 1251 *((LPWSTR *)buffer) = p + 1; 1252 return *p; 1253 } 1254 1255 i = min(buflen - 1, *p); 1256 memcpy(buffer, p + 1, i * sizeof(WCHAR)); 1257 buffer[i] = 0; 1258 1259 TRACE("returning %s\n", debugstr_w(buffer)); 1260 return i; 1261} 1262 1263INT WINAPI DECLSPEC_HOTPATCH LoadStringA(HINSTANCE instance, UINT resource_id, LPSTR buffer, INT buflen) 1264{ 1265 DWORD retval = 0; 1266 HGLOBAL hmem; 1267 HRSRC hrsrc; 1268 1269 TRACE("instance = %p, id = %04x, buffer = %p, length = %d\n", instance, resource_id, buffer, buflen); 1270 1271 if (!buflen) return -1; 1272 1273 /* Use loword (incremented by 1) as resourceid */ 1274 if ((hrsrc = FindResourceW(instance, MAKEINTRESOURCEW((LOWORD(resource_id) >> 4) + 1), (LPWSTR)RT_STRING )) && 1275 (hmem = LoadResource(instance, hrsrc))) 1276 { 1277 const WCHAR *p = LockResource(hmem); 1278 unsigned int id = resource_id & 0x000f; 1279 1280 while (id--) p += *p + 1; 1281 1282 RtlUnicodeToMultiByteN(buffer, buflen - 1, &retval, p + 1, *p * sizeof(WCHAR)); 1283 } 1284 buffer[retval] = 0; 1285 TRACE("returning %s\n", debugstr_a(buffer)); 1286 return retval; 1287} 1288 1289int WINAPI StrCmpLogicalW(const WCHAR *str, const WCHAR *comp) 1290{ 1291 TRACE("%s, %s\n", wine_dbgstr_w(str), wine_dbgstr_w(comp)); 1292 1293 if (!str || !comp) 1294 return 0; 1295 1296 while (*str) 1297 { 1298 if (!*comp) 1299 return 1; 1300 else if (*str >= '0' && *str <= '9') 1301 { 1302 int str_value, comp_value; 1303 1304 if (*comp < '0' || *comp > '9') 1305 return -1; 1306 1307 /* Compare the numbers */ 1308 StrToIntExW(str, 0, &str_value); 1309 StrToIntExW(comp, 0, &comp_value); 1310 1311 if (str_value < comp_value) 1312 return -1; 1313 else if (str_value > comp_value) 1314 return 1; 1315 1316 /* Skip */ 1317 while (*str >= '0' && *str <= '9') str++; 1318 while (*comp >= '0' && *comp <= '9') comp++; 1319 } 1320 else if (*comp >= '0' && *comp <= '9') 1321 return 1; 1322 else 1323 { 1324 int diff = ChrCmpIW(*str, *comp); 1325 if (diff > 0) 1326 return 1; 1327 else if (diff < 0) 1328 return -1; 1329 1330 str++; 1331 comp++; 1332 } 1333 } 1334 1335 if (*comp) 1336 return -1; 1337 1338 return 0; 1339} 1340 1341BOOL WINAPI StrIsIntlEqualA(BOOL case_sensitive, const char *str, const char *cmp, int len) 1342{ 1343 DWORD flags; 1344 1345 TRACE("%d, %s, %s, %d\n", case_sensitive, wine_dbgstr_a(str), wine_dbgstr_a(cmp), len); 1346 1347 /* FIXME: This flag is undocumented and unknown by our CompareString. 1348 * We need a define for it. 1349 */ 1350 flags = 0x10000000; 1351 if (!case_sensitive) 1352 flags |= NORM_IGNORECASE; 1353 1354 return (CompareStringA(GetThreadLocale(), flags, str, len, cmp, len) == CSTR_EQUAL); 1355} 1356 1357BOOL WINAPI StrIsIntlEqualW(BOOL case_sensitive, const WCHAR *str, const WCHAR *cmp, int len) 1358{ 1359 DWORD flags; 1360 1361 TRACE("%d, %s, %s, %d\n", case_sensitive, debugstr_w(str), debugstr_w(cmp), len); 1362 1363 /* FIXME: This flag is undocumented and unknown by our CompareString. 1364 * We need a define for it. 1365 */ 1366 flags = 0x10000000; 1367 if (!case_sensitive) 1368 flags |= NORM_IGNORECASE; 1369 1370 return (CompareStringW(GetThreadLocale(), flags, str, len, cmp, len) == CSTR_EQUAL); 1371} 1372 1373char * WINAPI StrCatBuffA(char *str, const char *cat, INT max_len) 1374{ 1375 INT len; 1376 1377 TRACE("%p, %s, %d\n", str, wine_dbgstr_a(cat), max_len); 1378 1379 if (!str) 1380 return NULL; 1381 1382 len = strlen(str); 1383 max_len -= len; 1384 if (max_len > 0) 1385 StrCpyNA(str + len, cat, max_len); 1386 1387 return str; 1388} 1389 1390WCHAR * WINAPI StrCatBuffW(WCHAR *str, const WCHAR *cat, INT max_len) 1391{ 1392 INT len; 1393 1394 TRACE("%p, %s, %d\n", str, wine_dbgstr_w(cat), max_len); 1395 1396 if (!str) 1397 return NULL; 1398 1399 len = lstrlenW(str); 1400 max_len -= len; 1401 if (max_len > 0) 1402 StrCpyNW(str + len, cat, max_len); 1403 1404 return str; 1405} 1406 1407DWORD WINAPI StrCatChainW(WCHAR *str, DWORD max_len, DWORD at, const WCHAR *cat) 1408{ 1409 TRACE("%s, %lu, %ld, %s\n", wine_dbgstr_w(str), max_len, at, wine_dbgstr_w(cat)); 1410 1411 if (at == -1) 1412 at = lstrlenW(str); 1413 1414 if (!max_len) 1415 return at; 1416 1417 if (at == max_len) 1418 at--; 1419 1420 if (cat && at < max_len) 1421 { 1422 str += at; 1423 while (at < max_len - 1 && *cat) 1424 { 1425 *str++ = *cat++; 1426 at++; 1427 } 1428 *str = 0; 1429 } 1430 1431 return at; 1432} 1433 1434DWORD WINAPI SHTruncateString(char *str, DWORD size) 1435{ 1436 char *last_byte; 1437 1438 if (!str || !size) 1439 return 0; 1440 1441 last_byte = str + size - 1; 1442 1443 while (str < last_byte) 1444 str += IsDBCSLeadByte(*str) ? 2 : 1; 1445 1446 if (str == last_byte && IsDBCSLeadByte(*str)) 1447 { 1448 *str = '\0'; 1449 size--; 1450 } 1451 1452 return size; 1453} 1454 1455HRESULT WINAPI SHLoadIndirectString(const WCHAR *src, WCHAR *dst, UINT dst_len, void **reserved) 1456{ 1457 WCHAR *dllname = NULL; 1458 HMODULE hmod = NULL; 1459 HRESULT hr = E_FAIL; 1460 1461 TRACE("%s, %p, %#x, %p\n", debugstr_w(src), dst, dst_len, reserved); 1462 1463 if (src[0] == '@') 1464 { 1465 WCHAR *index_str; 1466 int index; 1467 1468 dst[0] = 0; 1469 dllname = StrDupW(src + 1); 1470 index_str = wcschr(dllname, ','); 1471 1472 if(!index_str) goto end; 1473 1474 *index_str = 0; 1475 index_str++; 1476 index = wcstol(index_str, NULL, 10); 1477 1478 hmod = LoadLibraryW(dllname); 1479 if (!hmod) goto end; 1480 1481 if (index < 0) 1482 { 1483 if (LoadStringW(hmod, -index, dst, dst_len)) 1484 hr = S_OK; 1485 } 1486 else 1487 FIXME("can't handle non-negative indices (%d)\n", index); 1488 } 1489 else 1490 { 1491 if (dst != src) 1492 lstrcpynW(dst, src, dst_len); 1493 hr = S_OK; 1494 } 1495 1496 TRACE("returning %s\n", debugstr_w(dst)); 1497end: 1498 if (hmod) FreeLibrary(hmod); 1499 LocalFree(dllname); 1500 return hr; 1501}