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 iLen = lpszStr ? strlen(lpszStr) + 1 : 1; 1072 lpszRet = LocalAlloc(LMEM_FIXED, iLen); 1073 1074 if (lpszRet) 1075 { 1076 if (lpszStr) 1077 memcpy(lpszRet, lpszStr, iLen); 1078 else 1079 *lpszRet = '\0'; 1080 } 1081 return lpszRet; 1082 } 1083 1084 /************************************************************************* 1085 * StrDupW [SHLWAPI.@] 1086 * 1087 * See StrDupA. 1088 */ 1089 LPWSTR WINAPI StrDupW(LPCWSTR lpszStr) 1090 { 1091 int iLen; 1092 LPWSTR lpszRet; 1093 1094 TRACE("(%s)\n",debugstr_w(lpszStr)); 1095 1096 iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR); 1097 lpszRet = LocalAlloc(LMEM_FIXED, iLen); 1098 1099 if (lpszRet) 1100 { 1101 if (lpszStr) 1102 memcpy(lpszRet, lpszStr, iLen); 1103 else 1104 *lpszRet = '\0'; 1105 } 1106 return lpszRet; 1107 } 1108 1109 /************************************************************************* 1110 * SHLWAPI_StrSpnHelperA 1111 * 1112 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA 1113 */ 1114 static int SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch, 1115 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD), 1116 BOOL bInvert) 1117 { 1118 LPCSTR lpszRead = lpszStr; 1119 if (lpszStr && *lpszStr && lpszMatch) 1120 { 1121 while (*lpszRead) 1122 { 1123 LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead); 1124 1125 if (!bInvert && !lpszTest) 1126 break; 1127 if (bInvert && lpszTest) 1128 break; 1129 lpszRead = CharNextA(lpszRead); 1130 }; 1131 } 1132 return lpszRead - lpszStr; 1133 } 1134 1135 /************************************************************************* 1136 * StrSpnA [SHLWAPI.@] 1137 * 1138 * Find the length of the start of a string that contains only certain 1139 * characters. 1140 * 1141 * PARAMS 1142 * lpszStr [I] String to search 1143 * lpszMatch [I] Characters that can be in the substring 1144 * 1145 * RETURNS 1146 * The length of the part of lpszStr containing only chars from lpszMatch, 1147 * or 0 if any parameter is invalid. 1148 */ 1149 int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch) 1150 { 1151 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch)); 1152 1153 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE); 1154 } 1155 1156 /************************************************************************* 1157 * StrSpnW [SHLWAPI.@] 1158 * 1159 * See StrSpnA. 1160 */ 1161 int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch) 1162 { 1163 if (!lpszStr || !lpszMatch) return 0; 1164 return strspnW( lpszStr, lpszMatch ); 1165 } 1166 1167 /************************************************************************* 1168 * StrCSpnA [SHLWAPI.@] 1169 * 1170 * Find the length of the start of a string that does not contain certain 1171 * characters. 1172 * 1173 * PARAMS 1174 * lpszStr [I] String to search 1175 * lpszMatch [I] Characters that cannot be in the substring 1176 * 1177 * RETURNS 1178 * The length of the part of lpszStr containing only chars not in lpszMatch, 1179 * or 0 if any parameter is invalid. 1180 */ 1181 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch) 1182 { 1183 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch)); 1184 1185 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE); 1186 } 1187 1188 /************************************************************************* 1189 * StrCSpnW [SHLWAPI.@] 1190 * 1191 * See StrCSpnA. 1192 */ 1193 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch) 1194 { 1195 if (!lpszStr || !lpszMatch) return 0; 1196 return strcspnW( lpszStr, lpszMatch ); 1197 } 1198 1199 /************************************************************************* 1200 * StrCSpnIA [SHLWAPI.@] 1201 * 1202 * Find the length of the start of a string that does not contain certain 1203 * characters, ignoring case. 1204 * 1205 * PARAMS 1206 * lpszStr [I] String to search 1207 * lpszMatch [I] Characters that cannot be in the substring 1208 * 1209 * RETURNS 1210 * The length of the part of lpszStr containing only chars not in lpszMatch, 1211 * or 0 if any parameter is invalid. 1212 */ 1213 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch) 1214 { 1215 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch)); 1216 1217 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE); 1218 } 1219 1220 /************************************************************************* 1221 * StrCSpnIW [SHLWAPI.@] 1222 * 1223 * See StrCSpnIA. 1224 */ 1225 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch) 1226 { 1227 LPCWSTR lpszRead = lpszStr; 1228 1229 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch)); 1230 1231 if (lpszStr && *lpszStr && lpszMatch) 1232 { 1233 while (*lpszRead) 1234 { 1235 if (StrChrIW(lpszMatch, *lpszRead)) break; 1236 lpszRead++; 1237 } 1238 } 1239 return lpszRead - lpszStr; 1240 } 1241 1242 /************************************************************************* 1243 * StrPBrkA [SHLWAPI.@] 1244 * 1245 * Search a string for any of a group of characters. 1246 * 1247 * PARAMS 1248 * lpszStr [I] String to search 1249 * lpszMatch [I] Characters to match 1250 * 1251 * RETURNS 1252 * A pointer to the first matching character in lpszStr, or NULL if no 1253 * match was found. 1254 */ 1255 LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch) 1256 { 1257 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch)); 1258 1259 if (lpszStr && lpszMatch && *lpszMatch) 1260 { 1261 while (*lpszStr) 1262 { 1263 if (StrChrA(lpszMatch, *lpszStr)) 1264 return (LPSTR)lpszStr; 1265 lpszStr = CharNextA(lpszStr); 1266 } 1267 } 1268 return NULL; 1269 } 1270 1271 /************************************************************************* 1272 * StrPBrkW [SHLWAPI.@] 1273 * 1274 * See StrPBrkA. 1275 */ 1276 LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch) 1277 { 1278 if (!lpszStr || !lpszMatch) return NULL; 1279 return strpbrkW( lpszStr, lpszMatch ); 1280 } 1281 1282 /************************************************************************* 1283 * SHLWAPI_StrRChrHelperA 1284 * 1285 * Internal implementation of StrRChrA/StrRChrIA. 1286 */ 1287 static LPSTR SHLWAPI_StrRChrHelperA(LPCSTR lpszStr, 1288 LPCSTR lpszEnd, WORD ch, 1289 BOOL (WINAPI *pChrCmpFn)(WORD,WORD)) 1290 { 1291 LPCSTR lpszRet = NULL; 1292 1293 if (lpszStr) 1294 { 1295 WORD ch2; 1296 1297 if (!lpszEnd) 1298 lpszEnd = lpszStr + lstrlenA(lpszStr); 1299 1300 while (*lpszStr && lpszStr <= lpszEnd) 1301 { 1302 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr; 1303 1304 if (!pChrCmpFn(ch, ch2)) 1305 lpszRet = lpszStr; 1306 lpszStr = CharNextA(lpszStr); 1307 } 1308 } 1309 return (LPSTR)lpszRet; 1310 } 1311 1312 /************************************************************************** 1313 * StrRChrA [SHLWAPI.@] 1314 * 1315 * Find the last occurrence of a character in string. 1316 * 1317 * PARAMS 1318 * lpszStr [I] String to search in 1319 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr 1320 * ch [I] Character to search for. 1321 * 1322 * RETURNS 1323 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd, 1324 * or NULL if not found. 1325 * Failure: NULL, if any arguments are invalid. 1326 */ 1327 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch) 1328 { 1329 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch); 1330 1331 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA); 1332 } 1333 1334 /************************************************************************** 1335 * StrRChrW [SHLWAPI.@] 1336 * 1337 * See StrRChrA. 1338 */ 1339 LPWSTR WINAPI StrRChrW(LPCWSTR str, LPCWSTR end, WORD ch) 1340 { 1341 WCHAR *ret = NULL; 1342 1343 if (!str) return NULL; 1344 if (!end) end = str + strlenW(str); 1345 while (str < end) 1346 { 1347 if (*str == ch) ret = (WCHAR *)str; 1348 str++; 1349 } 1350 return ret; 1351 } 1352 1353 /************************************************************************** 1354 * StrRChrIA [SHLWAPI.@] 1355 * 1356 * Find the last occurrence of a character in string, ignoring case. 1357 * 1358 * PARAMS 1359 * lpszStr [I] String to search in 1360 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr 1361 * ch [I] Character to search for. 1362 * 1363 * RETURNS 1364 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd, 1365 * or NULL if not found. 1366 * Failure: NULL, if any arguments are invalid. 1367 */ 1368 LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch) 1369 { 1370 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch); 1371 1372 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA); 1373 } 1374 1375 /************************************************************************** 1376 * StrRChrIW [SHLWAPI.@] 1377 * 1378 * See StrRChrIA. 1379 */ 1380 LPWSTR WINAPI StrRChrIW(LPCWSTR str, LPCWSTR end, WORD ch) 1381 { 1382 WCHAR *ret = NULL; 1383 1384 if (!str) return NULL; 1385 if (!end) end = str + strlenW(str); 1386 while (str < end) 1387 { 1388 if (!ChrCmpIW(*str, ch)) ret = (WCHAR *)str; 1389 str++; 1390 } 1391 return ret; 1392 } 1393 1394 /************************************************************************* 1395 * StrCatBuffA [SHLWAPI.@] 1396 * 1397 * Concatenate two strings together. 1398 * 1399 * PARAMS 1400 * lpszStr [O] String to concatenate to 1401 * lpszCat [I] String to add to lpszCat 1402 * cchMax [I] Maximum number of characters for the whole string 1403 * 1404 * RETURNS 1405 * lpszStr. 1406 * 1407 * NOTES 1408 * cchMax determines the number of characters in the final length of the 1409 * string, not the number appended to lpszStr from lpszCat. 1410 */ 1411 LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax) 1412 { 1413 INT iLen; 1414 1415 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax); 1416 1417 if (!lpszStr) 1418 { 1419 WARN("Invalid lpszStr would crash under Win32!\n"); 1420 return NULL; 1421 } 1422 1423 iLen = strlen(lpszStr); 1424 cchMax -= iLen; 1425 1426 if (cchMax > 0) 1427 StrCpyNA(lpszStr + iLen, lpszCat, cchMax); 1428 return lpszStr; 1429 } 1430 1431 /************************************************************************* 1432 * StrCatBuffW [SHLWAPI.@] 1433 * 1434 * See StrCatBuffA. 1435 */ 1436 LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax) 1437 { 1438 INT iLen; 1439 1440 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax); 1441 1442 if (!lpszStr) 1443 { 1444 WARN("Invalid lpszStr would crash under Win32!\n"); 1445 return NULL; 1446 } 1447 1448 iLen = strlenW(lpszStr); 1449 cchMax -= iLen; 1450 1451 if (cchMax > 0) 1452 StrCpyNW(lpszStr + iLen, lpszCat, cchMax); 1453 return lpszStr; 1454 } 1455 1456 /************************************************************************* 1457 * StrRetToBufA [SHLWAPI.@] 1458 * 1459 * Convert a STRRET to a normal string. 1460 * 1461 * PARAMS 1462 * lpStrRet [O] STRRET to convert 1463 * pIdl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET 1464 * lpszDest [O] Destination for normal string 1465 * dwLen [I] Length of lpszDest 1466 * 1467 * RETURNS 1468 * Success: S_OK. lpszDest contains up to dwLen characters of the string. 1469 * If lpStrRet is of type STRRET_WSTR, its memory is freed with 1470 * CoTaskMemFree() and its type set to STRRET_CSTRA. 1471 * Failure: E_FAIL, if any parameters are invalid. 1472 */ 1473 HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, UINT len) 1474 { 1475 /* NOTE: 1476 * This routine is identical to that in dlls/shell32/shellstring.c. 1477 * It was duplicated because not every version of Shlwapi.dll exports 1478 * StrRetToBufA. If you change one routine, change them both. 1479 */ 1480 TRACE("dest=%p len=0x%x strret=%p pidl=%p\n", dest, len, src, pidl); 1481 1482 if (!src) 1483 { 1484 WARN("Invalid lpStrRet would crash under Win32!\n"); 1485 if (dest) 1486 *dest = '\0'; 1487 return E_FAIL; 1488 } 1489 1490 if (!dest || !len) 1491 return E_FAIL; 1492 1493 *dest = '\0'; 1494 1495 switch (src->uType) 1496 { 1497 case STRRET_WSTR: 1498 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL); 1499 CoTaskMemFree(src->u.pOleStr); 1500 break; 1501 1502 case STRRET_CSTR: 1503 lstrcpynA(dest, src->u.cStr, len); 1504 break; 1505 1506 case STRRET_OFFSET: 1507 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len); 1508 break; 1509 1510 default: 1511 FIXME("unknown type!\n"); 1512 return E_NOTIMPL; 1513 } 1514 return S_OK; 1515 } 1516 1517 /************************************************************************* 1518 * StrRetToBufW [SHLWAPI.@] 1519 * 1520 * See StrRetToBufA. 1521 */ 1522 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, UINT len) 1523 { 1524 TRACE("dest=%p len=0x%x strret=%p pidl=%p\n", dest, len, src, pidl); 1525 1526 if (!dest || !len) 1527 return E_FAIL; 1528 1529 if (!src) 1530 { 1531 WARN("Invalid lpStrRet would crash under Win32!\n"); 1532 if (dest) 1533 *dest = '\0'; 1534 return E_FAIL; 1535 } 1536 1537 *dest = '\0'; 1538 1539 switch (src->uType) { 1540 case STRRET_WSTR: { 1541 size_t dst_len; 1542 if (!src->u.pOleStr) 1543 return E_FAIL; 1544 dst_len = strlenW(src->u.pOleStr); 1545 memcpy(dest, src->u.pOleStr, min(dst_len, len-1) * sizeof(WCHAR)); 1546 dest[min(dst_len, len-1)] = 0; 1547 CoTaskMemFree(src->u.pOleStr); 1548 if (len <= dst_len) 1549 { 1550 dest[0] = 0; 1551 return E_NOT_SUFFICIENT_BUFFER; 1552 } 1553 break; 1554 } 1555 1556 case STRRET_CSTR: 1557 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len )) 1558 dest[len-1] = 0; 1559 break; 1560 1561 case STRRET_OFFSET: 1562 if (pidl) 1563 { 1564 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, 1565 dest, len )) 1566 dest[len-1] = 0; 1567 } 1568 break; 1569 1570 default: 1571 FIXME("unknown type!\n"); 1572 return E_NOTIMPL; 1573 } 1574 1575 return S_OK; 1576 } 1577 1578 /************************************************************************* 1579 * StrRetToStrA [SHLWAPI.@] 1580 * 1581 * Converts a STRRET to a normal string. 1582 * 1583 * PARAMS 1584 * lpStrRet [O] STRRET to convert 1585 * pidl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET 1586 * ppszName [O] Destination for converted string 1587 * 1588 * RETURNS 1589 * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc(). 1590 * Failure: E_FAIL, if any parameters are invalid. 1591 */ 1592 HRESULT WINAPI StrRetToStrA(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPSTR *ppszName) 1593 { 1594 HRESULT hRet = E_FAIL; 1595 1596 switch (lpStrRet->uType) 1597 { 1598 case STRRET_WSTR: 1599 hRet = _SHStrDupAW(lpStrRet->u.pOleStr, ppszName); 1600 CoTaskMemFree(lpStrRet->u.pOleStr); 1601 break; 1602 1603 case STRRET_CSTR: 1604 hRet = _SHStrDupAA(lpStrRet->u.cStr, ppszName); 1605 break; 1606 1607 case STRRET_OFFSET: 1608 hRet = _SHStrDupAA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName); 1609 break; 1610 1611 default: 1612 *ppszName = NULL; 1613 } 1614 1615 return hRet; 1616 } 1617 1618 /************************************************************************* 1619 * StrRetToStrW [SHLWAPI.@] 1620 * 1621 * See StrRetToStrA. 1622 */ 1623 HRESULT WINAPI StrRetToStrW(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPWSTR *ppszName) 1624 { 1625 HRESULT hRet = E_FAIL; 1626 1627 switch (lpStrRet->uType) 1628 { 1629 case STRRET_WSTR: 1630 hRet = SHStrDupW(lpStrRet->u.pOleStr, ppszName); 1631 CoTaskMemFree(lpStrRet->u.pOleStr); 1632 break; 1633 1634 case STRRET_CSTR: 1635 hRet = SHStrDupA(lpStrRet->u.cStr, ppszName); 1636 break; 1637 1638 case STRRET_OFFSET: 1639 hRet = SHStrDupA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName); 1640 break; 1641 1642 default: 1643 *ppszName = NULL; 1644 } 1645 1646 return hRet; 1647 } 1648 1649 /* Create an ASCII string copy using SysAllocString() */ 1650 static HRESULT _SHStrDupAToBSTR(LPCSTR src, BSTR *pBstrOut) 1651 { 1652 *pBstrOut = NULL; 1653 1654 if (src) 1655 { 1656 INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0); 1657 WCHAR* szTemp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 1658 1659 if (szTemp) 1660 { 1661 MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len); 1662 *pBstrOut = SysAllocString(szTemp); 1663 HeapFree(GetProcessHeap(), 0, szTemp); 1664 1665 if (*pBstrOut) 1666 return S_OK; 1667 } 1668 } 1669 return E_OUTOFMEMORY; 1670 } 1671 1672 /************************************************************************* 1673 * StrRetToBSTR [SHLWAPI.@] 1674 * 1675 * Converts a STRRET to a BSTR. 1676 * 1677 * PARAMS 1678 * lpStrRet [O] STRRET to convert 1679 * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSET 1680 * pBstrOut [O] Destination for converted BSTR 1681 * 1682 * RETURNS 1683 * Success: S_OK. pBstrOut contains the new string. 1684 * Failure: E_FAIL, if any parameters are invalid. 1685 */ 1686 HRESULT WINAPI StrRetToBSTR(STRRET *lpStrRet, LPCITEMIDLIST pidl, BSTR* pBstrOut) 1687 { 1688 HRESULT hRet = E_FAIL; 1689 1690 switch (lpStrRet->uType) 1691 { 1692 case STRRET_WSTR: 1693 *pBstrOut = SysAllocString(lpStrRet->u.pOleStr); 1694 if (*pBstrOut) 1695 hRet = S_OK; 1696 CoTaskMemFree(lpStrRet->u.pOleStr); 1697 break; 1698 1699 case STRRET_CSTR: 1700 hRet = _SHStrDupAToBSTR(lpStrRet->u.cStr, pBstrOut); 1701 break; 1702 1703 case STRRET_OFFSET: 1704 hRet = _SHStrDupAToBSTR(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, pBstrOut); 1705 break; 1706 1707 default: 1708 *pBstrOut = NULL; 1709 } 1710 1711 return hRet; 1712 } 1713 1714 /************************************************************************* 1715 * StrFormatKBSizeA [SHLWAPI.@] 1716 * 1717 * Create a formatted string containing a byte count in Kilobytes. 1718 * 1719 * PARAMS 1720 * llBytes [I] Byte size to format 1721 * lpszDest [I] Destination for formatted string 1722 * cchMax [I] Size of lpszDest 1723 * 1724 * RETURNS 1725 * lpszDest. 1726 */ 1727 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax) 1728 { 1729 WCHAR wszBuf[256]; 1730 1731 if (!StrFormatKBSizeW(llBytes, wszBuf, 256)) 1732 return NULL; 1733 if (!WideCharToMultiByte(CP_ACP, 0, wszBuf, -1, lpszDest, cchMax, NULL, NULL)) 1734 return NULL; 1735 return lpszDest; 1736 } 1737 1738 /************************************************************************* 1739 * StrFormatKBSizeW [SHLWAPI.@] 1740 * 1741 * See StrFormatKBSizeA. 1742 */ 1743 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax) 1744 { 1745 static const WCHAR kb[] = {' ','K','B',0}; 1746 LONGLONG llKB = (llBytes + 1023) >> 10; 1747 int len; 1748 1749 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax); 1750 1751 if (!FormatInt(llKB, lpszDest, cchMax)) 1752 return NULL; 1753 1754 len = lstrlenW(lpszDest); 1755 if (cchMax - len < 4) 1756 return NULL; 1757 lstrcatW(lpszDest, kb); 1758 return lpszDest; 1759 } 1760 1761 /************************************************************************* 1762 * StrNCatA [SHLWAPI.@] 1763 * 1764 * Concatenate two strings together. 1765 * 1766 * PARAMS 1767 * lpszStr [O] String to concatenate to 1768 * lpszCat [I] String to add to lpszCat 1769 * cchMax [I] Maximum number of characters to concatenate 1770 * 1771 * RETURNS 1772 * lpszStr. 1773 * 1774 * NOTES 1775 * cchMax determines the number of characters that are appended to lpszStr, 1776 * not the total length of the string. 1777 */ 1778 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax) 1779 { 1780 LPSTR lpszRet = lpszStr; 1781 1782 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax); 1783 1784 if (!lpszStr) 1785 { 1786 WARN("Invalid lpszStr would crash under Win32!\n"); 1787 return NULL; 1788 } 1789 1790 StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax); 1791 return lpszRet; 1792 } 1793 1794 /************************************************************************* 1795 * StrNCatW [SHLWAPI.@] 1796 * 1797 * See StrNCatA. 1798 */ 1799 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax) 1800 { 1801 LPWSTR lpszRet = lpszStr; 1802 1803 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax); 1804 1805 if (!lpszStr) 1806 { 1807 WARN("Invalid lpszStr would crash under Win32\n"); 1808 return NULL; 1809 } 1810 1811 StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax); 1812 return lpszRet; 1813 } 1814 1815 /************************************************************************* 1816 * StrTrimA [SHLWAPI.@] 1817 * 1818 * Remove characters from the start and end of a string. 1819 * 1820 * PARAMS 1821 * lpszStr [O] String to remove characters from 1822 * lpszTrim [I] Characters to remove from lpszStr 1823 * 1824 * RETURNS 1825 * TRUE If lpszStr was valid and modified 1826 * FALSE Otherwise 1827 */ 1828 BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim) 1829 { 1830 DWORD dwLen; 1831 LPSTR lpszRead = lpszStr; 1832 BOOL bRet = FALSE; 1833 1834 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim)); 1835 1836 if (lpszRead && *lpszRead) 1837 { 1838 while (*lpszRead && StrChrA(lpszTrim, *lpszRead)) 1839 lpszRead = CharNextA(lpszRead); /* Skip leading matches */ 1840 1841 dwLen = strlen(lpszRead); 1842 1843 if (lpszRead != lpszStr) 1844 { 1845 memmove(lpszStr, lpszRead, dwLen + 1); 1846 bRet = TRUE; 1847 } 1848 if (dwLen > 0) 1849 { 1850 lpszRead = lpszStr + dwLen; 1851 while (StrChrA(lpszTrim, lpszRead[-1])) 1852 lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */ 1853 1854 if (lpszRead != lpszStr + dwLen) 1855 { 1856 *lpszRead = '\0'; 1857 bRet = TRUE; 1858 } 1859 } 1860 } 1861 return bRet; 1862 } 1863 1864 /************************************************************************* 1865 * StrTrimW [SHLWAPI.@] 1866 * 1867 * See StrTrimA. 1868 */ 1869 BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim) 1870 { 1871 DWORD dwLen; 1872 LPWSTR lpszRead = lpszStr; 1873 BOOL bRet = FALSE; 1874 1875 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim)); 1876 1877 if (lpszRead && *lpszRead) 1878 { 1879 while (*lpszRead && StrChrW(lpszTrim, *lpszRead)) lpszRead++; 1880 1881 dwLen = strlenW(lpszRead); 1882 1883 if (lpszRead != lpszStr) 1884 { 1885 memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR)); 1886 bRet = TRUE; 1887 } 1888 if (dwLen > 0) 1889 { 1890 lpszRead = lpszStr + dwLen; 1891 while (StrChrW(lpszTrim, lpszRead[-1])) 1892 lpszRead--; /* Skip trailing matches */ 1893 1894 if (lpszRead != lpszStr + dwLen) 1895 { 1896 *lpszRead = '\0'; 1897 bRet = TRUE; 1898 } 1899 } 1900 } 1901 return bRet; 1902 } 1903 1904 /************************************************************************* 1905 * _SHStrDupAA [INTERNAL] 1906 * 1907 * Duplicates a ASCII string to ASCII. The destination buffer is allocated. 1908 */ 1909 static HRESULT _SHStrDupAA(LPCSTR src, LPSTR * dest) 1910 { 1911 HRESULT hr; 1912 int len = 0; 1913 1914 if (src) { 1915 len = lstrlenA(src) + 1; 1916 *dest = CoTaskMemAlloc(len); 1917 } else { 1918 *dest = NULL; 1919 } 1920 1921 if (*dest) { 1922 lstrcpynA(*dest,src, len); 1923 hr = S_OK; 1924 } else { 1925 hr = E_OUTOFMEMORY; 1926 } 1927 1928 TRACE("%s->(%p)\n", debugstr_a(src), *dest); 1929 return hr; 1930 } 1931 1932 /************************************************************************* 1933 * SHStrDupA [SHLWAPI.@] 1934 * 1935 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc(). 1936 * 1937 * PARAMS 1938 * lpszStr [I] String to copy 1939 * lppszDest [O] Destination for the new string copy 1940 * 1941 * RETURNS 1942 * Success: S_OK. lppszDest contains the new string in Unicode format. 1943 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation 1944 * fails. 1945 */ 1946 HRESULT WINAPI SHStrDupA(LPCSTR lpszStr, LPWSTR * lppszDest) 1947 { 1948 HRESULT hRet; 1949 int len = 0; 1950 1951 if (lpszStr) 1952 { 1953 len = MultiByteToWideChar(CP_ACP, 0, lpszStr, -1, NULL, 0) * sizeof(WCHAR); 1954 *lppszDest = CoTaskMemAlloc(len); 1955 } 1956 else 1957 *lppszDest = NULL; 1958 1959 if (*lppszDest) 1960 { 1961 MultiByteToWideChar(CP_ACP, 0, lpszStr, -1, *lppszDest, len/sizeof(WCHAR)); 1962 hRet = S_OK; 1963 } 1964 else 1965 hRet = E_OUTOFMEMORY; 1966 1967 TRACE("%s->(%p)\n", debugstr_a(lpszStr), *lppszDest); 1968 return hRet; 1969 } 1970 1971 /************************************************************************* 1972 * _SHStrDupAW [INTERNAL] 1973 * 1974 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated. 1975 */ 1976 static HRESULT _SHStrDupAW(LPCWSTR src, LPSTR * dest) 1977 { 1978 HRESULT hr; 1979 int len = 0; 1980 1981 if (src) { 1982 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL); 1983 *dest = CoTaskMemAlloc(len); 1984 } else { 1985 *dest = NULL; 1986 } 1987 1988 if (*dest) { 1989 WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL); 1990 hr = S_OK; 1991 } else { 1992 hr = E_OUTOFMEMORY; 1993 } 1994 1995 TRACE("%s->(%p)\n", debugstr_w(src), *dest); 1996 return hr; 1997 } 1998 1999 /************************************************************************* 2000 * SHStrDupW [SHLWAPI.@] 2001 * 2002 * See SHStrDupA. 2003 */ 2004 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest) 2005 { 2006 HRESULT hr; 2007 int len = 0; 2008 2009 if (src) { 2010 len = (lstrlenW(src) + 1) * sizeof(WCHAR); 2011 *dest = CoTaskMemAlloc(len); 2012 } else { 2013 *dest = NULL; 2014 } 2015 2016 if (*dest) { 2017 memcpy(*dest, src, len); 2018 hr = S_OK; 2019 } else { 2020 hr = E_OUTOFMEMORY; 2021 } 2022 2023 TRACE("%s->(%p)\n", debugstr_w(src), *dest); 2024 return hr; 2025 } 2026 2027 /************************************************************************* 2028 * SHLWAPI_WriteReverseNum 2029 * 2030 * Internal helper for SHLWAPI_WriteTimeClass. 2031 */ 2032 static inline LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum) 2033 { 2034 *lpszOut-- = '\0'; 2035 2036 /* Write a decimal number to a string, backwards */ 2037 do 2038 { 2039 DWORD dwNextDigit = dwNum % 10; 2040 *lpszOut-- = '0' + dwNextDigit; 2041 dwNum = (dwNum - dwNextDigit) / 10; 2042 } while (dwNum > 0); 2043 2044 return lpszOut; 2045 } 2046 2047 /************************************************************************* 2048 * SHLWAPI_FormatSignificant 2049 * 2050 * Internal helper for SHLWAPI_WriteTimeClass. 2051 */ 2052 static inline int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits) 2053 { 2054 /* Zero non significant digits, return remaining significant digits */ 2055 while (*lpszNum) 2056 { 2057 lpszNum++; 2058 if (--dwDigits == 0) 2059 { 2060 while (*lpszNum) 2061 *lpszNum++ = '0'; 2062 return 0; 2063 } 2064 } 2065 return dwDigits; 2066 } 2067 2068 /************************************************************************* 2069 * SHLWAPI_WriteTimeClass 2070 * 2071 * Internal helper for StrFromTimeIntervalW. 2072 */ 2073 static int SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue, 2074 UINT uClassStringId, int iDigits) 2075 { 2076 WCHAR szBuff[64], *szOut = szBuff + 32; 2077 2078 szOut = SHLWAPI_WriteReverseNum(szOut, dwValue); 2079 iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits); 2080 *szOut = ' '; 2081 LoadStringW(shlwapi_hInstance, uClassStringId, szBuff + 32, 32); 2082 strcatW(lpszOut, szOut); 2083 return iDigits; 2084 } 2085 2086 /************************************************************************* 2087 * StrFromTimeIntervalA [SHLWAPI.@] 2088 * 2089 * Format a millisecond time interval into a string 2090 * 2091 * PARAMS 2092 * lpszStr [O] Output buffer for formatted time interval 2093 * cchMax [I] Size of lpszStr 2094 * dwMS [I] Number of milliseconds 2095 * iDigits [I] Number of digits to print 2096 * 2097 * RETURNS 2098 * The length of the formatted string, or 0 if any parameter is invalid. 2099 * 2100 * NOTES 2101 * This implementation mimics the Win32 behaviour of always writing a leading 2102 * space before the time interval begins. 2103 * 2104 * iDigits is used to provide approximate times if accuracy is not important. 2105 * This number of digits will be written of the first non-zero time class 2106 * (hours/minutes/seconds). If this does not complete the time classification, 2107 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded). 2108 * If there are digits remaining following the writing of a time class, the 2109 * next time class will be written. 2110 * 2111 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the 2112 * following will result from the given values of iDigits: 2113 * 2114 *| iDigits 1 2 3 4 5 ... 2115 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ... 2116 */ 2117 INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS, 2118 int iDigits) 2119 { 2120 INT iRet = 0; 2121 2122 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits); 2123 2124 if (lpszStr && cchMax) 2125 { 2126 WCHAR szBuff[128]; 2127 StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits); 2128 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0); 2129 } 2130 return iRet; 2131 } 2132 2133 2134 /************************************************************************* 2135 * StrFromTimeIntervalW [SHLWAPI.@] 2136 * 2137 * See StrFromTimeIntervalA. 2138 */ 2139 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS, 2140 int iDigits) 2141 { 2142 INT iRet = 0; 2143 2144 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits); 2145 2146 if (lpszStr && cchMax) 2147 { 2148 WCHAR szCopy[128]; 2149 DWORD dwHours, dwMinutes; 2150 2151 if (!iDigits || cchMax == 1) 2152 { 2153 *lpszStr = '\0'; 2154 return 0; 2155 } 2156 2157 /* Calculate the time classes */ 2158 dwMS = (dwMS + 500) / 1000; 2159 dwHours = dwMS / 3600; 2160 dwMS -= dwHours * 3600; 2161 dwMinutes = dwMS / 60; 2162 dwMS -= dwMinutes * 60; 2163 2164 szCopy[0] = '\0'; 2165 2166 if (dwHours) 2167 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, IDS_TIME_INTERVAL_HOURS, iDigits); 2168 2169 if (dwMinutes && iDigits) 2170 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, IDS_TIME_INTERVAL_MINUTES, iDigits); 2171 2172 if (iDigits) /* Always write seconds if we have significant digits */ 2173 SHLWAPI_WriteTimeClass(szCopy, dwMS, IDS_TIME_INTERVAL_SECONDS, iDigits); 2174 2175 lstrcpynW(lpszStr, szCopy, cchMax); 2176 iRet = strlenW(lpszStr); 2177 } 2178 return iRet; 2179 } 2180 2181 /************************************************************************* 2182 * StrIsIntlEqualA [SHLWAPI.@] 2183 * 2184 * Compare two strings. 2185 * 2186 * PARAMS 2187 * bCase [I] Whether to compare case sensitively 2188 * lpszStr [I] First string to compare 2189 * lpszComp [I] Second string to compare 2190 * iLen [I] Length to compare 2191 * 2192 * RETURNS 2193 * TRUE If the strings are equal. 2194 * FALSE Otherwise. 2195 */ 2196 BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp, 2197 int iLen) 2198 { 2199 DWORD dwFlags; 2200 2201 TRACE("(%d,%s,%s,%d)\n", bCase, 2202 debugstr_a(lpszStr), debugstr_a(lpszComp), iLen); 2203 2204 /* FIXME: This flag is undocumented and unknown by our CompareString. 2205 * We need a define for it. 2206 */ 2207 dwFlags = 0x10000000; 2208 if (!bCase) dwFlags |= NORM_IGNORECASE; 2209 2210 return (CompareStringA(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL); 2211 } 2212 2213 /************************************************************************* 2214 * StrIsIntlEqualW [SHLWAPI.@] 2215 * 2216 * See StrIsIntlEqualA. 2217 */ 2218 BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp, 2219 int iLen) 2220 { 2221 DWORD dwFlags; 2222 2223 TRACE("(%d,%s,%s,%d)\n", bCase, 2224 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen); 2225 2226 /* FIXME: This flag is undocumented and unknown by our CompareString. 2227 * We need a define for it. 2228 */ 2229 dwFlags = 0x10000000; 2230 if (!bCase) dwFlags |= NORM_IGNORECASE; 2231 2232 return (CompareStringW(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL); 2233 } 2234 2235 /************************************************************************* 2236 * @ [SHLWAPI.399] 2237 * 2238 * Copy a string to another string, up to a maximum number of characters. 2239 * 2240 * PARAMS 2241 * lpszDest [O] Destination string 2242 * lpszSrc [I] Source string 2243 * iLen [I] Maximum number of chars to copy 2244 * 2245 * RETURNS 2246 * Success: A pointer to the last character written to lpszDest. 2247 * Failure: lpszDest, if any arguments are invalid. 2248 */ 2249 LPSTR WINAPI StrCpyNXA(LPSTR lpszDest, LPCSTR lpszSrc, int iLen) 2250 { 2251 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen); 2252 2253 if (lpszDest && lpszSrc && iLen > 0) 2254 { 2255 while ((iLen-- > 1) && *lpszSrc) 2256 *lpszDest++ = *lpszSrc++; 2257 if (iLen >= 0) 2258 *lpszDest = '\0'; 2259 } 2260 return lpszDest; 2261 } 2262 2263 /************************************************************************* 2264 * @ [SHLWAPI.400] 2265 * 2266 * Unicode version of StrCpyNXA. 2267 */ 2268 LPWSTR WINAPI StrCpyNXW(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen) 2269 { 2270 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen); 2271 2272 if (lpszDest && lpszSrc && iLen > 0) 2273 { 2274 while ((iLen-- > 1) && *lpszSrc) 2275 *lpszDest++ = *lpszSrc++; 2276 if (iLen >= 0) 2277 *lpszDest = '\0'; 2278 } 2279 return lpszDest; 2280 } 2281 2282 /************************************************************************* 2283 * StrCmpLogicalW [SHLWAPI.@] 2284 * 2285 * Compare two strings, ignoring case and comparing digits as numbers. 2286 * 2287 * PARAMS 2288 * lpszStr [I] First string to compare 2289 * lpszComp [I] Second string to compare 2290 * iLen [I] Length to compare 2291 * 2292 * RETURNS 2293 * TRUE If the strings are equal. 2294 * FALSE Otherwise. 2295 */ 2296 INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp) 2297 { 2298 INT iDiff; 2299 2300 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp)); 2301 2302 if (lpszStr && lpszComp) 2303 { 2304 while (*lpszStr) 2305 { 2306 if (!*lpszComp) 2307 return 1; 2308 else if (isdigitW(*lpszStr)) 2309 { 2310 int iStr, iComp; 2311 2312 if (!isdigitW(*lpszComp)) 2313 return -1; 2314 2315 /* Compare the numbers */ 2316 StrToIntExW(lpszStr, 0, &iStr); 2317 StrToIntExW(lpszComp, 0, &iComp); 2318 2319 if (iStr < iComp) 2320 return -1; 2321 else if (iStr > iComp) 2322 return 1; 2323 2324 /* Skip */ 2325 while (isdigitW(*lpszStr)) 2326 lpszStr++; 2327 while (isdigitW(*lpszComp)) 2328 lpszComp++; 2329 } 2330 else if (isdigitW(*lpszComp)) 2331 return 1; 2332 else 2333 { 2334 iDiff = ChrCmpIW(*lpszStr,*lpszComp); 2335 if (iDiff > 0) 2336 return 1; 2337 else if (iDiff < 0) 2338 return -1; 2339 2340 lpszStr++; 2341 lpszComp++; 2342 } 2343 } 2344 if (*lpszComp) 2345 return -1; 2346 } 2347 return 0; 2348 } 2349 2350 /* Structure for formatting byte strings */ 2351 typedef struct tagSHLWAPI_BYTEFORMATS 2352 { 2353 LONGLONG dLimit; 2354 double dDivisor; 2355 double dNormaliser; 2356 int nDecimals; 2357 WCHAR wPrefix; 2358 } SHLWAPI_BYTEFORMATS; 2359 2360 /************************************************************************* 2361 * StrFormatByteSizeW [SHLWAPI.@] 2362 * 2363 * Create a string containing an abbreviated byte count of up to 2^63-1. 2364 * 2365 * PARAMS 2366 * llBytes [I] Byte size to format 2367 * lpszDest [I] Destination for formatted string 2368 * cchMax [I] Size of lpszDest 2369 * 2370 * RETURNS 2371 * lpszDest. 2372 * 2373 * NOTES 2374 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW(). 2375 */ 2376 LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax) 2377 { 2378 #define KB ((ULONGLONG)1024) 2379 #define MB (KB*KB) 2380 #define GB (KB*KB*KB) 2381 #define TB (KB*KB*KB*KB) 2382 #define PB (KB*KB*KB*KB*KB) 2383 2384 static const SHLWAPI_BYTEFORMATS bfFormats[] = 2385 { 2386 { 10*KB, 10.24, 100.0, 2, 'K' }, /* 10 KB */ 2387 { 100*KB, 102.4, 10.0, 1, 'K' }, /* 100 KB */ 2388 { 1000*KB, 1024.0, 1.0, 0, 'K' }, /* 1000 KB */ 2389 { 10*MB, 10485.76, 100.0, 2, 'M' }, /* 10 MB */ 2390 { 100*MB, 104857.6, 10.0, 1, 'M' }, /* 100 MB */ 2391 { 1000*MB, 1048576.0, 1.0, 0, 'M' }, /* 1000 MB */ 2392 { 10*GB, 10737418.24, 100.0, 2, 'G' }, /* 10 GB */ 2393 { 100*GB, 107374182.4, 10.0, 1, 'G' }, /* 100 GB */ 2394 { 1000*GB, 1073741824.0, 1.0, 0, 'G' }, /* 1000 GB */ 2395 { 10*TB, 10485.76, 100.0, 2, 'T' }, /* 10 TB */ 2396 { 100*TB, 104857.6, 10.0, 1, 'T' }, /* 100 TB */ 2397 { 1000*TB, 1048576.0, 1.0, 0, 'T' }, /* 1000 TB */ 2398 { 10*PB, 10737418.24, 100.00, 2, 'P' }, /* 10 PB */ 2399 { 100*PB, 107374182.4, 10.00, 1, 'P' }, /* 100 PB */ 2400 { 1000*PB, 1073741824.0, 1.00, 0, 'P' }, /* 1000 PB */ 2401 { 0, 10995116277.76, 100.00, 2, 'E' } /* EB's, catch all */ 2402 }; 2403 WCHAR wszAdd[] = {' ','?','B',0}; 2404 double dBytes; 2405 UINT i = 0; 2406 2407 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax); 2408 2409 if (!lpszDest || !cchMax) 2410 return lpszDest; 2411 2412 if (llBytes < 1024) /* 1K */ 2413 { 2414 WCHAR wszBytesFormat[64]; 2415 LoadStringW(shlwapi_hInstance, IDS_BYTES_FORMAT, wszBytesFormat, 64); 2416 snprintfW(lpszDest, cchMax, wszBytesFormat, (int)llBytes); 2417 return lpszDest; 2418 } 2419 2420 /* Note that if this loop completes without finding a match, i will be 2421 * pointing at the last entry, which is a catch all for > 1000 PB 2422 */ 2423 while (i < sizeof(bfFormats) / sizeof(SHLWAPI_BYTEFORMATS) - 1) 2424 { 2425 if (llBytes < bfFormats[i].dLimit) 2426 break; 2427 i++; 2428 } 2429 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above 2430 * this number we integer shift down by 1 MB first. The table above has 2431 * the divisors scaled down from the '< 10 TB' entry onwards, to account 2432 * for this. We also add a small fudge factor to get the correct result for 2433 * counts that lie exactly on a 1024 byte boundary. 2434 */ 2435 if (i > 8) 2436 dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by 1 MB */ 2437 else 2438 dBytes = (double)llBytes + 0.00001; 2439 2440 dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser; 2441 2442 if (!FormatDouble(dBytes, bfFormats[i].nDecimals, lpszDest, cchMax)) 2443 return NULL; 2444 wszAdd[1] = bfFormats[i].wPrefix; 2445 StrCatBuffW(lpszDest, wszAdd, cchMax); 2446 return lpszDest; 2447 } 2448 2449 /************************************************************************* 2450 * StrFormatByteSize64A [SHLWAPI.@] 2451 * 2452 * See StrFormatByteSizeW. 2453 */ 2454 LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax) 2455 { 2456 WCHAR wszBuff[32]; 2457 2458 StrFormatByteSizeW(llBytes, wszBuff, sizeof(wszBuff)/sizeof(WCHAR)); 2459 2460 if (lpszDest) 2461 WideCharToMultiByte(CP_ACP, 0, wszBuff, -1, lpszDest, cchMax, 0, 0); 2462 return lpszDest; 2463 } 2464 2465 /************************************************************************* 2466 * StrFormatByteSizeA [SHLWAPI.@] 2467 * 2468 * Create a string containing an abbreviated byte count of up to 2^31-1. 2469 * 2470 * PARAMS 2471 * dwBytes [I] Byte size to format 2472 * lpszDest [I] Destination for formatted string 2473 * cchMax [I] Size of lpszDest 2474 * 2475 * RETURNS 2476 * lpszDest. 2477 * 2478 * NOTES 2479 * The Ascii and Unicode versions of this function accept a different 2480 * integer type for dwBytes. See StrFormatByteSize64A(). 2481 */ 2482 LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax) 2483 { 2484 TRACE("(%d,%p,%d)\n", dwBytes, lpszDest, cchMax); 2485 2486 return StrFormatByteSize64A(dwBytes, lpszDest, cchMax); 2487 } 2488 2489 /************************************************************************* 2490 * @ [SHLWAPI.162] 2491 * 2492 * Remove a hanging lead byte from the end of a string, if present. 2493 * 2494 * PARAMS 2495 * lpStr [I] String to check for a hanging lead byte 2496 * size [I] Length of lpStr 2497 * 2498 * RETURNS 2499 * Success: The new length of the string. Any hanging lead bytes are removed. 2500 * Failure: 0, if any parameters are invalid. 2501 */ 2502 DWORD WINAPI SHTruncateString(LPSTR lpStr, DWORD size) 2503 { 2504 if (lpStr && size) 2505 { 2506 LPSTR lastByte = lpStr + size - 1; 2507 2508 while(lpStr < lastByte) 2509 lpStr += IsDBCSLeadByte(*lpStr) ? 2 : 1; 2510 2511 if(lpStr == lastByte && IsDBCSLeadByte(*lpStr)) 2512 { 2513 *lpStr = '\0'; 2514 size--; 2515 } 2516 return size; 2517 } 2518 return 0; 2519 } 2520 2521 /************************************************************************* 2522 * @ [SHLWAPI.203] 2523 * 2524 * Remove a single non-trailing ampersand ('&') from a string. 2525 * 2526 * PARAMS 2527 * lpszStr [I/O] String to remove ampersand from. 2528 * 2529 * RETURNS 2530 * The character after the first ampersand in lpszStr, or the first character 2531 * in lpszStr if there is no ampersand in the string. 2532 */ 2533 char WINAPI SHStripMneumonicA(LPCSTR lpszStr) 2534 { 2535 LPSTR lpszIter, lpszTmp; 2536 char ch; 2537 2538 TRACE("(%s)\n", debugstr_a(lpszStr)); 2539 2540 ch = *lpszStr; 2541 2542 if ((lpszIter = StrChrA(lpszStr, '&'))) 2543 { 2544 lpszTmp = CharNextA(lpszIter); 2545 if (*lpszTmp) 2546 { 2547 if (*lpszTmp != '&') 2548 ch = *lpszTmp; 2549 2550 memmove( lpszIter, lpszTmp, strlen(lpszTmp) + 1 ); 2551 } 2552 } 2553 2554 return ch; 2555 } 2556 2557 /************************************************************************* 2558 * @ [SHLWAPI.225] 2559 * 2560 * Unicode version of SHStripMneumonicA. 2561 */ 2562 WCHAR WINAPI SHStripMneumonicW(LPCWSTR lpszStr) 2563 { 2564 LPWSTR lpszIter, lpszTmp; 2565 WCHAR ch; 2566 2567 TRACE("(%s)\n", debugstr_w(lpszStr)); 2568 2569 ch = *lpszStr; 2570 2571 if ((lpszIter = StrChrW(lpszStr, '&'))) 2572 { 2573 lpszTmp = lpszIter + 1; 2574 if (*lpszTmp) 2575 { 2576 if (*lpszTmp != '&') 2577 ch = *lpszTmp; 2578 2579 memmove( lpszIter, lpszTmp, (strlenW(lpszTmp) + 1) * sizeof(WCHAR) ); 2580 } 2581 } 2582 2583 return ch; 2584 } 2585 2586 /************************************************************************* 2587 * @ [SHLWAPI.216] 2588 * 2589 * Convert an Ascii string to Unicode. 2590 * 2591 * PARAMS 2592 * dwCp [I] Code page for the conversion 2593 * lpSrcStr [I] Source Ascii string to convert 2594 * lpDstStr [O] Destination for converted Unicode string 2595 * iLen [I] Length of lpDstStr 2596 * 2597 * RETURNS 2598 * The return value of the MultiByteToWideChar() function called on lpSrcStr. 2599 */ 2600 DWORD WINAPI SHAnsiToUnicodeCP(DWORD dwCp, LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen) 2601 { 2602 DWORD dwRet; 2603 2604 dwRet = MultiByteToWideChar(dwCp, 0, lpSrcStr, -1, lpDstStr, iLen); 2605 TRACE("%s->%s,ret=%d\n", debugstr_a(lpSrcStr), debugstr_w(lpDstStr), dwRet); 2606 return dwRet; 2607 } 2608 2609 /************************************************************************* 2610 * @ [SHLWAPI.215] 2611 * 2612 * Convert an Ascii string to Unicode. 2613 * 2614 * PARAMS 2615 * lpSrcStr [I] Source Ascii string to convert 2616 * lpDstStr [O] Destination for converted Unicode string 2617 * iLen [I] Length of lpDstStr 2618 * 2619 * RETURNS 2620 * The return value of the MultiByteToWideChar() function called on lpSrcStr. 2621 * 2622 * NOTES 2623 * This function simply calls SHAnsiToUnicodeCP with code page CP_ACP. 2624 */ 2625 DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen) 2626 { 2627 return SHAnsiToUnicodeCP(CP_ACP, lpSrcStr, lpDstStr, iLen); 2628 } 2629 2630 /************************************************************************* 2631 * @ [SHLWAPI.218] 2632 * 2633 * Convert a Unicode string to Ascii. 2634 * 2635 * PARAMS 2636 * CodePage [I] Code page to use for the conversion 2637 * lpSrcStr [I] Source Unicode string to convert 2638 * lpDstStr [O] Destination for converted Ascii string 2639 * dstlen [I] Length of buffer at lpDstStr 2640 * 2641 * RETURNS 2642 * Success: The length in bytes of the result at lpDstStr (including the terminator) 2643 * Failure: When using CP_UTF8, CP_UTF7 or 0xc350 as codePage, 0 is returned and 2644 * the result is not nul-terminated. 2645 * When using a different codepage, the length in bytes of the truncated 2646 * result at lpDstStr (including the terminator) is returned and 2647 * lpDstStr is always nul-terminated. 2648 * 2649 */ 2650 DWORD WINAPI SHUnicodeToAnsiCP(UINT CodePage, LPCWSTR lpSrcStr, LPSTR lpDstStr, int dstlen) 2651 { 2652 static const WCHAR emptyW[] = { '\0' }; 2653 int len , reqLen; 2654 LPSTR mem; 2655 2656 if (!lpDstStr || !dstlen) 2657 return 0; 2658 2659 if (!lpSrcStr) 2660 lpSrcStr = emptyW; 2661 2662 *lpDstStr = '\0'; 2663 2664 len = strlenW(lpSrcStr) + 1; 2665 2666 switch (CodePage) 2667 { 2668 case CP_WINUNICODE: 2669 CodePage = CP_UTF8; /* Fall through... */ 2670 case 0x0000C350: /* FIXME: CP_ #define */ 2671 case CP_UTF7: 2672 case CP_UTF8: 2673 { 2674 DWORD dwMode = 0; 2675 INT lenW = len - 1; 2676 INT needed = dstlen - 1; 2677 HRESULT hr; 2678 2679 /* try the user supplied buffer first */ 2680 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &lenW, lpDstStr, &needed); 2681 if (hr == S_OK) 2682 { 2683 lpDstStr[needed] = '\0'; 2684 return needed + 1; 2685 } 2686 2687 /* user buffer too small. exclude termination and copy as much as possible */ 2688 lenW = len; 2689 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &lenW, NULL, &needed); 2690 needed++; 2691 mem = HeapAlloc(GetProcessHeap(), 0, needed); 2692 if (!mem) 2693 return 0; 2694 2695 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &len, mem, &needed); 2696 if (hr == S_OK) 2697 { 2698 reqLen = SHTruncateString(mem, dstlen); 2699 if (reqLen > 0) memcpy(lpDstStr, mem, reqLen-1); 2700 } 2701 HeapFree(GetProcessHeap(), 0, mem); 2702 return 0; 2703 } 2704 default: 2705 break; 2706 } 2707 2708 /* try the user supplied buffer first */ 2709 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, lpDstStr, dstlen, NULL, NULL); 2710 2711 if (!reqLen && GetLastError() == ERROR_INSUFFICIENT_BUFFER) 2712 { 2713 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, NULL, 0, NULL, NULL); 2714 if (reqLen) 2715 { 2716 mem = HeapAlloc(GetProcessHeap(), 0, reqLen); 2717 if (mem) 2718 { 2719 WideCharToMultiByte(CodePage, 0, lpSrcStr, len, mem, reqLen, NULL, NULL); 2720 2721 reqLen = SHTruncateString(mem, dstlen -1); 2722 reqLen++; 2723 2724 lstrcpynA(lpDstStr, mem, reqLen); 2725 HeapFree(GetProcessHeap(), 0, mem); 2726 lpDstStr[reqLen-1] = '\0'; 2727 } 2728 } 2729 } 2730 return reqLen; 2731 } 2732 2733 /************************************************************************* 2734 * @ [SHLWAPI.217] 2735 * 2736 * Convert a Unicode string to Ascii. 2737 * 2738 * PARAMS 2739 * lpSrcStr [I] Source Unicode string to convert 2740 * lpDstStr [O] Destination for converted Ascii string 2741 * iLen [O] Length of lpDstStr in characters 2742 * 2743 * RETURNS 2744 * See SHUnicodeToAnsiCP 2745 2746 * NOTES 2747 * This function simply calls SHUnicodeToAnsiCP() with CodePage = CP_ACP. 2748 */ 2749 INT WINAPI SHUnicodeToAnsi(LPCWSTR lpSrcStr, LPSTR lpDstStr, INT iLen) 2750 { 2751 return SHUnicodeToAnsiCP(CP_ACP, lpSrcStr, lpDstStr, iLen); 2752 } 2753 2754 /************************************************************************* 2755 * @ [SHLWAPI.345] 2756 * 2757 * Copy one string to another. 2758 * 2759 * PARAMS 2760 * lpszSrc [I] Source string to copy 2761 * lpszDst [O] Destination for copy 2762 * iLen [I] Length of lpszDst in characters 2763 * 2764 * RETURNS 2765 * The length of the copied string, including the terminating NUL. lpszDst 2766 * contains iLen characters of lpszSrc. 2767 */ 2768 DWORD WINAPI SHAnsiToAnsi(LPCSTR lpszSrc, LPSTR lpszDst, int iLen) 2769 { 2770 LPSTR lpszRet; 2771 2772 TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszSrc), lpszDst, iLen); 2773 2774 lpszRet = StrCpyNXA(lpszDst, lpszSrc, iLen); 2775 return lpszRet - lpszDst + 1; 2776 } 2777 2778 /************************************************************************* 2779 * @ [SHLWAPI.346] 2780 * 2781 * Unicode version of SSHAnsiToAnsi. 2782 */ 2783 DWORD WINAPI SHUnicodeToUnicode(LPCWSTR lpszSrc, LPWSTR lpszDst, int iLen) 2784 { 2785 LPWSTR lpszRet; 2786 2787 TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszSrc), lpszDst, iLen); 2788 2789 lpszRet = StrCpyNXW(lpszDst, lpszSrc, iLen); 2790 return lpszRet - lpszDst + 1; 2791 } 2792 2793 /************************************************************************* 2794 * @ [SHLWAPI.364] 2795 * 2796 * Determine if an Ascii string converts to Unicode and back identically. 2797 * 2798 * PARAMS 2799 * lpSrcStr [I] Source Unicode string to convert 2800 * lpDst [O] Destination for resulting Ascii string 2801 * iLen [I] Length of lpDst in characters 2802 * 2803 * RETURNS 2804 * TRUE, since Ascii strings always convert identically. 2805 */ 2806 BOOL WINAPI DoesStringRoundTripA(LPCSTR lpSrcStr, LPSTR lpDst, INT iLen) 2807 { 2808 lstrcpynA(lpDst, lpSrcStr, iLen); 2809 return TRUE; 2810 } 2811 2812 /************************************************************************* 2813 * @ [SHLWAPI.365] 2814 * 2815 * Determine if a Unicode string converts to Ascii and back identically. 2816 * 2817 * PARAMS 2818 * lpSrcStr [I] Source Unicode string to convert 2819 * lpDst [O] Destination for resulting Ascii string 2820 * iLen [I] Length of lpDst in characters 2821 * 2822 * RETURNS 2823 * TRUE, if lpSrcStr converts to Ascii and back identically, 2824 * FALSE otherwise. 2825 */ 2826 BOOL WINAPI DoesStringRoundTripW(LPCWSTR lpSrcStr, LPSTR lpDst, INT iLen) 2827 { 2828 WCHAR szBuff[MAX_PATH]; 2829 2830 SHUnicodeToAnsi(lpSrcStr, lpDst, iLen); 2831 SHAnsiToUnicode(lpDst, szBuff, MAX_PATH); 2832 return !strcmpW(lpSrcStr, szBuff); 2833 } 2834 2835 /************************************************************************* 2836 * SHLoadIndirectString [SHLWAPI.@] 2837 * 2838 * If passed a string that begins with '@', extract the string from the 2839 * appropriate resource, otherwise do a straight copy. 2840 * 2841 */ 2842 HRESULT WINAPI SHLoadIndirectString(LPCWSTR src, LPWSTR dst, UINT dst_len, void **reserved) 2843 { 2844 WCHAR *dllname = NULL; 2845 HMODULE hmod = NULL; 2846 HRESULT hr = E_FAIL; 2847 2848 TRACE("(%s %p %08x %p)\n", debugstr_w(src), dst, dst_len, reserved); 2849 2850 if(src[0] == '@') 2851 { 2852 WCHAR *index_str; 2853 int index; 2854 2855 dst[0] = 0; 2856 dllname = StrDupW(src + 1); 2857 index_str = strchrW(dllname, ','); 2858 2859 if(!index_str) goto end; 2860 2861 *index_str = 0; 2862 index_str++; 2863 index = atoiW(index_str); 2864 2865 hmod = LoadLibraryW(dllname); 2866 if(!hmod) goto end; 2867 2868 if(index < 0) 2869 { 2870 if(LoadStringW(hmod, -index, dst, dst_len)) 2871 hr = S_OK; 2872 } 2873 else 2874 FIXME("can't handle non-negative indices (%d)\n", index); 2875 } 2876 else 2877 { 2878 if(dst != src) 2879 lstrcpynW(dst, src, dst_len); 2880 hr = S_OK; 2881 } 2882 2883 TRACE("returning %s\n", debugstr_w(dst)); 2884 end: 2885 if(hmod) FreeLibrary(hmod); 2886 LocalFree(dllname); 2887 return hr; 2888 } 2889 2890 BOOL WINAPI IsCharSpaceA(CHAR c) 2891 { 2892 WORD CharType; 2893 return GetStringTypeA(GetSystemDefaultLCID(), CT_CTYPE1, &c, 1, &CharType) && (CharType & C1_SPACE); 2894 } 2895 2896 /************************************************************************* 2897 * @ [SHLWAPI.29] 2898 * 2899 * Determine if a Unicode character is a space. 2900 * 2901 * PARAMS 2902 * wc [I] Character to check. 2903 * 2904 * RETURNS 2905 * TRUE, if wc is a space, 2906 * FALSE otherwise. 2907 */ 2908 BOOL WINAPI IsCharSpaceW(WCHAR wc) 2909 { 2910 WORD CharType; 2911 2912 return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_SPACE); 2913 } 2914