1 /* 2 * Shlwapi string functions 3 * 4 * Copyright 1998 Juergen Schmied 5 * Copyright 2002 Jon Griffiths 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 */ 21 22 #include "config.h" 23 #include "wine/port.h" 24 25 #include <math.h> 26 #include <stdarg.h> 27 #include <stdio.h> 28 #include <string.h> 29 30 #define NONAMELESSUNION 31 32 #include "windef.h" 33 #include "winbase.h" 34 #define NO_SHLWAPI_REG 35 #define NO_SHLWAPI_STREAM 36 #include "shlwapi.h" 37 #include "wingdi.h" 38 #include "winuser.h" 39 #include "shlobj.h" 40 #include "mlang.h" 41 #include "ddeml.h" 42 #include "wine/unicode.h" 43 #include "wine/debug.h" 44 45 #include "resource.h" 46 47 WINE_DEFAULT_DEBUG_CHANNEL(shell); 48 49 extern HINSTANCE shlwapi_hInstance; 50 51 static HRESULT _SHStrDupAA(LPCSTR,LPSTR*); 52 static HRESULT _SHStrDupAW(LPCWSTR,LPSTR*); 53 54 55 static void FillNumberFmt(NUMBERFMTW *fmt, LPWSTR decimal_buffer, int decimal_bufwlen, 56 LPWSTR thousand_buffer, int thousand_bufwlen) 57 { 58 WCHAR grouping[64]; 59 WCHAR *c; 60 61 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_ILZERO|LOCALE_RETURN_NUMBER, (LPWSTR)&fmt->LeadingZero, sizeof(fmt->LeadingZero)/sizeof(WCHAR)); 62 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_INEGNUMBER|LOCALE_RETURN_NUMBER, (LPWSTR)&fmt->LeadingZero, sizeof(fmt->NegativeOrder)/sizeof(WCHAR)); 63 fmt->NumDigits = 0; 64 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, decimal_buffer, decimal_bufwlen); 65 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, thousand_buffer, thousand_bufwlen); 66 fmt->lpThousandSep = thousand_buffer; 67 fmt->lpDecimalSep = decimal_buffer; 68 69 /* 70 * Converting grouping string to number as described on 71 * http://blogs.msdn.com/oldnewthing/archive/2006/04/18/578251.aspx 72 */ 73 fmt->Grouping = 0; 74 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, grouping, sizeof(grouping)/sizeof(WCHAR)); 75 for (c = grouping; *c; c++) 76 if (*c >= '0' && *c < '9') 77 { 78 fmt->Grouping *= 10; 79 fmt->Grouping += *c - '0'; 80 } 81 82 if (fmt->Grouping % 10 == 0) 83 fmt->Grouping /= 10; 84 else 85 fmt->Grouping *= 10; 86 } 87 88 /************************************************************************* 89 * FormatInt [internal] 90 * 91 * Format an integer according to the current locale 92 * 93 * RETURNS 94 * The number of characters written on success or 0 on failure 95 */ 96 static int FormatInt(LONGLONG qdwValue, LPWSTR pszBuf, int cchBuf) 97 { 98 NUMBERFMTW fmt; 99 WCHAR decimal[8], thousand[8]; 100 WCHAR buf[24]; 101 WCHAR *c; 102 BOOL neg = (qdwValue < 0); 103 104 FillNumberFmt(&fmt, decimal, sizeof decimal / sizeof (WCHAR), 105 thousand, sizeof thousand / sizeof (WCHAR)); 106 107 c = &buf[24]; 108 *(--c) = 0; 109 do 110 { 111 *(--c) = '0' + (qdwValue%10); 112 qdwValue /= 10; 113 } while (qdwValue > 0); 114 if (neg) 115 *(--c) = '-'; 116 117 return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, c, &fmt, pszBuf, cchBuf); 118 } 119 120 /************************************************************************* 121 * FormatDouble [internal] 122 * 123 * Format an integer according to the current locale. Prints the specified number of digits 124 * after the decimal point 125 * 126 * RETURNS 127 * The number of characters written on success or 0 on failure 128 */ 129 static int FormatDouble(double value, int decimals, LPWSTR pszBuf, int cchBuf) 130 { 131 static const WCHAR flfmt[] = {'%','f',0}; 132 WCHAR buf[64]; 133 NUMBERFMTW fmt; 134 WCHAR decimal[8], thousand[8]; 135 136 snprintfW(buf, 64, flfmt, value); 137 138 FillNumberFmt(&fmt, decimal, sizeof decimal / sizeof (WCHAR), 139 thousand, sizeof thousand / sizeof (WCHAR)); 140 fmt.NumDigits = decimals; 141 return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, buf, &fmt, pszBuf, cchBuf); 142 } 143 144 /************************************************************************* 145 * SHLWAPI_ChrCmpHelperA 146 * 147 * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA. 148 * 149 * NOTES 150 * Both this function and its Unicode counterpart are very inefficient. To 151 * fix this, CompareString must be completely implemented and optimised 152 * first. Then the core character test can be taken out of that function and 153 * placed here, so that it need never be called at all. Until then, do not 154 * attempt to optimise this code unless you are willing to test that it 155 * still performs correctly. 156 */ 157 static BOOL SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags) 158 { 159 char str1[3], str2[3]; 160 161 str1[0] = LOBYTE(ch1); 162 if (IsDBCSLeadByte(str1[0])) 163 { 164 str1[1] = HIBYTE(ch1); 165 str1[2] = '\0'; 166 } 167 else 168 str1[1] = '\0'; 169 170 str2[0] = LOBYTE(ch2); 171 if (IsDBCSLeadByte(str2[0])) 172 { 173 str2[1] = HIBYTE(ch2); 174 str2[2] = '\0'; 175 } 176 else 177 str2[1] = '\0'; 178 179 return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - CSTR_EQUAL; 180 } 181 182 /************************************************************************* 183 * SHLWAPI_ChrCmpA 184 * 185 * Internal helper function. 186 */ 187 static BOOL WINAPI SHLWAPI_ChrCmpA(WORD ch1, WORD ch2) 188 { 189 return SHLWAPI_ChrCmpHelperA(ch1, ch2, 0); 190 } 191 192 /************************************************************************* 193 * ChrCmpIA (SHLWAPI.385) 194 * 195 * Compare two characters, ignoring case. 196 * 197 * PARAMS 198 * ch1 [I] First character to compare 199 * ch2 [I] Second character to compare 200 * 201 * RETURNS 202 * FALSE, if the characters are equal. 203 * Non-zero otherwise. 204 */ 205 BOOL WINAPI ChrCmpIA(WORD ch1, WORD ch2) 206 { 207 TRACE("(%d,%d)\n", ch1, ch2); 208 209 return SHLWAPI_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE); 210 } 211 212 /************************************************************************* 213 * ChrCmpIW [SHLWAPI.386] 214 * 215 * See ChrCmpIA. 216 */ 217 BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2) 218 { 219 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE, &ch1, 1, &ch2, 1) - CSTR_EQUAL; 220 } 221 222 /************************************************************************* 223 * StrChrA [SHLWAPI.@] 224 * 225 * Find a given character in a string. 226 * 227 * PARAMS 228 * lpszStr [I] String to search in. 229 * ch [I] Character to search for. 230 * 231 * RETURNS 232 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if 233 * not found. 234 * Failure: NULL, if any arguments are invalid. 235 */ 236 LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch) 237 { 238 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch); 239 240 if (lpszStr) 241 { 242 while (*lpszStr) 243 { 244 if (!SHLWAPI_ChrCmpA(*lpszStr, ch)) 245 return (LPSTR)lpszStr; 246 lpszStr = CharNextA(lpszStr); 247 } 248 } 249 return NULL; 250 } 251 252 /************************************************************************* 253 * StrChrW [SHLWAPI.@] 254 * 255 * See StrChrA. 256 */ 257 LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch) 258 { 259 LPWSTR lpszRet = NULL; 260 261 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch); 262 263 if (lpszStr) 264 lpszRet = strchrW(lpszStr, ch); 265 return lpszRet; 266 } 267 268 /************************************************************************* 269 * StrChrIA [SHLWAPI.@] 270 * 271 * Find a given character in a string, ignoring case. 272 * 273 * PARAMS 274 * lpszStr [I] String to search in. 275 * ch [I] Character to search for. 276 * 277 * RETURNS 278 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if 279 * not found. 280 * Failure: NULL, if any arguments are invalid. 281 */ 282 LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch) 283 { 284 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch); 285 286 if (lpszStr) 287 { 288 while (*lpszStr) 289 { 290 if (!ChrCmpIA(*lpszStr, ch)) 291 return (LPSTR)lpszStr; 292 lpszStr = CharNextA(lpszStr); 293 } 294 } 295 return NULL; 296 } 297 298 /************************************************************************* 299 * StrChrIW [SHLWAPI.@] 300 * 301 * See StrChrA. 302 */ 303 LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch) 304 { 305 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch); 306 307 if (lpszStr) 308 { 309 ch = toupperW(ch); 310 while (*lpszStr) 311 { 312 if (toupperW(*lpszStr) == ch) 313 return (LPWSTR)lpszStr; 314 lpszStr++; 315 } 316 lpszStr = NULL; 317 } 318 return (LPWSTR)lpszStr; 319 } 320 321 /************************************************************************* 322 * StrChrNW [SHLWAPI.@] 323 */ 324 LPWSTR WINAPI StrChrNW(LPCWSTR lpszStr, WCHAR ch, UINT cchMax) 325 { 326 TRACE("(%s(%i),%i)\n", debugstr_wn(lpszStr,cchMax), cchMax, ch); 327 328 if (lpszStr) 329 { 330 while (*lpszStr && cchMax-- > 0) 331 { 332 if (*lpszStr == ch) 333 return (LPWSTR)lpszStr; 334 lpszStr++; 335 } 336 } 337 return NULL; 338 } 339 340 /************************************************************************* 341 * StrCmpIW [SHLWAPI.@] 342 * 343 * Compare two strings, ignoring case. 344 * 345 * PARAMS 346 * lpszStr [I] First string to compare 347 * lpszComp [I] Second string to compare 348 * 349 * RETURNS 350 * An integer less than, equal to or greater than 0, indicating that 351 * lpszStr is less than, the same, or greater than lpszComp. 352 */ 353 int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp) 354 { 355 TRACE("(%s,%s)\n", debugstr_w(lpszStr),debugstr_w(lpszComp)); 356 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, -1, lpszComp, -1) - CSTR_EQUAL; 357 } 358 359 /************************************************************************* 360 * StrCmpNA [SHLWAPI.@] 361 * 362 * Compare two strings, up to a maximum length. 363 * 364 * PARAMS 365 * lpszStr [I] First string to compare 366 * lpszComp [I] Second string to compare 367 * iLen [I] Number of chars to compare 368 * 369 * RETURNS 370 * An integer less than, equal to or greater than 0, indicating that 371 * lpszStr is less than, the same, or greater than lpszComp. 372 */ 373 INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen) 374 { 375 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen); 376 return CompareStringA(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen) - CSTR_EQUAL; 377 } 378 379 /************************************************************************* 380 * StrCmpNW [SHLWAPI.@] 381 * 382 * See StrCmpNA. 383 */ 384 INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen) 385 { 386 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen); 387 return CompareStringW(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen) - CSTR_EQUAL; 388 } 389 390 /************************************************************************* 391 * StrCmpNIA [SHLWAPI.@] 392 * 393 * Compare two strings, up to a maximum length, ignoring case. 394 * 395 * PARAMS 396 * lpszStr [I] First string to compare 397 * lpszComp [I] Second string to compare 398 * iLen [I] Number of chars to compare 399 * 400 * RETURNS 401 * An integer less than, equal to or greater than 0, indicating that 402 * lpszStr is less than, the same, or greater than lpszComp. 403 */ 404 int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen) 405 { 406 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen); 407 return CompareStringA(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen) - CSTR_EQUAL; 408 } 409 410 /************************************************************************* 411 * StrCmpNIW [SHLWAPI.@] 412 * 413 * See StrCmpNIA. 414 */ 415 INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen) 416 { 417 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen); 418 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen) - CSTR_EQUAL; 419 } 420 421 /************************************************************************* 422 * StrCmpW [SHLWAPI.@] 423 * 424 * Compare two strings. 425 * 426 * PARAMS 427 * lpszStr [I] First string to compare 428 * lpszComp [I] Second string to compare 429 * 430 * RETURNS 431 * An integer less than, equal to or greater than 0, indicating that 432 * lpszStr is less than, the same, or greater than lpszComp. 433 */ 434 int WINAPI StrCmpW(LPCWSTR lpszStr, LPCWSTR lpszComp) 435 { 436 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp)); 437 return CompareStringW(GetThreadLocale(), 0, lpszStr, -1, lpszComp, -1) - CSTR_EQUAL; 438 } 439 440 /************************************************************************* 441 * StrCatW [SHLWAPI.@] 442 * 443 * Concatenate two strings. 444 * 445 * PARAMS 446 * lpszStr [O] Initial string 447 * lpszSrc [I] String to concatenate 448 * 449 * RETURNS 450 * lpszStr. 451 */ 452 LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc) 453 { 454 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSrc)); 455 456 if (lpszStr && lpszSrc) 457 strcatW(lpszStr, lpszSrc); 458 return lpszStr; 459 } 460 461 /************************************************************************* 462 * StrCatChainW [SHLWAPI.@] 463 * 464 * Concatenates two unicode strings. 465 * 466 * PARAMS 467 * lpszStr [O] Initial string 468 * cchMax [I] Length of destination buffer 469 * ichAt [I] Offset from the destination buffer to begin concatenation 470 * lpszCat [I] String to concatenate 471 * 472 * RETURNS 473 * The offset from the beginning of pszDst to the terminating NULL. 474 */ 475 DWORD WINAPI StrCatChainW(LPWSTR lpszStr, DWORD cchMax, DWORD ichAt, LPCWSTR lpszCat) 476 { 477 TRACE("(%s,%u,%d,%s)\n", debugstr_w(lpszStr), cchMax, ichAt, debugstr_w(lpszCat)); 478 479 if (ichAt == -1) 480 ichAt = strlenW(lpszStr); 481 482 if (!cchMax) 483 return ichAt; 484 485 if (ichAt == cchMax) 486 ichAt--; 487 488 if (lpszCat && ichAt < cchMax) 489 { 490 lpszStr += ichAt; 491 while (ichAt < cchMax - 1 && *lpszCat) 492 { 493 *lpszStr++ = *lpszCat++; 494 ichAt++; 495 } 496 *lpszStr = 0; 497 } 498 499 return ichAt; 500 } 501 502 /************************************************************************* 503 * StrCpyW [SHLWAPI.@] 504 * 505 * Copy a string to another string. 506 * 507 * PARAMS 508 * lpszStr [O] Destination string 509 * lpszSrc [I] Source string 510 * 511 * RETURNS 512 * lpszStr. 513 */ 514 LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc) 515 { 516 TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc)); 517 518 if (lpszStr && lpszSrc) 519 strcpyW(lpszStr, lpszSrc); 520 return lpszStr; 521 } 522 523 /************************************************************************* 524 * StrCpyNW [SHLWAPI.@] 525 * 526 * Copy a string to another string, up to a maximum number of characters. 527 * 528 * PARAMS 529 * dst [O] Destination string 530 * src [I] Source string 531 * count [I] Maximum number of chars to copy 532 * 533 * RETURNS 534 * dst. 535 */ 536 LPWSTR WINAPI StrCpyNW(LPWSTR dst, LPCWSTR src, int count) 537 { 538 LPWSTR d = dst; 539 LPCWSTR s = src; 540 541 TRACE("(%p,%s,%i)\n", dst, debugstr_w(src), count); 542 543 if (s) 544 { 545 while ((count > 1) && *s) 546 { 547 count--; 548 *d++ = *s++; 549 } 550 } 551 if (count) *d = 0; 552 553 return dst; 554 } 555 556 /************************************************************************* 557 * SHLWAPI_StrStrHelperA 558 * 559 * Internal implementation of StrStrA/StrStrIA 560 */ 561 static LPSTR SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch, 562 INT (WINAPI *pStrCmpFn)(LPCSTR,LPCSTR,INT)) 563 { 564 size_t iLen; 565 LPCSTR end; 566 567 if (!lpszStr || !lpszSearch || !*lpszSearch) 568 return NULL; 569 570 iLen = strlen(lpszSearch); 571 end = lpszStr + strlen(lpszStr); 572 573 while (lpszStr + iLen <= end) 574 { 575 if (!pStrCmpFn(lpszStr, lpszSearch, iLen)) 576 return (LPSTR)lpszStr; 577 lpszStr = CharNextA(lpszStr); 578 } 579 return NULL; 580 } 581 582 /************************************************************************* 583 * StrStrA [SHLWAPI.@] 584 * 585 * Find a substring within a string. 586 * 587 * PARAMS 588 * lpszStr [I] String to search in 589 * lpszSearch [I] String to look for 590 * 591 * RETURNS 592 * The start of lpszSearch within lpszStr, or NULL if not found. 593 */ 594 LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch) 595 { 596 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch)); 597 598 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, StrCmpNA); 599 } 600 601 /************************************************************************* 602 * StrStrW [SHLWAPI.@] 603 * 604 * See StrStrA. 605 */ 606 LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch) 607 { 608 TRACE("(%s, %s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch)); 609 610 if (!lpszStr || !lpszSearch || !*lpszSearch) return NULL; 611 return strstrW( lpszStr, lpszSearch ); 612 } 613 614 /************************************************************************* 615 * StrRStrIA [SHLWAPI.@] 616 * 617 * Find the last occurrence of a substring within a string. 618 * 619 * PARAMS 620 * lpszStr [I] String to search in 621 * lpszEnd [I] End of lpszStr 622 * lpszSearch [I] String to look for 623 * 624 * RETURNS 625 * The last occurrence lpszSearch within lpszStr, or NULL if not found. 626 */ 627 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch) 628 { 629 LPSTR lpszRet = NULL; 630 WORD ch1, ch2; 631 INT iLen; 632 633 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch)); 634 635 if (!lpszStr || !lpszSearch || !*lpszSearch) 636 return NULL; 637 638 if (IsDBCSLeadByte(*lpszSearch)) 639 ch1 = *lpszSearch << 8 | (UCHAR)lpszSearch[1]; 640 else 641 ch1 = *lpszSearch; 642 iLen = lstrlenA(lpszSearch); 643 644 if (!lpszEnd) 645 lpszEnd = lpszStr + lstrlenA(lpszStr); 646 else /* reproduce the broken behaviour on Windows */ 647 lpszEnd += min(iLen - 1, lstrlenA(lpszEnd)); 648 649 while (lpszStr + iLen <= lpszEnd && *lpszStr) 650 { 651 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | (UCHAR)lpszStr[1] : *lpszStr; 652 if (!ChrCmpIA(ch1, ch2)) 653 { 654 if (!StrCmpNIA(lpszStr, lpszSearch, iLen)) 655 lpszRet = (LPSTR)lpszStr; 656 } 657 lpszStr = CharNextA(lpszStr); 658 } 659 return lpszRet; 660 } 661 662 /************************************************************************* 663 * StrRStrIW [SHLWAPI.@] 664 * 665 * See StrRStrIA. 666 */ 667 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch) 668 { 669 LPWSTR lpszRet = NULL; 670 INT iLen; 671 672 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch)); 673 674 if (!lpszStr || !lpszSearch || !*lpszSearch) 675 return NULL; 676 677 iLen = strlenW(lpszSearch); 678 679 if (!lpszEnd) 680 lpszEnd = lpszStr + strlenW(lpszStr); 681 else /* reproduce the broken behaviour on Windows */ 682 lpszEnd += min(iLen - 1, lstrlenW(lpszEnd)); 683 684 while (lpszStr + iLen <= lpszEnd && *lpszStr) 685 { 686 if (!ChrCmpIW(*lpszSearch, *lpszStr)) 687 { 688 if (!StrCmpNIW(lpszStr, lpszSearch, iLen)) 689 lpszRet = (LPWSTR)lpszStr; 690 } 691 lpszStr++; 692 } 693 return lpszRet; 694 } 695 696 /************************************************************************* 697 * StrStrIA [SHLWAPI.@] 698 * 699 * Find a substring within a string, ignoring case. 700 * 701 * PARAMS 702 * lpszStr [I] String to search in 703 * lpszSearch [I] String to look for 704 * 705 * RETURNS 706 * The start of lpszSearch within lpszStr, or NULL if not found. 707 */ 708 LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch) 709 { 710 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch)); 711 712 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, StrCmpNIA); 713 } 714 715 /************************************************************************* 716 * StrStrIW [SHLWAPI.@] 717 * 718 * See StrStrIA. 719 */ 720 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch) 721 { 722 int iLen; 723 LPCWSTR end; 724 725 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch)); 726 727 if (!lpszStr || !lpszSearch || !*lpszSearch) 728 return NULL; 729 730 iLen = strlenW(lpszSearch); 731 end = lpszStr + strlenW(lpszStr); 732 733 while (lpszStr + iLen <= end) 734 { 735 if (!StrCmpNIW(lpszStr, lpszSearch, iLen)) 736 return (LPWSTR)lpszStr; 737 lpszStr++; 738 } 739 return NULL; 740 } 741 742 /************************************************************************* 743 * StrStrNW [SHLWAPI.@] 744 * 745 * Find a substring within a string up to a given number of initial characters. 746 * 747 * PARAMS 748 * lpFirst [I] String to search in 749 * lpSrch [I] String to look for 750 * cchMax [I] Maximum number of initial search characters 751 * 752 * RETURNS 753 * The start of lpFirst within lpSrch, or NULL if not found. 754 */ 755 LPWSTR WINAPI StrStrNW(LPCWSTR lpFirst, LPCWSTR lpSrch, UINT cchMax) 756 { 757 UINT i; 758 int len; 759 760 TRACE("(%s, %s, %u)\n", debugstr_w(lpFirst), debugstr_w(lpSrch), cchMax); 761 762 if (!lpFirst || !lpSrch || !*lpSrch || !cchMax) 763 return NULL; 764 765 len = strlenW(lpSrch); 766 767 for (i = cchMax; *lpFirst && (i > 0); i--, lpFirst++) 768 { 769 if (!strncmpW(lpFirst, lpSrch, len)) 770 return (LPWSTR)lpFirst; 771 } 772 773 return NULL; 774 } 775 776 /************************************************************************* 777 * StrStrNIW [SHLWAPI.@] 778 * 779 * Find a substring within a string up to a given number of initial characters, 780 * ignoring case. 781 * 782 * PARAMS 783 * lpFirst [I] String to search in 784 * lpSrch [I] String to look for 785 * cchMax [I] Maximum number of initial search characters 786 * 787 * RETURNS 788 * The start of lpFirst within lpSrch, or NULL if not found. 789 */ 790 LPWSTR WINAPI StrStrNIW(LPCWSTR lpFirst, LPCWSTR lpSrch, UINT cchMax) 791 { 792 UINT i; 793 int len; 794 795 TRACE("(%s, %s, %u)\n", debugstr_w(lpFirst), debugstr_w(lpSrch), cchMax); 796 797 if (!lpFirst || !lpSrch || !*lpSrch || !cchMax) 798 return NULL; 799 800 len = strlenW(lpSrch); 801 802 for (i = cchMax; *lpFirst && (i > 0); i--, lpFirst++) 803 { 804 if (!strncmpiW(lpFirst, lpSrch, len)) 805 return (LPWSTR)lpFirst; 806 } 807 808 return NULL; 809 } 810 811 /************************************************************************* 812 * StrToIntA [SHLWAPI.@] 813 * 814 * Read a signed integer from a string. 815 * 816 * PARAMS 817 * lpszStr [I] String to read integer from 818 * 819 * RETURNS 820 * The signed integer value represented by the string, or 0 if no integer is 821 * present. 822 * 823 * NOTES 824 * No leading space is allowed before the number, although a leading '-' is. 825 */ 826 int WINAPI StrToIntA(LPCSTR lpszStr) 827 { 828 int iRet = 0; 829 830 TRACE("(%s)\n", debugstr_a(lpszStr)); 831 832 if (!lpszStr) 833 { 834 WARN("Invalid lpszStr would crash under Win32!\n"); 835 return 0; 836 } 837 838 if (*lpszStr == '-' || isdigit(*lpszStr)) 839 StrToIntExA(lpszStr, 0, &iRet); 840 return iRet; 841 } 842 843 /************************************************************************* 844 * StrToIntW [SHLWAPI.@] 845 * 846 * See StrToIntA. 847 */ 848 int WINAPI StrToIntW(LPCWSTR lpszStr) 849 { 850 int iRet = 0; 851 852 TRACE("(%s)\n", debugstr_w(lpszStr)); 853 854 if (!lpszStr) 855 { 856 WARN("Invalid lpszStr would crash under Win32!\n"); 857 return 0; 858 } 859 860 if (*lpszStr == '-' || isdigitW(*lpszStr)) 861 StrToIntExW(lpszStr, 0, &iRet); 862 return iRet; 863 } 864 865 /************************************************************************* 866 * StrToIntExA [SHLWAPI.@] 867 * 868 * Read an integer from a string. 869 * 870 * PARAMS 871 * lpszStr [I] String to read integer from 872 * dwFlags [I] Flags controlling the conversion 873 * lpiRet [O] Destination for read integer. 874 * 875 * RETURNS 876 * Success: TRUE. lpiRet contains the integer value represented by the string. 877 * Failure: FALSE, if the string is invalid, or no number is present. 878 * 879 * NOTES 880 * Leading whitespace, '-' and '+' are allowed before the number. If 881 * dwFlags includes STIF_SUPPORT_HEX, hexadecimal numbers are allowed, if 882 * preceded by '0x'. If this flag is not set, or there is no '0x' prefix, 883 * the string is treated as a decimal string. A leading '-' is ignored for 884 * hexadecimal numbers. 885 */ 886 BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet) 887 { 888 LONGLONG li; 889 BOOL bRes; 890 891 TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet); 892 893 bRes = StrToInt64ExA(lpszStr, dwFlags, &li); 894 if (bRes) *lpiRet = li; 895 return bRes; 896 } 897 898 /************************************************************************* 899 * StrToInt64ExA [SHLWAPI.@] 900 * 901 * See StrToIntExA. 902 */ 903 BOOL WINAPI StrToInt64ExA(LPCSTR lpszStr, DWORD dwFlags, LONGLONG *lpiRet) 904 { 905 BOOL bNegative = FALSE; 906 LONGLONG iRet = 0; 907 908 TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet); 909 910 if (!lpszStr || !lpiRet) 911 { 912 WARN("Invalid parameter would crash under Win32!\n"); 913 return FALSE; 914 } 915 if (dwFlags > STIF_SUPPORT_HEX) WARN("Unknown flags %08x\n", dwFlags); 916 917 /* Skip leading space, '+', '-' */ 918 while (isspace(*lpszStr)) 919 lpszStr = CharNextA(lpszStr); 920 921 if (*lpszStr == '-') 922 { 923 bNegative = TRUE; 924 lpszStr++; 925 } 926 else if (*lpszStr == '+') 927 lpszStr++; 928 929 if (dwFlags & STIF_SUPPORT_HEX && 930 *lpszStr == '0' && tolower(lpszStr[1]) == 'x') 931 { 932 /* Read hex number */ 933 lpszStr += 2; 934 935 if (!isxdigit(*lpszStr)) 936 return FALSE; 937 938 while (isxdigit(*lpszStr)) 939 { 940 iRet = iRet * 16; 941 if (isdigit(*lpszStr)) 942 iRet += (*lpszStr - '0'); 943 else 944 iRet += 10 + (tolower(*lpszStr) - 'a'); 945 lpszStr++; 946 } 947 *lpiRet = iRet; 948 return TRUE; 949 } 950 951 /* Read decimal number */ 952 if (!isdigit(*lpszStr)) 953 return FALSE; 954 955 while (isdigit(*lpszStr)) 956 { 957 iRet = iRet * 10; 958 iRet += (*lpszStr - '0'); 959 lpszStr++; 960 } 961 *lpiRet = bNegative ? -iRet : iRet; 962 return TRUE; 963 } 964 965 /************************************************************************* 966 * StrToIntExW [SHLWAPI.@] 967 * 968 * See StrToIntExA. 969 */ 970 BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet) 971 { 972 LONGLONG li; 973 BOOL bRes; 974 975 TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet); 976 977 bRes = StrToInt64ExW(lpszStr, dwFlags, &li); 978 if (bRes) *lpiRet = li; 979 return bRes; 980 } 981 982 /************************************************************************* 983 * StrToInt64ExW [SHLWAPI.@] 984 * 985 * See StrToIntExA. 986 */ 987 BOOL WINAPI StrToInt64ExW(LPCWSTR lpszStr, DWORD dwFlags, LONGLONG *lpiRet) 988 { 989 BOOL bNegative = FALSE; 990 LONGLONG iRet = 0; 991 992 TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet); 993 994 if (!lpszStr || !lpiRet) 995 { 996 WARN("Invalid parameter would crash under Win32!\n"); 997 return FALSE; 998 } 999 if (dwFlags > STIF_SUPPORT_HEX) WARN("Unknown flags %08x\n", dwFlags); 1000 1001 /* Skip leading space, '+', '-' */ 1002 while (isspaceW(*lpszStr)) lpszStr++; 1003 1004 if (*lpszStr == '-') 1005 { 1006 bNegative = TRUE; 1007 lpszStr++; 1008 } 1009 else if (*lpszStr == '+') 1010 lpszStr++; 1011 1012 if (dwFlags & STIF_SUPPORT_HEX && 1013 *lpszStr == '0' && tolowerW(lpszStr[1]) == 'x') 1014 { 1015 /* Read hex number */ 1016 lpszStr += 2; 1017 1018 if (!isxdigitW(*lpszStr)) 1019 return FALSE; 1020 1021 while (isxdigitW(*lpszStr)) 1022 { 1023 iRet = iRet * 16; 1024 if (isdigitW(*lpszStr)) 1025 iRet += (*lpszStr - '0'); 1026 else 1027 iRet += 10 + (tolowerW(*lpszStr) - 'a'); 1028 lpszStr++; 1029 } 1030 *lpiRet = iRet; 1031 return TRUE; 1032 } 1033 1034 /* Read decimal number */ 1035 if (!isdigitW(*lpszStr)) 1036 return FALSE; 1037 1038 while (isdigitW(*lpszStr)) 1039 { 1040 iRet = iRet * 10; 1041 iRet += (*lpszStr - '0'); 1042 lpszStr++; 1043 } 1044 *lpiRet = bNegative ? -iRet : iRet; 1045 return TRUE; 1046 } 1047 1048 /************************************************************************* 1049 * StrDupA [SHLWAPI.@] 1050 * 1051 * Duplicate a string. 1052 * 1053 * PARAMS 1054 * lpszStr [I] String to duplicate. 1055 * 1056 * RETURNS 1057 * Success: A pointer to a new string containing the contents of lpszStr 1058 * Failure: NULL, if memory cannot be allocated 1059 * 1060 * NOTES 1061 * The string memory is allocated with LocalAlloc(), and so should be released 1062 * by calling LocalFree(). 1063 */ 1064 LPSTR WINAPI StrDupA(LPCSTR lpszStr) 1065 { 1066 int iLen; 1067 LPSTR lpszRet; 1068 1069 TRACE("(%s)\n",debugstr_a(lpszStr)); 1070 1071 #ifdef __REACTOS__ 1072 if (!lpszStr) 1073 return NULL; 1074 #endif 1075 iLen = lpszStr ? strlen(lpszStr) + 1 : 1; 1076 lpszRet = LocalAlloc(LMEM_FIXED, iLen); 1077 1078 if (lpszRet) 1079 { 1080 if (lpszStr) 1081 memcpy(lpszRet, lpszStr, iLen); 1082 else 1083 *lpszRet = '\0'; 1084 } 1085 return lpszRet; 1086 } 1087 1088 /************************************************************************* 1089 * StrDupW [SHLWAPI.@] 1090 * 1091 * See StrDupA. 1092 */ 1093 LPWSTR WINAPI StrDupW(LPCWSTR lpszStr) 1094 { 1095 int iLen; 1096 LPWSTR lpszRet; 1097 1098 TRACE("(%s)\n",debugstr_w(lpszStr)); 1099 1100 #ifdef __REACTOS__ 1101 if (!lpszStr) 1102 return NULL; 1103 #endif 1104 iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR); 1105 lpszRet = LocalAlloc(LMEM_FIXED, iLen); 1106 1107 if (lpszRet) 1108 { 1109 if (lpszStr) 1110 memcpy(lpszRet, lpszStr, iLen); 1111 else 1112 *lpszRet = '\0'; 1113 } 1114 return lpszRet; 1115 } 1116 1117 /************************************************************************* 1118 * SHLWAPI_StrSpnHelperA 1119 * 1120 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA 1121 */ 1122 static int SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch, 1123 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD), 1124 BOOL bInvert) 1125 { 1126 LPCSTR lpszRead = lpszStr; 1127 if (lpszStr && *lpszStr && lpszMatch) 1128 { 1129 while (*lpszRead) 1130 { 1131 LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead); 1132 1133 if (!bInvert && !lpszTest) 1134 break; 1135 if (bInvert && lpszTest) 1136 break; 1137 lpszRead = CharNextA(lpszRead); 1138 }; 1139 } 1140 return lpszRead - lpszStr; 1141 } 1142 1143 /************************************************************************* 1144 * StrSpnA [SHLWAPI.@] 1145 * 1146 * Find the length of the start of a string that contains only certain 1147 * characters. 1148 * 1149 * PARAMS 1150 * lpszStr [I] String to search 1151 * lpszMatch [I] Characters that can be in the substring 1152 * 1153 * RETURNS 1154 * The length of the part of lpszStr containing only chars from lpszMatch, 1155 * or 0 if any parameter is invalid. 1156 */ 1157 int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch) 1158 { 1159 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch)); 1160 1161 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE); 1162 } 1163 1164 /************************************************************************* 1165 * StrSpnW [SHLWAPI.@] 1166 * 1167 * See StrSpnA. 1168 */ 1169 int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch) 1170 { 1171 if (!lpszStr || !lpszMatch) return 0; 1172 return strspnW( lpszStr, lpszMatch ); 1173 } 1174 1175 /************************************************************************* 1176 * StrCSpnA [SHLWAPI.@] 1177 * 1178 * Find the length of the start of a string that does not contain certain 1179 * characters. 1180 * 1181 * PARAMS 1182 * lpszStr [I] String to search 1183 * lpszMatch [I] Characters that cannot be in the substring 1184 * 1185 * RETURNS 1186 * The length of the part of lpszStr containing only chars not in lpszMatch, 1187 * or 0 if any parameter is invalid. 1188 */ 1189 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch) 1190 { 1191 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch)); 1192 1193 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE); 1194 } 1195 1196 /************************************************************************* 1197 * StrCSpnW [SHLWAPI.@] 1198 * 1199 * See StrCSpnA. 1200 */ 1201 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch) 1202 { 1203 if (!lpszStr || !lpszMatch) return 0; 1204 return strcspnW( lpszStr, lpszMatch ); 1205 } 1206 1207 /************************************************************************* 1208 * StrCSpnIA [SHLWAPI.@] 1209 * 1210 * Find the length of the start of a string that does not contain certain 1211 * characters, ignoring case. 1212 * 1213 * PARAMS 1214 * lpszStr [I] String to search 1215 * lpszMatch [I] Characters that cannot be in the substring 1216 * 1217 * RETURNS 1218 * The length of the part of lpszStr containing only chars not in lpszMatch, 1219 * or 0 if any parameter is invalid. 1220 */ 1221 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch) 1222 { 1223 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch)); 1224 1225 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE); 1226 } 1227 1228 /************************************************************************* 1229 * StrCSpnIW [SHLWAPI.@] 1230 * 1231 * See StrCSpnIA. 1232 */ 1233 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch) 1234 { 1235 LPCWSTR lpszRead = lpszStr; 1236 1237 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch)); 1238 1239 if (lpszStr && *lpszStr && lpszMatch) 1240 { 1241 while (*lpszRead) 1242 { 1243 if (StrChrIW(lpszMatch, *lpszRead)) break; 1244 lpszRead++; 1245 } 1246 } 1247 return lpszRead - lpszStr; 1248 } 1249 1250 /************************************************************************* 1251 * StrPBrkA [SHLWAPI.@] 1252 * 1253 * Search a string for any of a group of characters. 1254 * 1255 * PARAMS 1256 * lpszStr [I] String to search 1257 * lpszMatch [I] Characters to match 1258 * 1259 * RETURNS 1260 * A pointer to the first matching character in lpszStr, or NULL if no 1261 * match was found. 1262 */ 1263 LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch) 1264 { 1265 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch)); 1266 1267 if (lpszStr && lpszMatch && *lpszMatch) 1268 { 1269 while (*lpszStr) 1270 { 1271 if (StrChrA(lpszMatch, *lpszStr)) 1272 return (LPSTR)lpszStr; 1273 lpszStr = CharNextA(lpszStr); 1274 } 1275 } 1276 return NULL; 1277 } 1278 1279 /************************************************************************* 1280 * StrPBrkW [SHLWAPI.@] 1281 * 1282 * See StrPBrkA. 1283 */ 1284 LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch) 1285 { 1286 if (!lpszStr || !lpszMatch) return NULL; 1287 return strpbrkW( lpszStr, lpszMatch ); 1288 } 1289 1290 /************************************************************************* 1291 * SHLWAPI_StrRChrHelperA 1292 * 1293 * Internal implementation of StrRChrA/StrRChrIA. 1294 */ 1295 static LPSTR SHLWAPI_StrRChrHelperA(LPCSTR lpszStr, 1296 LPCSTR lpszEnd, WORD ch, 1297 BOOL (WINAPI *pChrCmpFn)(WORD,WORD)) 1298 { 1299 LPCSTR lpszRet = NULL; 1300 1301 if (lpszStr) 1302 { 1303 WORD ch2; 1304 1305 if (!lpszEnd) 1306 lpszEnd = lpszStr + lstrlenA(lpszStr); 1307 1308 while (*lpszStr && lpszStr <= lpszEnd) 1309 { 1310 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr; 1311 1312 if (!pChrCmpFn(ch, ch2)) 1313 lpszRet = lpszStr; 1314 lpszStr = CharNextA(lpszStr); 1315 } 1316 } 1317 return (LPSTR)lpszRet; 1318 } 1319 1320 /************************************************************************** 1321 * StrRChrA [SHLWAPI.@] 1322 * 1323 * Find the last occurrence of a character in string. 1324 * 1325 * PARAMS 1326 * lpszStr [I] String to search in 1327 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr 1328 * ch [I] Character to search for. 1329 * 1330 * RETURNS 1331 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd, 1332 * or NULL if not found. 1333 * Failure: NULL, if any arguments are invalid. 1334 */ 1335 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch) 1336 { 1337 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch); 1338 1339 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA); 1340 } 1341 1342 /************************************************************************** 1343 * StrRChrW [SHLWAPI.@] 1344 * 1345 * See StrRChrA. 1346 */ 1347 LPWSTR WINAPI StrRChrW(LPCWSTR str, LPCWSTR end, WORD ch) 1348 { 1349 WCHAR *ret = NULL; 1350 1351 if (!str) return NULL; 1352 if (!end) end = str + strlenW(str); 1353 while (str < end) 1354 { 1355 if (*str == ch) ret = (WCHAR *)str; 1356 str++; 1357 } 1358 return ret; 1359 } 1360 1361 /************************************************************************** 1362 * StrRChrIA [SHLWAPI.@] 1363 * 1364 * Find the last occurrence of a character in string, ignoring case. 1365 * 1366 * PARAMS 1367 * lpszStr [I] String to search in 1368 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr 1369 * ch [I] Character to search for. 1370 * 1371 * RETURNS 1372 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd, 1373 * or NULL if not found. 1374 * Failure: NULL, if any arguments are invalid. 1375 */ 1376 LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch) 1377 { 1378 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch); 1379 1380 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA); 1381 } 1382 1383 /************************************************************************** 1384 * StrRChrIW [SHLWAPI.@] 1385 * 1386 * See StrRChrIA. 1387 */ 1388 LPWSTR WINAPI StrRChrIW(LPCWSTR str, LPCWSTR end, WORD ch) 1389 { 1390 WCHAR *ret = NULL; 1391 1392 if (!str) return NULL; 1393 if (!end) end = str + strlenW(str); 1394 while (str < end) 1395 { 1396 if (!ChrCmpIW(*str, ch)) ret = (WCHAR *)str; 1397 str++; 1398 } 1399 return ret; 1400 } 1401 1402 /************************************************************************* 1403 * StrCatBuffA [SHLWAPI.@] 1404 * 1405 * Concatenate two strings together. 1406 * 1407 * PARAMS 1408 * lpszStr [O] String to concatenate to 1409 * lpszCat [I] String to add to lpszCat 1410 * cchMax [I] Maximum number of characters for the whole string 1411 * 1412 * RETURNS 1413 * lpszStr. 1414 * 1415 * NOTES 1416 * cchMax determines the number of characters in the final length of the 1417 * string, not the number appended to lpszStr from lpszCat. 1418 */ 1419 LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax) 1420 { 1421 INT iLen; 1422 1423 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax); 1424 1425 if (!lpszStr) 1426 { 1427 WARN("Invalid lpszStr would crash under Win32!\n"); 1428 return NULL; 1429 } 1430 1431 iLen = strlen(lpszStr); 1432 cchMax -= iLen; 1433 1434 if (cchMax > 0) 1435 StrCpyNA(lpszStr + iLen, lpszCat, cchMax); 1436 return lpszStr; 1437 } 1438 1439 /************************************************************************* 1440 * StrCatBuffW [SHLWAPI.@] 1441 * 1442 * See StrCatBuffA. 1443 */ 1444 LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax) 1445 { 1446 INT iLen; 1447 1448 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax); 1449 1450 if (!lpszStr) 1451 { 1452 WARN("Invalid lpszStr would crash under Win32!\n"); 1453 return NULL; 1454 } 1455 1456 iLen = strlenW(lpszStr); 1457 cchMax -= iLen; 1458 1459 if (cchMax > 0) 1460 StrCpyNW(lpszStr + iLen, lpszCat, cchMax); 1461 return lpszStr; 1462 } 1463 1464 /************************************************************************* 1465 * StrRetToBufA [SHLWAPI.@] 1466 * 1467 * Convert a STRRET to a normal string. 1468 * 1469 * PARAMS 1470 * lpStrRet [O] STRRET to convert 1471 * pIdl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET 1472 * lpszDest [O] Destination for normal string 1473 * dwLen [I] Length of lpszDest 1474 * 1475 * RETURNS 1476 * Success: S_OK. lpszDest contains up to dwLen characters of the string. 1477 * If lpStrRet is of type STRRET_WSTR, its memory is freed with 1478 * CoTaskMemFree() and its type set to STRRET_CSTRA. 1479 * Failure: E_FAIL, if any parameters are invalid. 1480 */ 1481 HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, UINT len) 1482 { 1483 /* NOTE: 1484 * This routine is identical to that in dlls/shell32/shellstring.c. 1485 * It was duplicated because not every version of Shlwapi.dll exports 1486 * StrRetToBufA. If you change one routine, change them both. 1487 */ 1488 TRACE("dest=%p len=0x%x strret=%p pidl=%p\n", dest, len, src, pidl); 1489 1490 if (!src) 1491 { 1492 WARN("Invalid lpStrRet would crash under Win32!\n"); 1493 if (dest) 1494 *dest = '\0'; 1495 return E_FAIL; 1496 } 1497 1498 if (!dest || !len) 1499 return E_FAIL; 1500 1501 *dest = '\0'; 1502 1503 switch (src->uType) 1504 { 1505 case STRRET_WSTR: 1506 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL); 1507 CoTaskMemFree(src->u.pOleStr); 1508 break; 1509 1510 case STRRET_CSTR: 1511 lstrcpynA(dest, src->u.cStr, len); 1512 break; 1513 1514 case STRRET_OFFSET: 1515 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len); 1516 break; 1517 1518 default: 1519 FIXME("unknown type!\n"); 1520 return E_NOTIMPL; 1521 } 1522 return S_OK; 1523 } 1524 1525 /************************************************************************* 1526 * StrRetToBufW [SHLWAPI.@] 1527 * 1528 * See StrRetToBufA. 1529 */ 1530 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, UINT len) 1531 { 1532 TRACE("dest=%p len=0x%x strret=%p pidl=%p\n", dest, len, src, pidl); 1533 1534 if (!dest || !len) 1535 return E_FAIL; 1536 1537 if (!src) 1538 { 1539 WARN("Invalid lpStrRet would crash under Win32!\n"); 1540 if (dest) 1541 *dest = '\0'; 1542 return E_FAIL; 1543 } 1544 1545 *dest = '\0'; 1546 1547 switch (src->uType) { 1548 case STRRET_WSTR: { 1549 size_t dst_len; 1550 if (!src->u.pOleStr) 1551 return E_FAIL; 1552 dst_len = strlenW(src->u.pOleStr); 1553 memcpy(dest, src->u.pOleStr, min(dst_len, len-1) * sizeof(WCHAR)); 1554 dest[min(dst_len, len-1)] = 0; 1555 CoTaskMemFree(src->u.pOleStr); 1556 if (len <= dst_len) 1557 { 1558 dest[0] = 0; 1559 return E_NOT_SUFFICIENT_BUFFER; 1560 } 1561 break; 1562 } 1563 1564 case STRRET_CSTR: 1565 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len )) 1566 dest[len-1] = 0; 1567 break; 1568 1569 case STRRET_OFFSET: 1570 if (pidl) 1571 { 1572 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, 1573 dest, len )) 1574 dest[len-1] = 0; 1575 } 1576 break; 1577 1578 default: 1579 FIXME("unknown type!\n"); 1580 return E_NOTIMPL; 1581 } 1582 1583 return S_OK; 1584 } 1585 1586 /************************************************************************* 1587 * StrRetToStrA [SHLWAPI.@] 1588 * 1589 * Converts a STRRET to a normal string. 1590 * 1591 * PARAMS 1592 * lpStrRet [O] STRRET to convert 1593 * pidl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET 1594 * ppszName [O] Destination for converted string 1595 * 1596 * RETURNS 1597 * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc(). 1598 * Failure: E_FAIL, if any parameters are invalid. 1599 */ 1600 HRESULT WINAPI StrRetToStrA(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPSTR *ppszName) 1601 { 1602 HRESULT hRet = E_FAIL; 1603 1604 switch (lpStrRet->uType) 1605 { 1606 case STRRET_WSTR: 1607 hRet = _SHStrDupAW(lpStrRet->u.pOleStr, ppszName); 1608 CoTaskMemFree(lpStrRet->u.pOleStr); 1609 break; 1610 1611 case STRRET_CSTR: 1612 hRet = _SHStrDupAA(lpStrRet->u.cStr, ppszName); 1613 break; 1614 1615 case STRRET_OFFSET: 1616 hRet = _SHStrDupAA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName); 1617 break; 1618 1619 default: 1620 *ppszName = NULL; 1621 } 1622 1623 return hRet; 1624 } 1625 1626 /************************************************************************* 1627 * StrRetToStrW [SHLWAPI.@] 1628 * 1629 * See StrRetToStrA. 1630 */ 1631 HRESULT WINAPI StrRetToStrW(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPWSTR *ppszName) 1632 { 1633 HRESULT hRet = E_FAIL; 1634 1635 switch (lpStrRet->uType) 1636 { 1637 case STRRET_WSTR: 1638 hRet = SHStrDupW(lpStrRet->u.pOleStr, ppszName); 1639 CoTaskMemFree(lpStrRet->u.pOleStr); 1640 break; 1641 1642 case STRRET_CSTR: 1643 hRet = SHStrDupA(lpStrRet->u.cStr, ppszName); 1644 break; 1645 1646 case STRRET_OFFSET: 1647 hRet = SHStrDupA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName); 1648 break; 1649 1650 default: 1651 *ppszName = NULL; 1652 } 1653 1654 return hRet; 1655 } 1656 1657 /* Create an ASCII string copy using SysAllocString() */ 1658 static HRESULT _SHStrDupAToBSTR(LPCSTR src, BSTR *pBstrOut) 1659 { 1660 *pBstrOut = NULL; 1661 1662 if (src) 1663 { 1664 INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0); 1665 WCHAR* szTemp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 1666 1667 if (szTemp) 1668 { 1669 MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len); 1670 *pBstrOut = SysAllocString(szTemp); 1671 HeapFree(GetProcessHeap(), 0, szTemp); 1672 1673 if (*pBstrOut) 1674 return S_OK; 1675 } 1676 } 1677 return E_OUTOFMEMORY; 1678 } 1679 1680 /************************************************************************* 1681 * StrRetToBSTR [SHLWAPI.@] 1682 * 1683 * Converts a STRRET to a BSTR. 1684 * 1685 * PARAMS 1686 * lpStrRet [O] STRRET to convert 1687 * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSET 1688 * pBstrOut [O] Destination for converted BSTR 1689 * 1690 * RETURNS 1691 * Success: S_OK. pBstrOut contains the new string. 1692 * Failure: E_FAIL, if any parameters are invalid. 1693 */ 1694 HRESULT WINAPI StrRetToBSTR(STRRET *lpStrRet, LPCITEMIDLIST pidl, BSTR* pBstrOut) 1695 { 1696 HRESULT hRet = E_FAIL; 1697 1698 switch (lpStrRet->uType) 1699 { 1700 case STRRET_WSTR: 1701 *pBstrOut = SysAllocString(lpStrRet->u.pOleStr); 1702 if (*pBstrOut) 1703 hRet = S_OK; 1704 CoTaskMemFree(lpStrRet->u.pOleStr); 1705 break; 1706 1707 case STRRET_CSTR: 1708 hRet = _SHStrDupAToBSTR(lpStrRet->u.cStr, pBstrOut); 1709 break; 1710 1711 case STRRET_OFFSET: 1712 hRet = _SHStrDupAToBSTR(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, pBstrOut); 1713 break; 1714 1715 default: 1716 *pBstrOut = NULL; 1717 } 1718 1719 return hRet; 1720 } 1721 1722 /************************************************************************* 1723 * StrFormatKBSizeA [SHLWAPI.@] 1724 * 1725 * Create a formatted string containing a byte count in Kilobytes. 1726 * 1727 * PARAMS 1728 * llBytes [I] Byte size to format 1729 * lpszDest [I] Destination for formatted string 1730 * cchMax [I] Size of lpszDest 1731 * 1732 * RETURNS 1733 * lpszDest. 1734 */ 1735 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax) 1736 { 1737 WCHAR wszBuf[256]; 1738 1739 if (!StrFormatKBSizeW(llBytes, wszBuf, 256)) 1740 return NULL; 1741 if (!WideCharToMultiByte(CP_ACP, 0, wszBuf, -1, lpszDest, cchMax, NULL, NULL)) 1742 return NULL; 1743 return lpszDest; 1744 } 1745 1746 /************************************************************************* 1747 * StrFormatKBSizeW [SHLWAPI.@] 1748 * 1749 * See StrFormatKBSizeA. 1750 */ 1751 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax) 1752 { 1753 static const WCHAR kb[] = {' ','K','B',0}; 1754 LONGLONG llKB = (llBytes + 1023) >> 10; 1755 int len; 1756 1757 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax); 1758 1759 if (!FormatInt(llKB, lpszDest, cchMax)) 1760 return NULL; 1761 1762 len = lstrlenW(lpszDest); 1763 if (cchMax - len < 4) 1764 return NULL; 1765 lstrcatW(lpszDest, kb); 1766 return lpszDest; 1767 } 1768 1769 /************************************************************************* 1770 * StrNCatA [SHLWAPI.@] 1771 * 1772 * Concatenate two strings together. 1773 * 1774 * PARAMS 1775 * lpszStr [O] String to concatenate to 1776 * lpszCat [I] String to add to lpszCat 1777 * cchMax [I] Maximum number of characters to concatenate 1778 * 1779 * RETURNS 1780 * lpszStr. 1781 * 1782 * NOTES 1783 * cchMax determines the number of characters that are appended to lpszStr, 1784 * not the total length of the string. 1785 */ 1786 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax) 1787 { 1788 LPSTR lpszRet = lpszStr; 1789 1790 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax); 1791 1792 if (!lpszStr) 1793 { 1794 WARN("Invalid lpszStr would crash under Win32!\n"); 1795 return NULL; 1796 } 1797 1798 StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax); 1799 return lpszRet; 1800 } 1801 1802 /************************************************************************* 1803 * StrNCatW [SHLWAPI.@] 1804 * 1805 * See StrNCatA. 1806 */ 1807 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax) 1808 { 1809 LPWSTR lpszRet = lpszStr; 1810 1811 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax); 1812 1813 if (!lpszStr) 1814 { 1815 WARN("Invalid lpszStr would crash under Win32\n"); 1816 return NULL; 1817 } 1818 1819 StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax); 1820 return lpszRet; 1821 } 1822 1823 /************************************************************************* 1824 * StrTrimA [SHLWAPI.@] 1825 * 1826 * Remove characters from the start and end of a string. 1827 * 1828 * PARAMS 1829 * lpszStr [O] String to remove characters from 1830 * lpszTrim [I] Characters to remove from lpszStr 1831 * 1832 * RETURNS 1833 * TRUE If lpszStr was valid and modified 1834 * FALSE Otherwise 1835 */ 1836 BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim) 1837 { 1838 DWORD dwLen; 1839 LPSTR lpszRead = lpszStr; 1840 BOOL bRet = FALSE; 1841 1842 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim)); 1843 1844 if (lpszRead && *lpszRead) 1845 { 1846 while (*lpszRead && StrChrA(lpszTrim, *lpszRead)) 1847 lpszRead = CharNextA(lpszRead); /* Skip leading matches */ 1848 1849 dwLen = strlen(lpszRead); 1850 1851 if (lpszRead != lpszStr) 1852 { 1853 memmove(lpszStr, lpszRead, dwLen + 1); 1854 bRet = TRUE; 1855 } 1856 if (dwLen > 0) 1857 { 1858 lpszRead = lpszStr + dwLen; 1859 while (StrChrA(lpszTrim, lpszRead[-1])) 1860 lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */ 1861 1862 if (lpszRead != lpszStr + dwLen) 1863 { 1864 *lpszRead = '\0'; 1865 bRet = TRUE; 1866 } 1867 } 1868 } 1869 return bRet; 1870 } 1871 1872 /************************************************************************* 1873 * StrTrimW [SHLWAPI.@] 1874 * 1875 * See StrTrimA. 1876 */ 1877 BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim) 1878 { 1879 DWORD dwLen; 1880 LPWSTR lpszRead = lpszStr; 1881 BOOL bRet = FALSE; 1882 1883 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim)); 1884 1885 if (lpszRead && *lpszRead) 1886 { 1887 while (*lpszRead && StrChrW(lpszTrim, *lpszRead)) lpszRead++; 1888 1889 dwLen = strlenW(lpszRead); 1890 1891 if (lpszRead != lpszStr) 1892 { 1893 memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR)); 1894 bRet = TRUE; 1895 } 1896 if (dwLen > 0) 1897 { 1898 lpszRead = lpszStr + dwLen; 1899 while (StrChrW(lpszTrim, lpszRead[-1])) 1900 lpszRead--; /* Skip trailing matches */ 1901 1902 if (lpszRead != lpszStr + dwLen) 1903 { 1904 *lpszRead = '\0'; 1905 bRet = TRUE; 1906 } 1907 } 1908 } 1909 return bRet; 1910 } 1911 1912 /************************************************************************* 1913 * _SHStrDupAA [INTERNAL] 1914 * 1915 * Duplicates a ASCII string to ASCII. The destination buffer is allocated. 1916 */ 1917 static HRESULT _SHStrDupAA(LPCSTR src, LPSTR * dest) 1918 { 1919 HRESULT hr; 1920 int len = 0; 1921 1922 if (src) { 1923 len = lstrlenA(src) + 1; 1924 *dest = CoTaskMemAlloc(len); 1925 } else { 1926 *dest = NULL; 1927 } 1928 1929 if (*dest) { 1930 lstrcpynA(*dest,src, len); 1931 hr = S_OK; 1932 } else { 1933 hr = E_OUTOFMEMORY; 1934 } 1935 1936 TRACE("%s->(%p)\n", debugstr_a(src), *dest); 1937 return hr; 1938 } 1939 1940 /************************************************************************* 1941 * SHStrDupA [SHLWAPI.@] 1942 * 1943 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc(). 1944 * 1945 * PARAMS 1946 * lpszStr [I] String to copy 1947 * lppszDest [O] Destination for the new string copy 1948 * 1949 * RETURNS 1950 * Success: S_OK. lppszDest contains the new string in Unicode format. 1951 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation 1952 * fails. 1953 */ 1954 HRESULT WINAPI SHStrDupA(LPCSTR lpszStr, LPWSTR * lppszDest) 1955 { 1956 HRESULT hRet; 1957 int len = 0; 1958 1959 if (lpszStr) 1960 { 1961 len = MultiByteToWideChar(CP_ACP, 0, lpszStr, -1, NULL, 0) * sizeof(WCHAR); 1962 *lppszDest = CoTaskMemAlloc(len); 1963 } 1964 else 1965 *lppszDest = NULL; 1966 1967 if (*lppszDest) 1968 { 1969 MultiByteToWideChar(CP_ACP, 0, lpszStr, -1, *lppszDest, len/sizeof(WCHAR)); 1970 hRet = S_OK; 1971 } 1972 else 1973 hRet = E_OUTOFMEMORY; 1974 1975 TRACE("%s->(%p)\n", debugstr_a(lpszStr), *lppszDest); 1976 return hRet; 1977 } 1978 1979 /************************************************************************* 1980 * _SHStrDupAW [INTERNAL] 1981 * 1982 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated. 1983 */ 1984 static HRESULT _SHStrDupAW(LPCWSTR src, LPSTR * dest) 1985 { 1986 HRESULT hr; 1987 int len = 0; 1988 1989 if (src) { 1990 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL); 1991 *dest = CoTaskMemAlloc(len); 1992 } else { 1993 *dest = NULL; 1994 } 1995 1996 if (*dest) { 1997 WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL); 1998 hr = S_OK; 1999 } else { 2000 hr = E_OUTOFMEMORY; 2001 } 2002 2003 TRACE("%s->(%p)\n", debugstr_w(src), *dest); 2004 return hr; 2005 } 2006 2007 /************************************************************************* 2008 * SHStrDupW [SHLWAPI.@] 2009 * 2010 * See SHStrDupA. 2011 */ 2012 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest) 2013 { 2014 HRESULT hr; 2015 int len = 0; 2016 2017 if (src) { 2018 len = (lstrlenW(src) + 1) * sizeof(WCHAR); 2019 *dest = CoTaskMemAlloc(len); 2020 } else { 2021 *dest = NULL; 2022 } 2023 2024 if (*dest) { 2025 memcpy(*dest, src, len); 2026 hr = S_OK; 2027 } else { 2028 hr = E_OUTOFMEMORY; 2029 } 2030 2031 TRACE("%s->(%p)\n", debugstr_w(src), *dest); 2032 return hr; 2033 } 2034 2035 /************************************************************************* 2036 * SHLWAPI_WriteReverseNum 2037 * 2038 * Internal helper for SHLWAPI_WriteTimeClass. 2039 */ 2040 static inline LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum) 2041 { 2042 *lpszOut-- = '\0'; 2043 2044 /* Write a decimal number to a string, backwards */ 2045 do 2046 { 2047 DWORD dwNextDigit = dwNum % 10; 2048 *lpszOut-- = '0' + dwNextDigit; 2049 dwNum = (dwNum - dwNextDigit) / 10; 2050 } while (dwNum > 0); 2051 2052 return lpszOut; 2053 } 2054 2055 /************************************************************************* 2056 * SHLWAPI_FormatSignificant 2057 * 2058 * Internal helper for SHLWAPI_WriteTimeClass. 2059 */ 2060 static inline int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits) 2061 { 2062 /* Zero non significant digits, return remaining significant digits */ 2063 while (*lpszNum) 2064 { 2065 lpszNum++; 2066 if (--dwDigits == 0) 2067 { 2068 while (*lpszNum) 2069 *lpszNum++ = '0'; 2070 return 0; 2071 } 2072 } 2073 return dwDigits; 2074 } 2075 2076 /************************************************************************* 2077 * SHLWAPI_WriteTimeClass 2078 * 2079 * Internal helper for StrFromTimeIntervalW. 2080 */ 2081 static int SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue, 2082 UINT uClassStringId, int iDigits) 2083 { 2084 WCHAR szBuff[64], *szOut = szBuff + 32; 2085 2086 szOut = SHLWAPI_WriteReverseNum(szOut, dwValue); 2087 iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits); 2088 *szOut = ' '; 2089 LoadStringW(shlwapi_hInstance, uClassStringId, szBuff + 32, 32); 2090 strcatW(lpszOut, szOut); 2091 return iDigits; 2092 } 2093 2094 /************************************************************************* 2095 * StrFromTimeIntervalA [SHLWAPI.@] 2096 * 2097 * Format a millisecond time interval into a string 2098 * 2099 * PARAMS 2100 * lpszStr [O] Output buffer for formatted time interval 2101 * cchMax [I] Size of lpszStr 2102 * dwMS [I] Number of milliseconds 2103 * iDigits [I] Number of digits to print 2104 * 2105 * RETURNS 2106 * The length of the formatted string, or 0 if any parameter is invalid. 2107 * 2108 * NOTES 2109 * This implementation mimics the Win32 behaviour of always writing a leading 2110 * space before the time interval begins. 2111 * 2112 * iDigits is used to provide approximate times if accuracy is not important. 2113 * This number of digits will be written of the first non-zero time class 2114 * (hours/minutes/seconds). If this does not complete the time classification, 2115 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded). 2116 * If there are digits remaining following the writing of a time class, the 2117 * next time class will be written. 2118 * 2119 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the 2120 * following will result from the given values of iDigits: 2121 * 2122 *| iDigits 1 2 3 4 5 ... 2123 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ... 2124 */ 2125 INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS, 2126 int iDigits) 2127 { 2128 INT iRet = 0; 2129 2130 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits); 2131 2132 if (lpszStr && cchMax) 2133 { 2134 WCHAR szBuff[128]; 2135 StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits); 2136 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0); 2137 } 2138 return iRet; 2139 } 2140 2141 2142 /************************************************************************* 2143 * StrFromTimeIntervalW [SHLWAPI.@] 2144 * 2145 * See StrFromTimeIntervalA. 2146 */ 2147 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS, 2148 int iDigits) 2149 { 2150 INT iRet = 0; 2151 2152 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits); 2153 2154 if (lpszStr && cchMax) 2155 { 2156 WCHAR szCopy[128]; 2157 DWORD dwHours, dwMinutes; 2158 2159 if (!iDigits || cchMax == 1) 2160 { 2161 *lpszStr = '\0'; 2162 return 0; 2163 } 2164 2165 /* Calculate the time classes */ 2166 dwMS = (dwMS + 500) / 1000; 2167 dwHours = dwMS / 3600; 2168 dwMS -= dwHours * 3600; 2169 dwMinutes = dwMS / 60; 2170 dwMS -= dwMinutes * 60; 2171 2172 szCopy[0] = '\0'; 2173 2174 if (dwHours) 2175 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, IDS_TIME_INTERVAL_HOURS, iDigits); 2176 2177 if (dwMinutes && iDigits) 2178 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, IDS_TIME_INTERVAL_MINUTES, iDigits); 2179 2180 if (iDigits) /* Always write seconds if we have significant digits */ 2181 SHLWAPI_WriteTimeClass(szCopy, dwMS, IDS_TIME_INTERVAL_SECONDS, iDigits); 2182 2183 lstrcpynW(lpszStr, szCopy, cchMax); 2184 iRet = strlenW(lpszStr); 2185 } 2186 return iRet; 2187 } 2188 2189 /************************************************************************* 2190 * StrIsIntlEqualA [SHLWAPI.@] 2191 * 2192 * Compare two strings. 2193 * 2194 * PARAMS 2195 * bCase [I] Whether to compare case sensitively 2196 * lpszStr [I] First string to compare 2197 * lpszComp [I] Second string to compare 2198 * iLen [I] Length to compare 2199 * 2200 * RETURNS 2201 * TRUE If the strings are equal. 2202 * FALSE Otherwise. 2203 */ 2204 BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp, 2205 int iLen) 2206 { 2207 DWORD dwFlags; 2208 2209 TRACE("(%d,%s,%s,%d)\n", bCase, 2210 debugstr_a(lpszStr), debugstr_a(lpszComp), iLen); 2211 2212 /* FIXME: This flag is undocumented and unknown by our CompareString. 2213 * We need a define for it. 2214 */ 2215 dwFlags = 0x10000000; 2216 if (!bCase) dwFlags |= NORM_IGNORECASE; 2217 2218 return (CompareStringA(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL); 2219 } 2220 2221 /************************************************************************* 2222 * StrIsIntlEqualW [SHLWAPI.@] 2223 * 2224 * See StrIsIntlEqualA. 2225 */ 2226 BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp, 2227 int iLen) 2228 { 2229 DWORD dwFlags; 2230 2231 TRACE("(%d,%s,%s,%d)\n", bCase, 2232 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen); 2233 2234 /* FIXME: This flag is undocumented and unknown by our CompareString. 2235 * We need a define for it. 2236 */ 2237 dwFlags = 0x10000000; 2238 if (!bCase) dwFlags |= NORM_IGNORECASE; 2239 2240 return (CompareStringW(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL); 2241 } 2242 2243 /************************************************************************* 2244 * @ [SHLWAPI.399] 2245 * 2246 * Copy a string to another string, up to a maximum number of characters. 2247 * 2248 * PARAMS 2249 * lpszDest [O] Destination string 2250 * lpszSrc [I] Source string 2251 * iLen [I] Maximum number of chars to copy 2252 * 2253 * RETURNS 2254 * Success: A pointer to the last character written to lpszDest. 2255 * Failure: lpszDest, if any arguments are invalid. 2256 */ 2257 LPSTR WINAPI StrCpyNXA(LPSTR lpszDest, LPCSTR lpszSrc, int iLen) 2258 { 2259 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen); 2260 2261 if (lpszDest && lpszSrc && iLen > 0) 2262 { 2263 while ((iLen-- > 1) && *lpszSrc) 2264 *lpszDest++ = *lpszSrc++; 2265 if (iLen >= 0) 2266 *lpszDest = '\0'; 2267 } 2268 return lpszDest; 2269 } 2270 2271 /************************************************************************* 2272 * @ [SHLWAPI.400] 2273 * 2274 * Unicode version of StrCpyNXA. 2275 */ 2276 LPWSTR WINAPI StrCpyNXW(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen) 2277 { 2278 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen); 2279 2280 if (lpszDest && lpszSrc && iLen > 0) 2281 { 2282 while ((iLen-- > 1) && *lpszSrc) 2283 *lpszDest++ = *lpszSrc++; 2284 if (iLen >= 0) 2285 *lpszDest = '\0'; 2286 } 2287 return lpszDest; 2288 } 2289 2290 /************************************************************************* 2291 * StrCmpLogicalW [SHLWAPI.@] 2292 * 2293 * Compare two strings, ignoring case and comparing digits as numbers. 2294 * 2295 * PARAMS 2296 * lpszStr [I] First string to compare 2297 * lpszComp [I] Second string to compare 2298 * iLen [I] Length to compare 2299 * 2300 * RETURNS 2301 * TRUE If the strings are equal. 2302 * FALSE Otherwise. 2303 */ 2304 INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp) 2305 { 2306 INT iDiff; 2307 2308 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp)); 2309 2310 if (lpszStr && lpszComp) 2311 { 2312 while (*lpszStr) 2313 { 2314 if (!*lpszComp) 2315 return 1; 2316 else if (isdigitW(*lpszStr)) 2317 { 2318 int iStr, iComp; 2319 2320 if (!isdigitW(*lpszComp)) 2321 return -1; 2322 2323 /* Compare the numbers */ 2324 StrToIntExW(lpszStr, 0, &iStr); 2325 StrToIntExW(lpszComp, 0, &iComp); 2326 2327 if (iStr < iComp) 2328 return -1; 2329 else if (iStr > iComp) 2330 return 1; 2331 2332 /* Skip */ 2333 while (isdigitW(*lpszStr)) 2334 lpszStr++; 2335 while (isdigitW(*lpszComp)) 2336 lpszComp++; 2337 } 2338 else if (isdigitW(*lpszComp)) 2339 return 1; 2340 else 2341 { 2342 iDiff = ChrCmpIW(*lpszStr,*lpszComp); 2343 if (iDiff > 0) 2344 return 1; 2345 else if (iDiff < 0) 2346 return -1; 2347 2348 lpszStr++; 2349 lpszComp++; 2350 } 2351 } 2352 if (*lpszComp) 2353 return -1; 2354 } 2355 return 0; 2356 } 2357 2358 /* Structure for formatting byte strings */ 2359 typedef struct tagSHLWAPI_BYTEFORMATS 2360 { 2361 LONGLONG dLimit; 2362 double dDivisor; 2363 double dNormaliser; 2364 int nDecimals; 2365 #ifdef __REACTOS__ 2366 UINT nFormatID; 2367 #else 2368 WCHAR wPrefix; 2369 #endif 2370 } SHLWAPI_BYTEFORMATS; 2371 2372 /************************************************************************* 2373 * StrFormatByteSizeW [SHLWAPI.@] 2374 * 2375 * Create a string containing an abbreviated byte count of up to 2^63-1. 2376 * 2377 * PARAMS 2378 * llBytes [I] Byte size to format 2379 * lpszDest [I] Destination for formatted string 2380 * cchMax [I] Size of lpszDest 2381 * 2382 * RETURNS 2383 * lpszDest. 2384 * 2385 * NOTES 2386 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW(). 2387 */ 2388 LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax) 2389 { 2390 #define KB ((ULONGLONG)1024) 2391 #define MB (KB*KB) 2392 #define GB (KB*KB*KB) 2393 #define TB (KB*KB*KB*KB) 2394 #define PB (KB*KB*KB*KB*KB) 2395 2396 static const SHLWAPI_BYTEFORMATS bfFormats[] = 2397 { 2398 #ifdef __REACTOS__ 2399 { 10*KB, 10.24, 100.0, 2, IDS_KB_FORMAT }, /* 10 KB */ 2400 { 100*KB, 102.4, 10.0, 1, IDS_KB_FORMAT }, /* 100 KB */ 2401 { 1000*KB, 1024.0, 1.0, 0, IDS_KB_FORMAT }, /* 1000 KB */ 2402 { 10*MB, 10485.76, 100.0, 2, IDS_MB_FORMAT }, /* 10 MB */ 2403 { 100*MB, 104857.6, 10.0, 1, IDS_MB_FORMAT }, /* 100 MB */ 2404 { 1000*MB, 1048576.0, 1.0, 0, IDS_MB_FORMAT }, /* 1000 MB */ 2405 { 10*GB, 10737418.24, 100.0, 2, IDS_GB_FORMAT }, /* 10 GB */ 2406 { 100*GB, 107374182.4, 10.0, 1, IDS_GB_FORMAT }, /* 100 GB */ 2407 { 1000*GB, 1073741824.0, 1.0, 0, IDS_GB_FORMAT }, /* 1000 GB */ 2408 { 10*TB, 10485.76, 100.0, 2, IDS_TB_FORMAT }, /* 10 TB */ 2409 { 100*TB, 104857.6, 10.0, 1, IDS_TB_FORMAT }, /* 100 TB */ 2410 { 1000*TB, 1048576.0, 1.0, 0, IDS_TB_FORMAT }, /* 1000 TB */ 2411 { 10*PB, 10737418.24, 100.00, 2, IDS_PB_FORMAT }, /* 10 PB */ 2412 { 100*PB, 107374182.4, 10.00, 1, IDS_PB_FORMAT }, /* 100 PB */ 2413 { 1000*PB, 1073741824.0, 1.00, 0, IDS_PB_FORMAT }, /* 1000 PB */ 2414 { 0, 10995116277.76, 100.00, 2, IDS_EB_FORMAT } /* EB's, catch all */ 2415 #else 2416 { 10*KB, 10.24, 100.0, 2, 'K' }, /* 10 KB */ 2417 { 100*KB, 102.4, 10.0, 1, 'K' }, /* 100 KB */ 2418 { 1000*KB, 1024.0, 1.0, 0, 'K' }, /* 1000 KB */ 2419 { 10*MB, 10485.76, 100.0, 2, 'M' }, /* 10 MB */ 2420 { 100*MB, 104857.6, 10.0, 1, 'M' }, /* 100 MB */ 2421 { 1000*MB, 1048576.0, 1.0, 0, 'M' }, /* 1000 MB */ 2422 { 10*GB, 10737418.24, 100.0, 2, 'G' }, /* 10 GB */ 2423 { 100*GB, 107374182.4, 10.0, 1, 'G' }, /* 100 GB */ 2424 { 1000*GB, 1073741824.0, 1.0, 0, 'G' }, /* 1000 GB */ 2425 { 10*TB, 10485.76, 100.0, 2, 'T' }, /* 10 TB */ 2426 { 100*TB, 104857.6, 10.0, 1, 'T' }, /* 100 TB */ 2427 { 1000*TB, 1048576.0, 1.0, 0, 'T' }, /* 1000 TB */ 2428 { 10*PB, 10737418.24, 100.00, 2, 'P' }, /* 10 PB */ 2429 { 100*PB, 107374182.4, 10.00, 1, 'P' }, /* 100 PB */ 2430 { 1000*PB, 1073741824.0, 1.00, 0, 'P' }, /* 1000 PB */ 2431 { 0, 10995116277.76, 100.00, 2, 'E' } /* EB's, catch all */ 2432 #endif 2433 }; 2434 #ifdef __REACTOS__ 2435 WCHAR szBuff[40], wszFormat[40]; 2436 #else 2437 WCHAR wszAdd[] = {' ','?','B',0}; 2438 #endif 2439 double dBytes; 2440 UINT i = 0; 2441 2442 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax); 2443 2444 if (!lpszDest || !cchMax) 2445 return lpszDest; 2446 2447 if (llBytes < 1024) /* 1K */ 2448 { 2449 WCHAR wszBytesFormat[64]; 2450 LoadStringW(shlwapi_hInstance, IDS_BYTES_FORMAT, wszBytesFormat, 64); 2451 snprintfW(lpszDest, cchMax, wszBytesFormat, (int)llBytes); 2452 return lpszDest; 2453 } 2454 2455 /* Note that if this loop completes without finding a match, i will be 2456 * pointing at the last entry, which is a catch all for > 1000 PB 2457 */ 2458 while (i < sizeof(bfFormats) / sizeof(SHLWAPI_BYTEFORMATS) - 1) 2459 { 2460 if (llBytes < bfFormats[i].dLimit) 2461 break; 2462 i++; 2463 } 2464 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above 2465 * this number we integer shift down by 1 MB first. The table above has 2466 * the divisors scaled down from the '< 10 TB' entry onwards, to account 2467 * for this. We also add a small fudge factor to get the correct result for 2468 * counts that lie exactly on a 1024 byte boundary. 2469 */ 2470 if (i > 8) 2471 dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by 1 MB */ 2472 else 2473 dBytes = (double)llBytes + 0.00001; 2474 2475 dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser; 2476 2477 #ifdef __REACTOS__ 2478 if (!FormatDouble(dBytes, bfFormats[i].nDecimals, szBuff, ARRAYSIZE(szBuff))) 2479 return NULL; 2480 LoadStringW(shlwapi_hInstance, bfFormats[i].nFormatID, wszFormat, ARRAYSIZE(wszFormat)); 2481 snprintfW(lpszDest, cchMax, wszFormat, szBuff); 2482 #else 2483 if (!FormatDouble(dBytes, bfFormats[i].nDecimals, lpszDest, cchMax)) 2484 return NULL; 2485 wszAdd[1] = bfFormats[i].wPrefix; 2486 StrCatBuffW(lpszDest, wszAdd, cchMax); 2487 #endif 2488 return lpszDest; 2489 } 2490 2491 /************************************************************************* 2492 * StrFormatByteSize64A [SHLWAPI.@] 2493 * 2494 * See StrFormatByteSizeW. 2495 */ 2496 LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax) 2497 { 2498 WCHAR wszBuff[32]; 2499 2500 StrFormatByteSizeW(llBytes, wszBuff, sizeof(wszBuff)/sizeof(WCHAR)); 2501 2502 if (lpszDest) 2503 WideCharToMultiByte(CP_ACP, 0, wszBuff, -1, lpszDest, cchMax, 0, 0); 2504 return lpszDest; 2505 } 2506 2507 /************************************************************************* 2508 * StrFormatByteSizeA [SHLWAPI.@] 2509 * 2510 * Create a string containing an abbreviated byte count of up to 2^31-1. 2511 * 2512 * PARAMS 2513 * dwBytes [I] Byte size to format 2514 * lpszDest [I] Destination for formatted string 2515 * cchMax [I] Size of lpszDest 2516 * 2517 * RETURNS 2518 * lpszDest. 2519 * 2520 * NOTES 2521 * The Ascii and Unicode versions of this function accept a different 2522 * integer type for dwBytes. See StrFormatByteSize64A(). 2523 */ 2524 LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax) 2525 { 2526 TRACE("(%d,%p,%d)\n", dwBytes, lpszDest, cchMax); 2527 2528 return StrFormatByteSize64A(dwBytes, lpszDest, cchMax); 2529 } 2530 2531 /************************************************************************* 2532 * @ [SHLWAPI.162] 2533 * 2534 * Remove a hanging lead byte from the end of a string, if present. 2535 * 2536 * PARAMS 2537 * lpStr [I] String to check for a hanging lead byte 2538 * size [I] Length of lpStr 2539 * 2540 * RETURNS 2541 * Success: The new length of the string. Any hanging lead bytes are removed. 2542 * Failure: 0, if any parameters are invalid. 2543 */ 2544 DWORD WINAPI SHTruncateString(LPSTR lpStr, DWORD size) 2545 { 2546 if (lpStr && size) 2547 { 2548 LPSTR lastByte = lpStr + size - 1; 2549 2550 while(lpStr < lastByte) 2551 lpStr += IsDBCSLeadByte(*lpStr) ? 2 : 1; 2552 2553 if(lpStr == lastByte && IsDBCSLeadByte(*lpStr)) 2554 { 2555 *lpStr = '\0'; 2556 size--; 2557 } 2558 return size; 2559 } 2560 return 0; 2561 } 2562 2563 /************************************************************************* 2564 * @ [SHLWAPI.203] 2565 * 2566 * Remove a single non-trailing ampersand ('&') from a string. 2567 * 2568 * PARAMS 2569 * lpszStr [I/O] String to remove ampersand from. 2570 * 2571 * RETURNS 2572 * The character after the first ampersand in lpszStr, or the first character 2573 * in lpszStr if there is no ampersand in the string. 2574 */ 2575 char WINAPI SHStripMneumonicA(LPCSTR lpszStr) 2576 { 2577 LPSTR lpszIter, lpszTmp; 2578 char ch; 2579 2580 TRACE("(%s)\n", debugstr_a(lpszStr)); 2581 2582 ch = *lpszStr; 2583 2584 if ((lpszIter = StrChrA(lpszStr, '&'))) 2585 { 2586 lpszTmp = CharNextA(lpszIter); 2587 if (*lpszTmp) 2588 { 2589 if (*lpszTmp != '&') 2590 ch = *lpszTmp; 2591 2592 memmove( lpszIter, lpszTmp, strlen(lpszTmp) + 1 ); 2593 } 2594 } 2595 2596 return ch; 2597 } 2598 2599 /************************************************************************* 2600 * @ [SHLWAPI.225] 2601 * 2602 * Unicode version of SHStripMneumonicA. 2603 */ 2604 WCHAR WINAPI SHStripMneumonicW(LPCWSTR lpszStr) 2605 { 2606 LPWSTR lpszIter, lpszTmp; 2607 WCHAR ch; 2608 2609 TRACE("(%s)\n", debugstr_w(lpszStr)); 2610 2611 ch = *lpszStr; 2612 2613 if ((lpszIter = StrChrW(lpszStr, '&'))) 2614 { 2615 lpszTmp = lpszIter + 1; 2616 if (*lpszTmp) 2617 { 2618 if (*lpszTmp != '&') 2619 ch = *lpszTmp; 2620 2621 memmove( lpszIter, lpszTmp, (strlenW(lpszTmp) + 1) * sizeof(WCHAR) ); 2622 } 2623 } 2624 2625 return ch; 2626 } 2627 2628 /************************************************************************* 2629 * @ [SHLWAPI.216] 2630 * 2631 * Convert an Ascii string to Unicode. 2632 * 2633 * PARAMS 2634 * dwCp [I] Code page for the conversion 2635 * lpSrcStr [I] Source Ascii string to convert 2636 * lpDstStr [O] Destination for converted Unicode string 2637 * iLen [I] Length of lpDstStr 2638 * 2639 * RETURNS 2640 * The return value of the MultiByteToWideChar() function called on lpSrcStr. 2641 */ 2642 DWORD WINAPI SHAnsiToUnicodeCP(DWORD dwCp, LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen) 2643 { 2644 DWORD dwRet; 2645 2646 dwRet = MultiByteToWideChar(dwCp, 0, lpSrcStr, -1, lpDstStr, iLen); 2647 TRACE("%s->%s,ret=%d\n", debugstr_a(lpSrcStr), debugstr_w(lpDstStr), dwRet); 2648 return dwRet; 2649 } 2650 2651 /************************************************************************* 2652 * @ [SHLWAPI.215] 2653 * 2654 * Convert an Ascii string to Unicode. 2655 * 2656 * PARAMS 2657 * lpSrcStr [I] Source Ascii string to convert 2658 * lpDstStr [O] Destination for converted Unicode string 2659 * iLen [I] Length of lpDstStr 2660 * 2661 * RETURNS 2662 * The return value of the MultiByteToWideChar() function called on lpSrcStr. 2663 * 2664 * NOTES 2665 * This function simply calls SHAnsiToUnicodeCP with code page CP_ACP. 2666 */ 2667 DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen) 2668 { 2669 return SHAnsiToUnicodeCP(CP_ACP, lpSrcStr, lpDstStr, iLen); 2670 } 2671 2672 /************************************************************************* 2673 * @ [SHLWAPI.218] 2674 * 2675 * Convert a Unicode string to Ascii. 2676 * 2677 * PARAMS 2678 * CodePage [I] Code page to use for the conversion 2679 * lpSrcStr [I] Source Unicode string to convert 2680 * lpDstStr [O] Destination for converted Ascii string 2681 * dstlen [I] Length of buffer at lpDstStr 2682 * 2683 * RETURNS 2684 * Success: The length in bytes of the result at lpDstStr (including the terminator) 2685 * Failure: When using CP_UTF8, CP_UTF7 or 0xc350 as codePage, 0 is returned and 2686 * the result is not nul-terminated. 2687 * When using a different codepage, the length in bytes of the truncated 2688 * result at lpDstStr (including the terminator) is returned and 2689 * lpDstStr is always nul-terminated. 2690 * 2691 */ 2692 DWORD WINAPI SHUnicodeToAnsiCP(UINT CodePage, LPCWSTR lpSrcStr, LPSTR lpDstStr, int dstlen) 2693 { 2694 static const WCHAR emptyW[] = { '\0' }; 2695 int len , reqLen; 2696 LPSTR mem; 2697 2698 if (!lpDstStr || !dstlen) 2699 return 0; 2700 2701 if (!lpSrcStr) 2702 lpSrcStr = emptyW; 2703 2704 *lpDstStr = '\0'; 2705 2706 len = strlenW(lpSrcStr) + 1; 2707 2708 switch (CodePage) 2709 { 2710 case CP_WINUNICODE: 2711 CodePage = CP_UTF8; /* Fall through... */ 2712 case 0x0000C350: /* FIXME: CP_ #define */ 2713 case CP_UTF7: 2714 case CP_UTF8: 2715 { 2716 DWORD dwMode = 0; 2717 INT lenW = len - 1; 2718 INT needed = dstlen - 1; 2719 HRESULT hr; 2720 2721 /* try the user supplied buffer first */ 2722 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &lenW, lpDstStr, &needed); 2723 if (hr == S_OK) 2724 { 2725 lpDstStr[needed] = '\0'; 2726 return needed + 1; 2727 } 2728 2729 /* user buffer too small. exclude termination and copy as much as possible */ 2730 lenW = len; 2731 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &lenW, NULL, &needed); 2732 needed++; 2733 mem = HeapAlloc(GetProcessHeap(), 0, needed); 2734 if (!mem) 2735 return 0; 2736 2737 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &len, mem, &needed); 2738 if (hr == S_OK) 2739 { 2740 reqLen = SHTruncateString(mem, dstlen); 2741 if (reqLen > 0) memcpy(lpDstStr, mem, reqLen-1); 2742 } 2743 HeapFree(GetProcessHeap(), 0, mem); 2744 return 0; 2745 } 2746 default: 2747 break; 2748 } 2749 2750 /* try the user supplied buffer first */ 2751 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, lpDstStr, dstlen, NULL, NULL); 2752 2753 if (!reqLen && GetLastError() == ERROR_INSUFFICIENT_BUFFER) 2754 { 2755 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, NULL, 0, NULL, NULL); 2756 if (reqLen) 2757 { 2758 mem = HeapAlloc(GetProcessHeap(), 0, reqLen); 2759 if (mem) 2760 { 2761 WideCharToMultiByte(CodePage, 0, lpSrcStr, len, mem, reqLen, NULL, NULL); 2762 2763 reqLen = SHTruncateString(mem, dstlen -1); 2764 reqLen++; 2765 2766 lstrcpynA(lpDstStr, mem, reqLen); 2767 HeapFree(GetProcessHeap(), 0, mem); 2768 lpDstStr[reqLen-1] = '\0'; 2769 } 2770 } 2771 } 2772 return reqLen; 2773 } 2774 2775 /************************************************************************* 2776 * @ [SHLWAPI.217] 2777 * 2778 * Convert a Unicode string to Ascii. 2779 * 2780 * PARAMS 2781 * lpSrcStr [I] Source Unicode string to convert 2782 * lpDstStr [O] Destination for converted Ascii string 2783 * iLen [O] Length of lpDstStr in characters 2784 * 2785 * RETURNS 2786 * See SHUnicodeToAnsiCP 2787 2788 * NOTES 2789 * This function simply calls SHUnicodeToAnsiCP() with CodePage = CP_ACP. 2790 */ 2791 INT WINAPI SHUnicodeToAnsi(LPCWSTR lpSrcStr, LPSTR lpDstStr, INT iLen) 2792 { 2793 return SHUnicodeToAnsiCP(CP_ACP, lpSrcStr, lpDstStr, iLen); 2794 } 2795 2796 /************************************************************************* 2797 * @ [SHLWAPI.345] 2798 * 2799 * Copy one string to another. 2800 * 2801 * PARAMS 2802 * lpszSrc [I] Source string to copy 2803 * lpszDst [O] Destination for copy 2804 * iLen [I] Length of lpszDst in characters 2805 * 2806 * RETURNS 2807 * The length of the copied string, including the terminating NUL. lpszDst 2808 * contains iLen characters of lpszSrc. 2809 */ 2810 DWORD WINAPI SHAnsiToAnsi(LPCSTR lpszSrc, LPSTR lpszDst, int iLen) 2811 { 2812 LPSTR lpszRet; 2813 2814 TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszSrc), lpszDst, iLen); 2815 2816 lpszRet = StrCpyNXA(lpszDst, lpszSrc, iLen); 2817 return lpszRet - lpszDst + 1; 2818 } 2819 2820 /************************************************************************* 2821 * @ [SHLWAPI.346] 2822 * 2823 * Unicode version of SSHAnsiToAnsi. 2824 */ 2825 DWORD WINAPI SHUnicodeToUnicode(LPCWSTR lpszSrc, LPWSTR lpszDst, int iLen) 2826 { 2827 LPWSTR lpszRet; 2828 2829 TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszSrc), lpszDst, iLen); 2830 2831 lpszRet = StrCpyNXW(lpszDst, lpszSrc, iLen); 2832 return lpszRet - lpszDst + 1; 2833 } 2834 2835 /************************************************************************* 2836 * @ [SHLWAPI.364] 2837 * 2838 * Determine if an Ascii string converts to Unicode and back identically. 2839 * 2840 * PARAMS 2841 * lpSrcStr [I] Source Unicode string to convert 2842 * lpDst [O] Destination for resulting Ascii string 2843 * iLen [I] Length of lpDst in characters 2844 * 2845 * RETURNS 2846 * TRUE, since Ascii strings always convert identically. 2847 */ 2848 BOOL WINAPI DoesStringRoundTripA(LPCSTR lpSrcStr, LPSTR lpDst, INT iLen) 2849 { 2850 lstrcpynA(lpDst, lpSrcStr, iLen); 2851 return TRUE; 2852 } 2853 2854 /************************************************************************* 2855 * @ [SHLWAPI.365] 2856 * 2857 * Determine if a Unicode string converts to Ascii and back identically. 2858 * 2859 * PARAMS 2860 * lpSrcStr [I] Source Unicode string to convert 2861 * lpDst [O] Destination for resulting Ascii string 2862 * iLen [I] Length of lpDst in characters 2863 * 2864 * RETURNS 2865 * TRUE, if lpSrcStr converts to Ascii and back identically, 2866 * FALSE otherwise. 2867 */ 2868 BOOL WINAPI DoesStringRoundTripW(LPCWSTR lpSrcStr, LPSTR lpDst, INT iLen) 2869 { 2870 WCHAR szBuff[MAX_PATH]; 2871 2872 SHUnicodeToAnsi(lpSrcStr, lpDst, iLen); 2873 SHAnsiToUnicode(lpDst, szBuff, MAX_PATH); 2874 return !strcmpW(lpSrcStr, szBuff); 2875 } 2876 2877 /************************************************************************* 2878 * SHLoadIndirectString [SHLWAPI.@] 2879 * 2880 * If passed a string that begins with '@', extract the string from the 2881 * appropriate resource, otherwise do a straight copy. 2882 * 2883 */ 2884 HRESULT WINAPI SHLoadIndirectString(LPCWSTR src, LPWSTR dst, UINT dst_len, void **reserved) 2885 { 2886 WCHAR *dllname = NULL; 2887 HMODULE hmod = NULL; 2888 HRESULT hr = E_FAIL; 2889 #ifdef __REACTOS__ 2890 WCHAR szExpanded[512]; 2891 #endif 2892 2893 TRACE("(%s %p %08x %p)\n", debugstr_w(src), dst, dst_len, reserved); 2894 2895 if(src[0] == '@') 2896 { 2897 WCHAR *index_str; 2898 int index; 2899 2900 #ifdef __REACTOS__ 2901 if (wcschr(src, '%') != NULL) 2902 { 2903 ExpandEnvironmentStringsW(src, szExpanded, ARRAY_SIZE(szExpanded)); 2904 src = szExpanded; 2905 } 2906 #endif 2907 dst[0] = 0; 2908 dllname = StrDupW(src + 1); 2909 index_str = strchrW(dllname, ','); 2910 2911 if(!index_str) goto end; 2912 2913 *index_str = 0; 2914 index_str++; 2915 index = atoiW(index_str); 2916 2917 #ifdef __REACTOS__ 2918 hmod = LoadLibraryExW(dllname, NULL, LOAD_LIBRARY_AS_DATAFILE); 2919 #else 2920 hmod = LoadLibraryW(dllname); 2921 #endif 2922 if(!hmod) goto end; 2923 2924 if(index < 0) 2925 { 2926 if(LoadStringW(hmod, -index, dst, dst_len)) 2927 hr = S_OK; 2928 } 2929 else 2930 FIXME("can't handle non-negative indices (%d)\n", index); 2931 } 2932 else 2933 { 2934 if(dst != src) 2935 lstrcpynW(dst, src, dst_len); 2936 hr = S_OK; 2937 } 2938 2939 TRACE("returning %s\n", debugstr_w(dst)); 2940 end: 2941 if(hmod) FreeLibrary(hmod); 2942 LocalFree(dllname); 2943 return hr; 2944 } 2945 2946 BOOL WINAPI IsCharSpaceA(CHAR c) 2947 { 2948 WORD CharType; 2949 return GetStringTypeA(GetSystemDefaultLCID(), CT_CTYPE1, &c, 1, &CharType) && (CharType & C1_SPACE); 2950 } 2951 2952 /************************************************************************* 2953 * @ [SHLWAPI.29] 2954 * 2955 * Determine if a Unicode character is a space. 2956 * 2957 * PARAMS 2958 * wc [I] Character to check. 2959 * 2960 * RETURNS 2961 * TRUE, if wc is a space, 2962 * FALSE otherwise. 2963 */ 2964 BOOL WINAPI IsCharSpaceW(WCHAR wc) 2965 { 2966 WORD CharType; 2967 2968 return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_SPACE); 2969 } 2970