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