Changeset 8584 for trunk/src/shlwapi/path.c
- Timestamp:
- Jun 7, 2002, 10:02:20 AM (23 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/shlwapi/path.c
r8047 r8584 1 1 /* 2 2 * Path Functions 3 * 4 * Copyright 1999, 2000 Juergen Schmied 5 * Copyright 2001, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 3 20 */ 4 21 … … 15 32 #define NO_SHLWAPI_STREAM 16 33 #include "shlwapi.h" 17 #include " debugtools.h"34 #include "wine/debug.h" 18 35 #include "ordinal.h" 19 36 20 DEFAULT_DEBUG_CHANNEL(shell); 21 22 INT __cdecl _wtoi(LPWSTR string); 23 24 #define isSlash(x) ((x)=='\\' || (x)=='/') 25 /* 26 ########## Combining and Constructing paths ########## 37 WINE_DEFAULT_DEBUG_CHANNEL(shell); 38 39 /* function pointers for GET_FUNC macro; these need to be global because of gcc bug */ 40 #ifdef __WIN32OS2__ 41 static BOOL (* WINAPI pIsNetDrive)(DWORD); 42 #else 43 static BOOL (WINAPI *pIsNetDrive)(DWORD); 44 #endif 45 46 /************************************************************************* 47 * PathAppendA [SHLWAPI.@] 48 * 49 * Append one path to another. 50 * 51 * PARAMS 52 * lpszPath [O] Initial part of path 53 * lpszAppend [I] Path to append 54 * 55 * RETURNS 56 * Success: TRUE. lpszPath contains the newly created path. 57 * Failure: FALSE, if either path is NULL, or PathCombineA fails. 58 * 59 * NOTES 60 * lpszAppend must contain at least one backslash ('\') if not NULL. 61 * Because PathCombineA is used to join the paths, the resulting 62 * path is also canonicalized. 63 */ 64 BOOL WINAPI PathAppendA (LPSTR lpszPath, LPCSTR lpszAppend) 65 { 66 TRACE("(%s,%s)\n",debugstr_a(lpszPath), debugstr_a(lpszAppend)); 67 68 if (lpszPath && lpszAppend) 69 { 70 while (*lpszAppend == '\\') 71 lpszAppend++; 72 if (PathCombineA(lpszPath, lpszPath, lpszAppend)) 73 return TRUE; 74 } 75 return FALSE; 76 } 77 78 /************************************************************************* 79 * PathAppendW [SHLWAPI.@] 80 * 81 * See PathAppendA. 82 */ 83 BOOL WINAPI PathAppendW(LPWSTR lpszPath, LPCWSTR lpszAppend) 84 { 85 TRACE("(%s,%s)\n",debugstr_w(lpszPath), debugstr_w(lpszAppend)); 86 87 if (lpszPath && lpszAppend) 88 { 89 while (*lpszAppend == '\\') 90 lpszAppend++; 91 if (PathCombineW(lpszPath, lpszPath, lpszAppend)) 92 return TRUE; 93 } 94 return FALSE; 95 } 96 97 /************************************************************************* 98 * PathCombineA [SHLWAPI.@] 99 * 100 * Combine two paths together. 101 * 102 * PARAMS 103 * lpszDest [O] Destination for combined path 104 * lpszDir [I] Directory path 105 * liszFile [I] File path 106 * 107 * RETURNS 108 * Success: The output path 109 * Failure: NULL, if inputs are invalid. 110 * 111 * NOTES 112 * lpszDest should be at least MAX_PATH in size, and may point to the same 113 * memory location as lpszDir. The combined path is canonicalised. 114 */ 115 LPSTR WINAPI PathCombineA(LPSTR lpszDest, LPCSTR lpszDir, LPCSTR lpszFile) 116 { 117 TRACE("(%p,%s,%s)\n", lpszDest, debugstr_a(lpszDir), debugstr_a(lpszFile)); 118 119 if (!lpszDest || (!lpszDir && !lpszFile)) 120 return NULL; /* Invalid parameters */ 121 else 122 { 123 WCHAR szDest[MAX_PATH]; 124 WCHAR szDir[MAX_PATH]; 125 WCHAR szFile[MAX_PATH]; 126 if (lpszDir) 127 MultiByteToWideChar(0,0,lpszDir,-1,szDir,MAX_PATH); 128 if (lpszFile) 129 MultiByteToWideChar(0,0,lpszFile,-1,szFile,MAX_PATH); 130 PathCombineW(szDest, lpszDir ? szDir : NULL, lpszFile ? szFile : NULL); 131 WideCharToMultiByte(0,0,szDest,-1,lpszDest,MAX_PATH,0,0); 132 } 133 return lpszDest; 134 } 135 136 /************************************************************************* 137 * PathCombineW [SHLWAPI.@] 138 * 139 * See PathCombineA. 140 */ 141 LPWSTR WINAPI PathCombineW(LPWSTR lpszDest, LPCWSTR lpszDir, LPCWSTR lpszFile) 142 { 143 WCHAR szTemp[MAX_PATH]; 144 BOOL bUseBoth = FALSE, bStrip = FALSE; 145 146 TRACE("(%p,%s,%s)\n", lpszDest, debugstr_w(lpszDir), debugstr_w(lpszFile)); 147 148 if (!lpszDest || (!lpszDir && !lpszFile)) 149 return lpszDest; /* Invalid parameters */ 150 151 if (!lpszFile || !*lpszFile) 152 { 153 /* Use dir only */ 154 strncpyW(szTemp, lpszDir, MAX_PATH); 155 } 156 else if (!lpszDir || !*lpszDir || !PathIsRelativeW(lpszFile)) 157 { 158 if (!lpszDir || !*lpszDir || *lpszFile != '\\' || PathIsUNCW(lpszFile)) 159 { 160 /* Use file only */ 161 strncpyW(szTemp, lpszFile, MAX_PATH); 162 } 163 else 164 { 165 bUseBoth = TRUE; 166 bStrip = TRUE; 167 } 168 } 169 else 170 bUseBoth = TRUE; 171 172 if (bUseBoth) 173 { 174 strncpyW(szTemp, lpszDir, MAX_PATH); 175 if (bStrip) 176 { 177 PathStripToRootW(szTemp); 178 lpszFile++; /* Skip '\' */ 179 } 180 if (!PathAddBackslashW(szTemp)) 181 return NULL; 182 if (strlenW(szTemp) + strlenW(lpszFile) >= MAX_PATH) 183 return NULL; 184 strcatW(szTemp, lpszFile); 185 } 186 187 PathCanonicalizeW(lpszDest, szTemp); 188 return lpszDest; 189 } 190 191 /************************************************************************* 192 * PathAddBackslashA [SHLWAPI.@] 193 * 194 * Append a backslash ('\') to a path if one doesn't exist. 195 * 196 * PARAMS 197 * lpszPath [O] The path to append a backslash to. 198 * 199 * RETURNS 200 * Success: The position of the last backslash in the path. 201 * Failure: NULL, if lpszPath is NULL or the path is too large. 202 */ 203 LPSTR WINAPI PathAddBackslashA(LPSTR lpszPath) 204 { 205 int iLen; 206 207 TRACE("(%s)\n",debugstr_a(lpszPath)); 208 209 if (!lpszPath || (iLen = strlen(lpszPath)) >= MAX_PATH) 210 return NULL; 211 212 if (iLen) 213 { 214 lpszPath += iLen; 215 if (lpszPath[-1] != '\\') 216 { 217 *lpszPath++ = '\\'; 218 *lpszPath = '\0'; 219 } 220 } 221 return lpszPath; 222 } 223 224 /************************************************************************* 225 * PathAddBackslashW [SHLWAPI.@] 226 * 227 * See PathAddBackslashA. 228 */ 229 LPWSTR WINAPI PathAddBackslashW( LPWSTR lpszPath ) 230 { 231 int iLen; 232 233 TRACE("(%s)\n",debugstr_w(lpszPath)); 234 235 if (!lpszPath || (iLen = strlenW(lpszPath)) >= MAX_PATH) 236 return NULL; 237 238 if (iLen) 239 { 240 lpszPath += iLen; 241 if (lpszPath[-1] != '\\') 242 { 243 *lpszPath++ = '\\'; 244 *lpszPath = '\0'; 245 } 246 } 247 return lpszPath; 248 } 249 250 /************************************************************************* 251 * PathBuildRootA [SHLWAPI.@] 252 * 253 * Create a root drive string (e.g. "A:\") from a drive number. 254 * 255 * PARAMS 256 * lpszPath [O] Destination for the drive string 257 * 258 * RETURNS 259 * lpszPath 260 * 261 * NOTES 262 * If lpszPath is NULL or drive is invalid, nothing is written to lpszPath. 263 */ 264 LPSTR WINAPI PathBuildRootA(LPSTR lpszPath, int drive) 265 { 266 TRACE("(%p,%d)\n", debugstr_a(lpszPath), drive); 267 268 if (lpszPath && drive >= 0 && drive < 26) 269 { 270 lpszPath[0] = 'A' + drive; 271 lpszPath[1] = ':'; 272 lpszPath[2] = '\\'; 273 lpszPath[3] = '\0'; 274 } 275 return lpszPath; 276 } 277 278 /************************************************************************* 279 * PathBuildRootW [SHLWAPI.@] 280 * 281 * See PathBuildRootA. 282 */ 283 LPWSTR WINAPI PathBuildRootW(LPWSTR lpszPath, int drive) 284 { 285 TRACE("(%p,%d)\n",debugstr_w(lpszPath), drive); 286 287 if (lpszPath && drive >= 0 && drive < 26) 288 { 289 lpszPath[0] = 'A' + drive; 290 lpszPath[1] = ':'; 291 lpszPath[2] = '\\'; 292 lpszPath[3] = '\0'; 293 } 294 return lpszPath; 295 } 296 297 /************************************************************************* 298 * PathFindFileNameA [SHLWAPI.@] 299 * 300 * Locate the start of the file name in a path 301 * 302 * PARAMS 303 * lpszPath [I] Path to search 304 * 305 * RETURNS 306 * A pointer to the first character of the file name 307 */ 308 LPSTR WINAPI PathFindFileNameA(LPCSTR lpszPath) 309 { 310 LPCSTR lastSlash = lpszPath; 311 312 TRACE("(%s)\n",debugstr_a(lpszPath)); 313 314 while (lpszPath && *lpszPath) 315 { 316 if ((*lpszPath == '\\' || *lpszPath == '/' || *lpszPath == ':') && 317 lpszPath[1] && lpszPath[1] != '\\' && lpszPath[1] != '/') 318 lastSlash = lpszPath + 1; 319 lpszPath = CharNextA(lpszPath); 320 } 321 return (LPSTR)lastSlash; 322 } 323 324 /************************************************************************* 325 * PathFindFileNameW [SHLWAPI.@] 326 * 327 * See PathFindFileNameA. 328 */ 329 LPWSTR WINAPI PathFindFileNameW(LPCWSTR lpszPath) 330 { 331 LPCWSTR lastSlash = lpszPath; 332 333 TRACE("(%s)\n",debugstr_w(lpszPath)); 334 335 while (lpszPath && *lpszPath) 336 { 337 if ((*lpszPath == '\\' || *lpszPath == '/' || *lpszPath == ':') && 338 lpszPath[1] && lpszPath[1] != '\\' && lpszPath[1] != '/') 339 lastSlash = lpszPath + 1; 340 lpszPath = CharNextW(lpszPath); 341 } 342 return (LPWSTR)lastSlash; 343 } 344 345 /************************************************************************* 346 * PathFindExtensionA [SHLWAPI.@] 347 * 348 * Locate the start of the file extension in a path 349 * 350 * PARAMS 351 * lpszPath [I] The path to search 352 * 353 * RETURNS 354 * A pointer to the first character of the extension, the end of 355 * the string if the path has no extension, or NULL If lpszPath is NULL 356 */ 357 LPSTR WINAPI PathFindExtensionA( LPCSTR lpszPath ) 358 { 359 LPCSTR lastpoint = NULL; 360 361 TRACE("(%s)\n", debugstr_a(lpszPath)); 362 363 if (lpszPath) 364 { 365 while (*lpszPath) 366 { 367 if (*lpszPath == '\\' || *lpszPath==' ') 368 lastpoint = NULL; 369 else if (*lpszPath == '.') 370 lastpoint = lpszPath; 371 lpszPath = CharNextA(lpszPath); 372 } 373 } 374 return (LPSTR)(lastpoint ? lastpoint : lpszPath); 375 } 376 377 /************************************************************************* 378 * PathFindExtensionW [SHLWAPI.@] 379 * 380 * See PathFindExtensionA. 381 */ 382 LPWSTR WINAPI PathFindExtensionW( LPCWSTR lpszPath ) 383 { 384 LPCWSTR lastpoint = NULL; 385 386 TRACE("(%s)\n", debugstr_w(lpszPath)); 387 388 if (lpszPath) 389 { 390 while (*lpszPath) 391 { 392 if (*lpszPath == '\\' || *lpszPath==' ') 393 lastpoint = NULL; 394 else if (*lpszPath == '.') 395 lastpoint = lpszPath; 396 lpszPath = CharNextW(lpszPath); 397 } 398 } 399 return (LPWSTR)(lastpoint ? lastpoint : lpszPath); 400 } 401 402 /************************************************************************* 403 * PathGetArgsA [SHLWAPI.@] 404 * 405 * Find the next argument in a string delimited by spaces. 406 * 407 * PARAMS 408 * lpszPath [I] The string to search for arguments in 409 * 410 * RETURNS 411 * The start of the next argument in lpszPath, or NULL if lpszPath is NULL 412 * 413 * NOTES 414 * Spaces in quoted strings are ignored as delimiters. 415 */ 416 LPSTR WINAPI PathGetArgsA(LPCSTR lpszPath) 417 { 418 BOOL bSeenQuote = FALSE; 419 420 TRACE("(%s)\n",debugstr_a(lpszPath)); 421 422 if (lpszPath) 423 { 424 while (*lpszPath) 425 { 426 if ((*lpszPath==' ') && !bSeenQuote) 427 return (LPSTR)lpszPath + 1; 428 if (*lpszPath == '"') 429 bSeenQuote = !bSeenQuote; 430 lpszPath = CharNextA(lpszPath); 431 } 432 } 433 return (LPSTR)lpszPath; 434 } 435 436 /************************************************************************* 437 * PathGetArgsW [SHLWAPI.@] 438 * 439 * See PathGetArgsA. 440 */ 441 LPWSTR WINAPI PathGetArgsW(LPCWSTR lpszPath) 442 { 443 BOOL bSeenQuote = FALSE; 444 445 TRACE("(%s)\n",debugstr_w(lpszPath)); 446 447 if (lpszPath) 448 { 449 while (*lpszPath) 450 { 451 if ((*lpszPath==' ') && !bSeenQuote) 452 return (LPWSTR)lpszPath + 1; 453 if (*lpszPath == '"') 454 bSeenQuote = !bSeenQuote; 455 lpszPath = CharNextW(lpszPath); 456 } 457 } 458 return (LPWSTR)lpszPath; 459 } 460 461 /************************************************************************* 462 * PathGetDriveNumberA [SHLWAPI.@] 463 * 464 * Return the drive number from a path 465 * 466 * PARAMS 467 * lpszPath [I] Path to get the drive number from 468 * 469 * RETURNS 470 * Success: The drive number corresponding to the drive in the path 471 * Failure: -1, if lpszPath contains no valid drive 472 */ 473 int WINAPI PathGetDriveNumberA(LPCSTR lpszPath) 474 { 475 TRACE ("(%s)\n",debugstr_a(lpszPath)); 476 477 if (lpszPath && !IsDBCSLeadByte(*lpszPath) && lpszPath[1] == ':' && 478 tolower(*lpszPath) >= 'a' && tolower(*lpszPath) <= 'z') 479 return tolower(*lpszPath) - 'a'; 480 return -1; 481 } 482 483 /************************************************************************* 484 * PathGetDriveNumberW [SHLWAPI.@] 485 * 486 * See PathGetDriveNumberA. 487 */ 488 int WINAPI PathGetDriveNumberW(LPCWSTR lpszPath) 489 { 490 TRACE ("(%s)\n",debugstr_w(lpszPath)); 491 492 if (lpszPath && lpszPath[1] == ':' && 493 tolowerW(*lpszPath) >= 'a' && tolowerW(*lpszPath) <= 'z') 494 return tolowerW(*lpszPath) - 'a'; 495 return -1; 496 } 497 498 /************************************************************************* 499 * PathRemoveFileSpecA [SHLWAPI.@] 500 * 501 * Remove the file specification from a path. 502 * 503 * PARAMS 504 * lpszPath [O] Path to remove the file spec from 505 * 506 * RETURNS 507 * TRUE If the path was valid and modified 508 * FALSE Otherwise 509 */ 510 BOOL WINAPI PathRemoveFileSpecA(LPSTR lpszPath) 511 { 512 LPSTR lpszFileSpec = lpszPath; 513 BOOL bModified = FALSE; 514 515 TRACE("(%s)\n",debugstr_a(lpszPath)); 516 517 if(lpszPath) 518 { 519 /* Skip directory or UNC path */ 520 if (*lpszPath == '\\') 521 lpszFileSpec = ++lpszPath; 522 if (*lpszPath == '\\') 523 lpszFileSpec = ++lpszPath; 524 525 while (*lpszPath) 526 { 527 if(*lpszPath == '\\') 528 lpszFileSpec = lpszPath; /* Skip dir */ 529 else if(*lpszPath == ':') 530 { 531 lpszFileSpec = ++lpszPath; /* Skip drive */ 532 if (*lpszPath == '\\') 533 lpszFileSpec++; 534 } 535 if (!(lpszPath = CharNextA(lpszPath))) 536 break; 537 } 538 539 if (*lpszFileSpec) 540 { 541 *lpszFileSpec = '\0'; 542 bModified = TRUE; 543 } 544 } 545 return bModified; 546 } 547 548 /************************************************************************* 549 * PathRemoveFileSpecW [SHLWAPI.@] 550 * 551 * See PathRemoveFileSpecA. 552 */ 553 BOOL WINAPI PathRemoveFileSpecW(LPWSTR lpszPath) 554 { 555 LPWSTR lpszFileSpec = lpszPath; 556 BOOL bModified = FALSE; 557 558 TRACE("(%s)\n",debugstr_w(lpszPath)); 559 560 if(lpszPath) 561 { 562 /* Skip directory or UNC path */ 563 if (*lpszPath == '\\') 564 lpszFileSpec = ++lpszPath; 565 if (*lpszPath == '\\') 566 lpszFileSpec = ++lpszPath; 567 568 while (*lpszPath) 569 { 570 if(*lpszPath == '\\') 571 lpszFileSpec = lpszPath; /* Skip dir */ 572 else if(*lpszPath == ':') 573 { 574 lpszFileSpec = ++lpszPath; /* Skip drive */ 575 if (*lpszPath == '\\') 576 lpszFileSpec++; 577 } 578 if (!(lpszPath = CharNextW(lpszPath))) 579 break; 580 } 581 582 if (*lpszFileSpec) 583 { 584 *lpszFileSpec = '\0'; 585 bModified = TRUE; 586 } 587 } 588 return bModified; 589 } 590 591 /************************************************************************* 592 * PathStripPathA [SHLWAPI.@] 593 * 594 * Remove the initial path from the beginning of a filename 595 * 596 * PARAMS 597 * lpszPath [O] Path to remove the initial path from 598 * 599 * RETURNS 600 * Nothing. 601 */ 602 void WINAPI PathStripPathA(LPSTR lpszPath) 603 { 604 TRACE("(%s)\n", debugstr_a(lpszPath)); 605 606 if (lpszPath) 607 { 608 LPSTR lpszFileName = PathFindFileNameA(lpszPath); 609 if(lpszFileName) 610 RtlMoveMemory(lpszPath, lpszFileName, strlen(lpszFileName)+1); 611 } 612 } 613 614 /************************************************************************* 615 * PathStripPathW [SHLWAPI.@] 616 * 617 * See PathStripPathA. 618 */ 619 void WINAPI PathStripPathW(LPWSTR lpszPath) 620 { 621 LPWSTR lpszFileName; 622 623 TRACE("(%s)\n", debugstr_w(lpszPath)); 624 lpszFileName = PathFindFileNameW(lpszPath); 625 if(lpszFileName) 626 RtlMoveMemory(lpszPath, lpszFileName, (strlenW(lpszFileName)+1)*sizeof(WCHAR)); 627 } 628 629 /************************************************************************* 630 * PathStripToRootA [SHLWAPI.@] 631 * 632 * Reduce a path to its root. 633 * 634 * PARAMS 635 * lpszPath [O] the path to reduce 636 * 637 * RETURNS 638 * Success: TRUE if the stripped path is a root path 639 * Failure: FALSE if the path cannot be stripped or is NULL 640 */ 641 BOOL WINAPI PathStripToRootA(LPSTR lpszPath) 642 { 643 TRACE("(%s)\n", debugstr_a(lpszPath)); 644 645 if (!lpszPath) 646 return FALSE; 647 while(!PathIsRootA(lpszPath)) 648 if (!PathRemoveFileSpecA(lpszPath)) 649 return FALSE; 650 return TRUE; 651 } 652 653 /************************************************************************* 654 * PathStripToRootW [SHLWAPI.@] 655 * 656 * See PathStripToRootA. 657 */ 658 BOOL WINAPI PathStripToRootW(LPWSTR lpszPath) 659 { 660 TRACE("(%s)\n", debugstr_w(lpszPath)); 661 662 if (!lpszPath) 663 return FALSE; 664 while(!PathIsRootW(lpszPath)) 665 if (!PathRemoveFileSpecW(lpszPath)) 666 return FALSE; 667 return TRUE; 668 } 669 670 /************************************************************************* 671 * PathRemoveArgsA [SHLWAPI.@] 672 * 673 * Strip space seperated arguments from a path. 674 * 675 * PARAMS 676 * lpszPath [I] Path to remove arguments from 677 * 678 * RETURNS 679 * Nothing. 680 */ 681 void WINAPI PathRemoveArgsA(LPSTR lpszPath) 682 { 683 TRACE("(%s)\n",debugstr_a(lpszPath)); 684 685 if(lpszPath) 686 { 687 LPSTR lpszArgs = PathGetArgsA(lpszPath); 688 if (*lpszArgs) 689 lpszArgs[-1] = '\0'; 690 else 691 { 692 LPSTR lpszLastChar = CharPrevA(lpszPath, lpszArgs); 693 if(*lpszLastChar == ' ') 694 *lpszLastChar = '\0'; 695 } 696 } 697 } 698 699 /************************************************************************* 700 * PathRemoveArgsW [SHLWAPI.@] 701 * 702 * See PathRemoveArgsA. 703 */ 704 void WINAPI PathRemoveArgsW(LPWSTR lpszPath) 705 { 706 TRACE("(%s)\n",debugstr_w(lpszPath)); 707 708 if(lpszPath) 709 { 710 LPWSTR lpszArgs = PathGetArgsW(lpszPath); 711 if (*lpszArgs) 712 lpszArgs[-1] = '\0'; 713 else 714 { 715 LPWSTR lpszLastChar = CharPrevW(lpszPath, lpszArgs); 716 if(*lpszLastChar == ' ') 717 *lpszLastChar = '\0'; 718 } 719 } 720 } 721 722 /************************************************************************* 723 * PathRemoveExtensionA [SHLWAPI.@] 724 * 725 * Remove the file extension from a path 726 * 727 * PARAMS 728 * lpszPath [O] Path to remove the extension from 729 * 730 * RETURNS 731 * Nothing. 732 */ 733 void WINAPI PathRemoveExtensionA(LPSTR lpszPath) 734 { 735 TRACE("(%s)\n", debugstr_a(lpszPath)); 736 737 if (lpszPath) 738 { 739 lpszPath = PathFindExtensionA(lpszPath); 740 *lpszPath = '\0'; 741 } 742 } 743 744 /************************************************************************* 745 * PathRemoveExtensionW [SHLWAPI.@] 746 * 747 * See PathRemoveExtensionA. 27 748 */ 28 29 /************************************************************************* 30 * PathAppendA [SHLWAPI.@] 31 * 749 void WINAPI PathRemoveExtensionW(LPWSTR lpszPath) 750 { 751 TRACE("(%s)\n", debugstr_w(lpszPath)); 752 753 if (lpszPath) 754 { 755 lpszPath = PathFindExtensionW(lpszPath); 756 *lpszPath = '\0'; 757 } 758 } 759 760 /************************************************************************* 761 * PathRemoveBackslashA [SHLWAPI.@] 762 * 763 * Remove a trailing backslash from a path. 764 * 765 * PARAMS 766 * lpszPath [O] Path to remove backslash from 767 * 768 * RETURNS 769 * Success: A pointer to the end of the path 770 * Failure: NULL, if lpszPath is NULL 771 */ 772 LPSTR WINAPI PathRemoveBackslashA( LPSTR lpszPath ) 773 { 774 LPSTR szTemp = NULL; 775 776 TRACE("(%s)\n", debugstr_a(lpszPath)); 777 778 if(lpszPath) 779 { 780 szTemp = CharPrevA(lpszPath, lpszPath + strlen(lpszPath)); 781 if (!PathIsRootA(lpszPath) && *szTemp == '\\') 782 *szTemp = '\0'; 783 } 784 return szTemp; 785 } 786 787 /************************************************************************* 788 * PathRemoveBackslashW [SHLWAPI.@] 789 * 790 * See PathRemoveBackslashA. 791 */ 792 LPWSTR WINAPI PathRemoveBackslashW( LPWSTR lpszPath ) 793 { 794 LPWSTR szTemp = NULL; 795 796 TRACE("(%s)\n", debugstr_w(lpszPath)); 797 798 if(lpszPath) 799 { 800 szTemp = CharPrevW(lpszPath, lpszPath + strlenW(lpszPath)); 801 if (!PathIsRootW(lpszPath) && *szTemp == '\\') 802 *szTemp = '\0'; 803 } 804 return szTemp; 805 } 806 807 /************************************************************************* 808 * PathRemoveBlanksA [SHLWAPI.@] 809 * 810 * Remove Spaces from the start and end of a path. 811 * 812 * PARAMS 813 * lpszPath [O] Path to strip blanks from 814 * 815 * RETURNS 816 * Nothing. 817 */ 818 VOID WINAPI PathRemoveBlanksA(LPSTR lpszPath) 819 { 820 TRACE("(%s)\n", debugstr_a(lpszPath)); 821 822 if(lpszPath && *lpszPath) 823 { 824 LPSTR start = lpszPath; 825 826 while (*lpszPath == ' ') 827 lpszPath = CharNextA(lpszPath); 828 829 while(*lpszPath) 830 *start++ = *lpszPath++; 831 832 if (start != lpszPath) 833 while (start[-1] == ' ') 834 start--; 835 *start = '\0'; 836 } 837 } 838 839 /************************************************************************* 840 * PathRemoveBlanksW [SHLWAPI.@] 841 * 842 * See PathRemoveBlanksA. 843 */ 844 VOID WINAPI PathRemoveBlanksW(LPWSTR lpszPath) 845 { 846 TRACE("(%s)\n", debugstr_w(lpszPath)); 847 848 if(lpszPath && *lpszPath) 849 { 850 LPWSTR start = lpszPath; 851 852 while (*lpszPath == ' ') 853 lpszPath++; 854 855 while(*lpszPath) 856 *start++ = *lpszPath++; 857 858 if (start != lpszPath) 859 while (start[-1] == ' ') 860 start--; 861 *start = '\0'; 862 } 863 } 864 865 /************************************************************************* 866 * PathQuoteSpacesA [SHLWAPI.@] 867 * 868 * Surround a path containg spaces in quotes. 869 * 870 * PARAMS 871 * lpszPath [O] Path to quote 872 * 873 * RETURNS 874 * Nothing. 875 * 32 876 * NOTES 33 * concat path lpszPath2 onto lpszPath1 34 * 35 * FIXME 36 * the resulting path is also canonicalized 37 */ 38 BOOL WINAPI PathAppendA( 39 LPSTR lpszPath1, 40 LPCSTR lpszPath2) 41 { 42 TRACE("%s %s\n",lpszPath1, lpszPath2); 43 while (lpszPath2[0]=='\\') lpszPath2++; 44 PathCombineA(lpszPath1,lpszPath1,lpszPath2); 45 return TRUE; 46 } 47 48 /************************************************************************* 49 * PathAppendW [SHLWAPI.@] 50 */ 51 BOOL WINAPI PathAppendW( 52 LPWSTR lpszPath1, 53 LPCWSTR lpszPath2) 54 { 55 TRACE("%s %s\n",debugstr_w(lpszPath1), debugstr_w(lpszPath2)); 56 while (lpszPath2[0]=='\\') lpszPath2++; 57 PathCombineW(lpszPath1,lpszPath1,lpszPath2); 58 return TRUE; 59 } 60 61 /************************************************************************* 62 * PathCombineA [SHLWAPI.@] 63 * 877 * The path is not changed if it is invalid or has no spaces. 878 */ 879 VOID WINAPI PathQuoteSpacesA(LPSTR lpszPath) 880 { 881 TRACE("(%s)\n", debugstr_a(lpszPath)); 882 883 if(lpszPath && StrChrA(lpszPath,' ')) 884 { 885 int iLen = strlen(lpszPath) + 1; 886 887 if (iLen + 2 < MAX_PATH) 888 { 889 memmove(lpszPath + 1, lpszPath, iLen); 890 lpszPath[0] = '"'; 891 lpszPath[iLen] = '"'; 892 lpszPath[iLen + 1] = '\0'; 893 } 894 } 895 } 896 897 /************************************************************************* 898 * PathQuoteSpacesW [SHLWAPI.@] 899 * 900 * See PathQuoteSpacesA. 901 */ 902 VOID WINAPI PathQuoteSpacesW(LPWSTR lpszPath) 903 { 904 TRACE("(%s)\n", debugstr_w(lpszPath)); 905 906 if(lpszPath && StrChrW(lpszPath,' ')) 907 { 908 int iLen = strlenW(lpszPath) + 1; 909 910 if (iLen + 2 < MAX_PATH) 911 { 912 memmove(lpszPath + 1, lpszPath, iLen * sizeof(WCHAR)); 913 lpszPath[0] = '"'; 914 lpszPath[iLen] = '"'; 915 lpszPath[iLen + 1] = '\0'; 916 } 917 } 918 } 919 920 /************************************************************************* 921 * PathUnquoteSpacesA [SHLWAPI.@] 922 * 923 * Remove quotes ("") from around a path, if present. 924 * 925 * PARAMS 926 * lpszPath [O] Path to strip quotes from 927 * 928 * RETURNS 929 * Nothing 930 * 64 931 * NOTES 65 * if lpszFile='.' skip it 66 * szDest can be equal to lpszFile. Thats why we use sTemp 67 * 68 * FIXME 69 * the resulting path is also canonicalized 70 */ 71 LPSTR WINAPI PathCombineA( 72 LPSTR szDest, 73 LPCSTR lpszDir, 74 LPCSTR lpszFile) 75 { 76 char sTemp[MAX_PATH]; 77 TRACE("%p %p->%s %p->%s\n",szDest, lpszDir, lpszDir, lpszFile, lpszFile); 78 79 80 if (!lpszFile || !lpszFile[0] || (lpszFile[0]=='.' && !lpszFile[1]) ) 81 { 82 strcpy(szDest,lpszDir); 83 return szDest; 84 } 85 86 /* if lpszFile is a complete path don't care about lpszDir */ 87 if (PathGetDriveNumberA(lpszFile) != -1) 88 { 89 strcpy(szDest,lpszFile); 90 } 91 else if (lpszFile[0] == '\\' ) 92 { 93 strcpy(sTemp,lpszDir); 94 PathStripToRootA(sTemp); 95 strcat(sTemp,lpszFile); 96 strcpy(szDest,sTemp); 97 } 98 else 99 { 100 strcpy(sTemp,lpszDir); 101 PathAddBackslashA(sTemp); 102 strcat(sTemp,lpszFile); 103 strcpy(szDest,sTemp); 104 } 105 return szDest; 106 } 107 108 /************************************************************************* 109 * PathCombineW [SHLWAPI.@] 110 */ 111 LPWSTR WINAPI PathCombineW( 112 LPWSTR szDest, 113 LPCWSTR lpszDir, 114 LPCWSTR lpszFile) 115 { 116 WCHAR sTemp[MAX_PATH]; 117 TRACE("%p %p->%s %p->%s\n",szDest, lpszDir, debugstr_w(lpszDir), 118 lpszFile, debugstr_w(lpszFile)); 119 120 121 if (!lpszFile || !lpszFile[0] || (lpszFile[0]==(WCHAR)'.' && !lpszFile[1]) ) 122 { 123 strcpyW(szDest,lpszDir); 124 return szDest; 125 } 126 127 /* if lpszFile is a complete path don't care about lpszDir */ 128 if (PathGetDriveNumberW(lpszFile) != -1) 129 { 130 strcpyW(szDest,lpszFile); 131 } 132 else if (lpszFile[0] == (WCHAR)'\\' ) 133 { 134 strcpyW(sTemp,lpszDir); 135 PathStripToRootW(sTemp); 136 strcatW(sTemp,lpszFile); 137 strcpyW(szDest,sTemp); 138 } 139 else 140 { 141 strcpyW(sTemp,lpszDir); 142 PathAddBackslashW(sTemp); 143 strcatW(sTemp,lpszFile); 144 strcpyW(szDest,sTemp); 145 } 146 return szDest; 147 } 148 149 /************************************************************************* 150 * PathAddBackslashA [SHLWAPI.@] 932 * If the path contains a single quote only, an empty string will result. 933 * Otherwise quotes are only removed if they appear at the start and end 934 * of the path. 935 */ 936 VOID WINAPI PathUnquoteSpacesA(LPSTR lpszPath) 937 { 938 TRACE("(%s)\n", debugstr_a(lpszPath)); 939 940 if (lpszPath && *lpszPath == '"') 941 { 942 DWORD dwLen = strlen(lpszPath) - 1; 943 944 if (lpszPath[dwLen] == '"') 945 { 946 lpszPath[dwLen] = '\0'; 947 for (; *lpszPath; lpszPath++) 948 *lpszPath = lpszPath[1]; 949 } 950 } 951 } 952 953 /************************************************************************* 954 * PathUnquoteSpacesW [SHLWAPI.@] 955 * 956 * See PathUnquoteSpacesA. 957 */ 958 VOID WINAPI PathUnquoteSpacesW(LPWSTR lpszPath) 959 { 960 TRACE("(%s)\n", debugstr_w(lpszPath)); 961 962 if (lpszPath && *lpszPath == '"') 963 { 964 DWORD dwLen = strlenW(lpszPath) - 1; 965 966 if (lpszPath[dwLen] == '"') 967 { 968 lpszPath[dwLen] = '\0'; 969 for (; *lpszPath; lpszPath++) 970 *lpszPath = lpszPath[1]; 971 } 972 } 973 } 974 975 /************************************************************************* 976 * PathParseIconLocationA [SHLWAPI.@] 977 * 978 * Parse the location of an icon from a path. 979 * 980 * PARAMS 981 * lpszPath [O] The path to parse the icon location from. 982 * 983 * RETURNS 984 * Success: The number of the icon 985 * Failure: 0 if the path does not contain an icon location or is NULL 151 986 * 152 987 * NOTES 153 * append \ if there is none 154 */ 155 LPSTR WINAPI PathAddBackslashA(LPSTR lpszPath) 156 { 157 int len; 158 TRACE("%p->%s\n",lpszPath,lpszPath); 159 160 len = strlen(lpszPath); 161 if (len && lpszPath[len-1]!='\\') 162 { 163 lpszPath[len] = '\\'; 164 lpszPath[len+1]= 0x00; 165 return lpszPath+len+1; 166 } 167 return lpszPath+len; 168 } 169 170 /************************************************************************* 171 * PathAddBackslashW [SHLWAPI.@] 172 */ 173 LPWSTR WINAPI PathAddBackslashW(LPWSTR lpszPath) 174 { 175 int len; 176 TRACE("%p->%s\n",lpszPath,debugstr_w(lpszPath)); 177 178 len = strlenW(lpszPath); 179 if (len && lpszPath[len-1]!=(WCHAR)'\\') 180 { 181 lpszPath[len] = (WCHAR)'\\'; 182 lpszPath[len+1]= 0x00; 183 return lpszPath+len+1; 184 } 185 return lpszPath+len; 186 } 187 188 /************************************************************************* 189 * PathBuildRootA [SHLWAPI.@] 190 */ 191 LPSTR WINAPI PathBuildRootA(LPSTR lpszPath, int drive) 192 { 193 TRACE("%p %i\n",lpszPath, drive); 194 195 strcpy(lpszPath,"A:\\"); 196 lpszPath[0]+=drive; 197 return lpszPath; 198 } 199 200 /************************************************************************* 201 * PathBuildRootW [SHLWAPI.@] 202 */ 203 LPWSTR WINAPI PathBuildRootW(LPWSTR lpszPath, int drive) 204 { 205 lpszPath[0] = 'A' + drive; 206 lpszPath[1] = ':'; 207 lpszPath[2] = '\\'; 208 lpszPath[3] = 0; 209 TRACE("%p %i\n",debugstr_w(lpszPath), drive); 210 return lpszPath; 211 } 212 213 /* 214 Extracting Component Parts 215 */ 216 217 /************************************************************************* 218 * PathFindFileNameA [SHLWAPI.@] 219 */ 220 LPSTR WINAPI PathFindFileNameA(LPCSTR lpszPath) 221 { 222 LPCSTR lastSlash = lpszPath; 223 224 TRACE("%s\n",lpszPath); 225 while (*lpszPath) 226 { 227 if ( isSlash(lpszPath[0]) && lpszPath[1]) 228 lastSlash = lpszPath+1; 229 lpszPath = CharNextA(lpszPath); 230 } 231 return (LPSTR)lastSlash; 232 233 } 234 235 /************************************************************************* 236 * PathFindFileNameW [SHLWAPI.@] 237 */ 238 LPWSTR WINAPI PathFindFileNameW(LPCWSTR lpszPath) 239 { 240 LPCWSTR wslash; 241 wslash = lpszPath; 242 243 TRACE("%s\n",debugstr_w(wslash)); 244 while (lpszPath[0]) 245 { 246 if (((lpszPath[0]=='\\') || (lpszPath[0]==':')) && lpszPath[1] && lpszPath[1]!='\\') 247 wslash = lpszPath+1; 248 lpszPath = CharNextW(lpszPath); 249 } 250 return (LPWSTR)wslash; 251 } 252 253 /************************************************************************* 254 * PathFindExtensionA [SHLWAPI.@] 988 * The path has surrounding quotes and spaces removed regardless 989 * of whether the call succeeds or not. 990 */ 991 int WINAPI PathParseIconLocationA(LPSTR lpszPath) 992 { 993 int iRet = 0; 994 LPSTR lpszComma; 995 996 TRACE("(%s)\n", debugstr_a(lpszPath)); 997 998 if (lpszPath) 999 { 1000 if ((lpszComma = strchr(lpszPath, ','))) 1001 { 1002 *lpszComma++ = '\0'; 1003 iRet = StrToIntA(lpszComma); 1004 } 1005 PathUnquoteSpacesA(lpszPath); 1006 PathRemoveBlanksA(lpszPath); 1007 } 1008 return iRet; 1009 } 1010 1011 /************************************************************************* 1012 * PathParseIconLocationW [SHLWAPI.@] 1013 * 1014 * See PathParseIconLocationA. 1015 */ 1016 int WINAPI PathParseIconLocationW(LPWSTR lpszPath) 1017 { 1018 int iRet = 0; 1019 LPWSTR lpszComma; 1020 1021 TRACE("(%s)\n", debugstr_w(lpszPath)); 1022 1023 if (lpszPath) 1024 { 1025 if ((lpszComma = StrChrW(lpszPath, ','))) 1026 { 1027 *lpszComma++ = '\0'; 1028 iRet = StrToIntW(lpszComma); 1029 } 1030 PathUnquoteSpacesW(lpszPath); 1031 PathRemoveBlanksW(lpszPath); 1032 } 1033 return iRet; 1034 } 1035 1036 /************************************************************************* 1037 * SHLWAPI_PathFindLocalExeA 1038 * 1039 * Internal implementation of SHLWAPI_3. 1040 */ 1041 BOOL WINAPI SHLWAPI_PathFindLocalExeA (LPSTR lpszPath, DWORD dwWhich) 1042 { 1043 BOOL bRet = FALSE; 1044 1045 TRACE("(%s,%ld)\n", debugstr_a(lpszPath), dwWhich); 1046 1047 if (lpszPath) 1048 { 1049 WCHAR szPath[MAX_PATH]; 1050 MultiByteToWideChar(0,0,lpszPath,-1,szPath,MAX_PATH); 1051 bRet = SHLWAPI_PathFindLocalExeW(szPath, dwWhich); 1052 if (bRet) 1053 WideCharToMultiByte(0,0,szPath,-1,lpszPath,MAX_PATH,0,0); 1054 } 1055 return bRet; 1056 } 1057 1058 /************************************************************************* 1059 * SHLWAPI_PathFindLocalExeW 1060 * 1061 * Internal implementation of SHLWAPI_4. 1062 */ 1063 BOOL WINAPI SHLWAPI_PathFindLocalExeW (LPWSTR lpszPath, DWORD dwWhich) 1064 { 1065 static const WCHAR pszExts[7][5] = { { '.', 'p', 'i', 'f', '0'}, 1066 { '.', 'c', 'o', 'm', '0'}, 1067 { '.', 'e', 'x', 'e', '0'}, 1068 { '.', 'b', 'a', 't', '0'}, 1069 { '.', 'l', 'n', 'k', '0'}, 1070 { '.', 'c', 'm', 'd', '0'}, 1071 { '0', '0', '0', '0', '0'} }; 1072 1073 TRACE("(%s,%ld)\n", debugstr_w(lpszPath), dwWhich); 1074 1075 if (!lpszPath || PathIsUNCServerW(lpszPath) || PathIsUNCServerShareW(lpszPath)) 1076 return FALSE; 1077 1078 if (dwWhich) 1079 { 1080 LPCWSTR szExt = PathFindExtensionW(lpszPath); 1081 if (!*szExt || dwWhich & 0x40) 1082 { 1083 int iChoose = 0; 1084 int iLen = lstrlenW(lpszPath); 1085 if (iLen > (MAX_PATH - 5)) 1086 return FALSE; 1087 while (dwWhich & 0x1 && iChoose < sizeof(pszExts)) 1088 { 1089 lstrcpyW(lpszPath + iLen, pszExts[iChoose]); 1090 if (PathFileExistsW(lpszPath)) 1091 return TRUE; 1092 iChoose++; 1093 dwWhich >>= 1; 1094 } 1095 *(lpszPath + iLen) = (WCHAR)'\0'; 1096 return FALSE; 1097 } 1098 } 1099 return PathFileExistsW(lpszPath); 1100 } 1101 1102 /************************************************************************* 1103 * SHLWAPI_PathFindInOtherDirs 1104 * 1105 * Internal helper for SHLWAPI_PathFindOnPathExA/W. 1106 */ 1107 static BOOL WINAPI SHLWAPI_PathFindInOtherDirs(LPWSTR lpszFile, DWORD dwWhich) 1108 { 1109 static WCHAR szSystem[] = { 'S','y','s','t','e','m','\0'}; 1110 static WCHAR szPath[] = { 'P','A','T','H','\0'}; 1111 DWORD dwLenPATH; 1112 LPCWSTR lpszCurr; 1113 WCHAR *lpszPATH; 1114 WCHAR buff[MAX_PATH]; 1115 1116 TRACE("(%s,%08lx)\n", debugstr_w(lpszFile), dwWhich); 1117 1118 /* Try system directories */ 1119 GetSystemDirectoryW(buff, MAX_PATH); 1120 if (!PathAppendW(buff, lpszFile)) 1121 return FALSE; 1122 if (SHLWAPI_PathFindLocalExeW(buff, dwWhich)) 1123 { 1124 strcpyW(lpszFile, buff); 1125 return TRUE; 1126 } 1127 GetWindowsDirectoryW(buff, MAX_PATH); 1128 if (!PathAppendW(buff, szSystem ) || !PathAppendW(buff, lpszFile)) 1129 return FALSE; 1130 if (SHLWAPI_PathFindLocalExeW(buff, dwWhich)) 1131 { 1132 strcpyW(lpszFile, buff); 1133 return TRUE; 1134 } 1135 GetWindowsDirectoryW(buff, MAX_PATH); 1136 if (!PathAppendW(buff, lpszFile)) 1137 return FALSE; 1138 if (SHLWAPI_PathFindLocalExeW(buff, dwWhich)) 1139 { 1140 strcpyW(lpszFile, buff); 1141 return TRUE; 1142 } 1143 /* Try dirs listed in %PATH% */ 1144 dwLenPATH = GetEnvironmentVariableW(szPath, buff, MAX_PATH); 1145 1146 if (!dwLenPATH || !(lpszPATH = malloc((dwLenPATH + 1) * sizeof (WCHAR)))) 1147 return FALSE; 1148 1149 GetEnvironmentVariableW(szPath, lpszPATH, dwLenPATH + 1); 1150 lpszCurr = lpszPATH; 1151 while (lpszCurr) 1152 { 1153 LPCWSTR lpszEnd = lpszCurr; 1154 LPWSTR pBuff = buff; 1155 1156 while (*lpszEnd == ' ') 1157 lpszEnd++; 1158 while (*lpszEnd && *lpszEnd != ';') 1159 *pBuff++ = *lpszEnd++; 1160 *pBuff = '\0'; 1161 1162 if (*lpszEnd) 1163 lpszCurr = lpszEnd + 1; 1164 else 1165 lpszCurr = NULL; /* Last Path, terminate after this */ 1166 1167 if (!PathAppendW(buff, lpszFile)) 1168 return FALSE; 1169 if (SHLWAPI_PathFindLocalExeW(buff, dwWhich)) 1170 { 1171 strcpyW(lpszFile, buff); 1172 free(lpszPATH); 1173 return TRUE; 1174 } 1175 } 1176 free(lpszPATH); 1177 return FALSE; 1178 } 1179 1180 1181 /************************************************************************* 1182 * SHLWAPI_PathFindOnPathExA 1183 * 1184 * Internal implementation of SHLWAPI_5 1185 */ 1186 BOOL WINAPI SHLWAPI_PathFindOnPathExA(LPSTR lpszFile, LPCSTR *lppszOtherDirs, DWORD dwWhich) 1187 { 1188 WCHAR szFile[MAX_PATH]; 1189 WCHAR buff[MAX_PATH]; 1190 1191 TRACE("(%s,%p,%08lx)\n", debugstr_a(lpszFile), lppszOtherDirs, dwWhich); 1192 1193 if (!lpszFile || !PathIsFileSpecA(lpszFile)) 1194 return FALSE; 1195 1196 MultiByteToWideChar(0,0,lpszFile,-1,szFile,MAX_PATH); 1197 1198 /* Search provided directories first */ 1199 if (lppszOtherDirs && *lppszOtherDirs) 1200 { 1201 WCHAR szOther[MAX_PATH]; 1202 LPCSTR *lpszOtherPath = lppszOtherDirs; 1203 1204 while (lpszOtherPath && *lpszOtherPath && (*lpszOtherPath)[0]) 1205 { 1206 MultiByteToWideChar(0,0,*lpszOtherPath,-1,szOther,MAX_PATH); 1207 PathCombineW(buff, szOther, szFile); 1208 if (SHLWAPI_PathFindLocalExeW(buff, dwWhich)) 1209 { 1210 WideCharToMultiByte(0,0,buff,-1,lpszFile,MAX_PATH,0,0); 1211 return TRUE; 1212 } 1213 lpszOtherPath++; 1214 } 1215 } 1216 /* Not found, try system and path dirs */ 1217 if (SHLWAPI_PathFindInOtherDirs(szFile, dwWhich)) 1218 { 1219 WideCharToMultiByte(0,0,szFile,-1,lpszFile,MAX_PATH,0,0); 1220 return TRUE; 1221 } 1222 return FALSE; 1223 } 1224 1225 /************************************************************************* 1226 * SHLWAPI_PathFindOnPathExW 1227 * 1228 * Internal implementation of SHLWAPI_6. 1229 */ 1230 BOOL WINAPI SHLWAPI_PathFindOnPathExW(LPWSTR lpszFile, LPCWSTR *lppszOtherDirs, DWORD dwWhich) 1231 { 1232 WCHAR buff[MAX_PATH]; 1233 1234 TRACE("(%s,%p,%08lx)\n", debugstr_w(lpszFile), lppszOtherDirs, dwWhich); 1235 1236 if (!lpszFile || !PathIsFileSpecW(lpszFile)) 1237 return FALSE; 1238 1239 /* Search provided directories first */ 1240 if (lppszOtherDirs && *lppszOtherDirs) 1241 { 1242 LPCWSTR *lpszOtherPath = lppszOtherDirs; 1243 while (lpszOtherPath && *lpszOtherPath && (*lpszOtherPath)[0]) 1244 { 1245 PathCombineW(buff, *lpszOtherPath, lpszFile); 1246 if (SHLWAPI_PathFindLocalExeW(buff, dwWhich)) 1247 { 1248 strcpyW(lpszFile, buff); 1249 return TRUE; 1250 } 1251 lpszOtherPath++; 1252 } 1253 } 1254 /* Not found, try system and path dirs */ 1255 return SHLWAPI_PathFindInOtherDirs(lpszFile, dwWhich); 1256 } 1257 1258 /************************************************************************* 1259 * PathFindOnPathA [SHLWAPI.@] 1260 * 1261 * Search a range of paths for an executable. 1262 * 1263 * PARAMS 1264 * lpszFile [O] File to search for 1265 * lppszOtherDirs [I] Other directories to look in 1266 * 1267 * RETURNS 1268 * Success: TRUE. The path to the executable is stored in lpszFile. 1269 * Failure: FALSE. The path to the executable is unchanged. 1270 */ 1271 BOOL WINAPI PathFindOnPathA(LPSTR lpszFile, LPCSTR *lppszOtherDirs) 1272 { 1273 TRACE("(%s,%p)\n", debugstr_a(lpszFile), lppszOtherDirs); 1274 return SHLWAPI_PathFindOnPathExA(lpszFile, lppszOtherDirs, 0); 1275 } 1276 1277 /************************************************************************* 1278 * PathFindOnPathW [SHLWAPI.@] 1279 * 1280 * See PathFindOnPathA. 1281 */ 1282 BOOL WINAPI PathFindOnPathW (LPWSTR lpszFile, LPCWSTR *lppszOtherDirs) 1283 { 1284 TRACE("(%s,%p)\n", debugstr_w(lpszFile), lppszOtherDirs); 1285 return SHLWAPI_PathFindOnPathExW(lpszFile,lppszOtherDirs, 0); 1286 } 1287 1288 /************************************************************************* 1289 * PathCompactPathExA [SHLWAPI.@] 1290 * 1291 * Compact a path. 1292 * 1293 * PARAMS 1294 * lpszDest [O] Destination for compacted path 1295 * lpszPath [I] Source path 1296 * cchMax [I[ Size of lpszDest 1297 * dwFlags [I] Compaction flags 1298 * 1299 * RETURNS 1300 * FIXME 1301 */ 1302 BOOL WINAPI PathCompactPathExA(LPSTR lpszDest, LPCSTR lpszPath, 1303 UINT cchMax, DWORD dwFlags) 1304 { 1305 BOOL bRet = FALSE; 1306 1307 TRACE("(%p,%s,%d,0x%08lx)\n", lpszDest, debugstr_a(lpszPath), cchMax, dwFlags); 1308 1309 if (lpszPath && lpszDest) 1310 { 1311 WCHAR szPath[MAX_PATH]; 1312 WCHAR szDest[MAX_PATH]; 1313 1314 MultiByteToWideChar(0,0,lpszPath,-1,szPath,MAX_PATH); 1315 szDest[0] = '\0'; 1316 bRet = PathCompactPathExW(szDest, szPath, cchMax, dwFlags); 1317 WideCharToMultiByte(0,0,szDest,-1,lpszDest,MAX_PATH,0,0); 1318 } 1319 return bRet; 1320 } 1321 1322 /************************************************************************* 1323 * PathCompactPathExW [SHLWAPI.@] 1324 * 1325 * See PathCompactPathExA. 1326 */ 1327 BOOL WINAPI PathCompactPathExW(LPWSTR lpszDest, LPCWSTR lpszPath, 1328 UINT cchMax, DWORD dwFlags) 1329 { 1330 FIXME("(%p,%s,%d,0x%08lx)-stub\n", lpszDest, debugstr_w(lpszPath), cchMax, dwFlags); 1331 1332 if (!lpszPath) 1333 return FALSE; 1334 1335 if (!lpszDest) 1336 { 1337 WARN("Invalid lpszDest would crash under Win32!\n"); 1338 return FALSE; 1339 } 1340 1341 /* FIXME */ 1342 1343 return FALSE; 1344 } 1345 1346 /************************************************************************* 1347 * PathIsRelativeA [SHLWAPI.@] 1348 * 1349 * Determine if a path is a relative path. 1350 * 1351 * PARAMS 1352 * lpszPath [I] Path to check 1353 * 1354 * RETURNS 1355 * TRUE: The path is relative, or is invalid. 1356 * FALSE: The path is not relative. 1357 */ 1358 BOOL WINAPI PathIsRelativeA (LPCSTR lpszPath) 1359 { 1360 TRACE("(%s)\n",debugstr_a(lpszPath)); 1361 1362 if (!lpszPath || !*lpszPath || IsDBCSLeadByte(*lpszPath)) 1363 return TRUE; 1364 if (*lpszPath == '\\' || (*lpszPath && lpszPath[1] == ':')) 1365 return FALSE; 1366 return TRUE; 1367 } 1368 1369 /************************************************************************* 1370 * PathIsRelativeW [SHLWAPI.@] 1371 * 1372 * See PathIsRelativeA. 1373 */ 1374 BOOL WINAPI PathIsRelativeW (LPCWSTR lpszPath) 1375 { 1376 TRACE("(%s)\n",debugstr_w(lpszPath)); 1377 1378 if (!lpszPath || !*lpszPath) 1379 return TRUE; 1380 if (*lpszPath == '\\' || (*lpszPath && lpszPath[1] == ':')) 1381 return FALSE; 1382 return TRUE; 1383 } 1384 1385 /************************************************************************* 1386 * PathIsRootA [SHLWAPI.@] 1387 * 1388 * Determine if a path is a root path. 1389 * 1390 * PARAMS 1391 * lpszPath [I] Path to check 1392 * 1393 * RETURNS 1394 * TRUE If lpszPath is valid and a root path 1395 * FALSE Otherwise 1396 */ 1397 BOOL WINAPI PathIsRootA(LPCSTR lpszPath) 1398 { 1399 TRACE("(%s)\n", debugstr_a(lpszPath)); 1400 1401 if (lpszPath && *lpszPath) 1402 { 1403 if (*lpszPath == '\\') 1404 { 1405 if (!lpszPath[1]) 1406 return TRUE; /* \ */ 1407 else if (lpszPath[1]=='\\') 1408 { 1409 BOOL bSeenSlash = FALSE; 1410 lpszPath += 2; 1411 1412 /* Check for UNC root path */ 1413 while (*lpszPath) 1414 { 1415 if (*lpszPath == '\\') 1416 { 1417 if (bSeenSlash) 1418 return FALSE; 1419 bSeenSlash = TRUE; 1420 } 1421 lpszPath = CharNextA(lpszPath); 1422 } 1423 return TRUE; 1424 } 1425 } 1426 else if (lpszPath[1] == ':' && lpszPath[2] == '\\' && lpszPath[3] == '\0') 1427 return TRUE; /* X:\ */ 1428 } 1429 return FALSE; 1430 } 1431 1432 /************************************************************************* 1433 * PathIsRootW [SHLWAPI.@] 1434 * 1435 * See PathIsRootA. 1436 */ 1437 BOOL WINAPI PathIsRootW(LPCWSTR lpszPath) 1438 { 1439 TRACE("(%s)\n", debugstr_w(lpszPath)); 1440 1441 if (lpszPath && *lpszPath) 1442 { 1443 if (*lpszPath == '\\') 1444 { 1445 if (!lpszPath[1]) 1446 return TRUE; /* \ */ 1447 else if (lpszPath[1]=='\\') 1448 { 1449 BOOL bSeenSlash = FALSE; 1450 lpszPath += 2; 1451 1452 /* Check for UNC root path */ 1453 while (*lpszPath) 1454 { 1455 if (*lpszPath == '\\') 1456 { 1457 if (bSeenSlash) 1458 return FALSE; 1459 bSeenSlash = TRUE; 1460 } 1461 lpszPath = CharNextW(lpszPath); 1462 } 1463 return TRUE; 1464 } 1465 } 1466 else if (lpszPath[1] == ':' && lpszPath[2] == '\\' && lpszPath[3] == '\0') 1467 return TRUE; /* X:\ */ 1468 } 1469 return FALSE; 1470 } 1471 1472 /************************************************************************* 1473 * PathIsDirectoryA [SHLWAPI.@] 1474 * 1475 * Determine if a path is a valid directory 1476 * 1477 * PARAMS 1478 * lpszPath [I] Path to check. 1479 * 1480 * RETURNS 1481 * FILE_ATTRIBUTE_DIRECTORY if lpszPath exists and can be read (See Notes) 1482 * FALSE if lpszPath is invalid or not a directory. 255 1483 * 256 1484 * NOTES 257 * returns pointer to last . in last lpszPath component or at \0. 258 */ 259 260 LPSTR WINAPI PathFindExtensionA(LPCSTR lpszPath) 261 { 262 LPCSTR lastpoint = NULL; 263 264 TRACE("%p %s\n",lpszPath,lpszPath); 265 266 while (*lpszPath) 267 { 268 if (*lpszPath=='\\'||*lpszPath==' ') 269 lastpoint=NULL; 270 if (*lpszPath=='.') 271 lastpoint=lpszPath; 272 lpszPath = CharNextA(lpszPath); 273 } 274 return (LPSTR)(lastpoint?lastpoint:lpszPath); 275 } 276 277 /************************************************************************* 278 * PathFindExtensionW [SHLWAPI.@] 279 */ 280 LPWSTR WINAPI PathFindExtensionW(LPCWSTR lpszPath) 281 { 282 LPCWSTR lastpoint = NULL; 283 284 TRACE("(%p %s)\n",lpszPath,debugstr_w(lpszPath)); 285 286 while (*lpszPath) 287 { 288 if (*lpszPath==(WCHAR)'\\'||*lpszPath==(WCHAR)' ') 289 lastpoint=NULL; 290 if (*lpszPath==(WCHAR)'.') 291 lastpoint=lpszPath; 292 lpszPath = CharNextW(lpszPath); 293 } 294 return (LPWSTR)(lastpoint?lastpoint:lpszPath); 295 } 296 297 /************************************************************************* 298 * PathGetArgsA [SHLWAPI.@] 299 * 300 * NOTES 301 * look for next arg in string. handle "quoted" strings 302 * returns pointer to argument *AFTER* the space. Or to the \0. 303 * 304 * FIXME 305 * quoting by '\' 306 */ 307 LPSTR WINAPI PathGetArgsA(LPCSTR lpszPath) 308 { 309 BOOL qflag = FALSE; 310 311 TRACE("%s\n",lpszPath); 312 313 while (*lpszPath) 314 { 315 if ((*lpszPath==' ') && !qflag) 316 return (LPSTR)lpszPath+1; 317 if (*lpszPath=='"') 318 qflag=!qflag; 319 lpszPath = CharNextA(lpszPath); 320 } 321 return (LPSTR)lpszPath; 322 } 323 324 /************************************************************************* 325 * PathGetArgsW [SHLWAPI.@] 326 */ 327 LPWSTR WINAPI PathGetArgsW(LPCWSTR lpszPath) 328 { 329 BOOL qflag = FALSE; 330 331 TRACE("%s\n",debugstr_w(lpszPath)); 332 333 while (*lpszPath) 334 { 335 if ((*lpszPath==' ') && !qflag) 336 return (LPWSTR)lpszPath+1; 337 if (*lpszPath=='"') 338 qflag=!qflag; 339 lpszPath = CharNextW(lpszPath); 340 } 341 return (LPWSTR)lpszPath; 342 } 343 344 /************************************************************************* 345 * PathGetDriveNumberA [SHLWAPI.@] 346 */ 347 int WINAPI PathGetDriveNumberA(LPCSTR lpszPath) 348 { 349 int chr = tolower(lpszPath[0]); 350 351 TRACE ("%s\n",debugstr_a(lpszPath)); 352 353 if (!lpszPath || lpszPath[1]!=':' || chr < 'a' || chr > 'z') return -1; 354 return tolower(lpszPath[0]) - 'a' ; 355 } 356 357 /************************************************************************* 358 * PathGetDriveNumberW [SHLWAPI.@] 359 */ 360 int WINAPI PathGetDriveNumberW(LPCWSTR lpszPath) 361 { 362 int chr = tolowerW(lpszPath[0]); 363 364 TRACE ("%s\n",debugstr_w(lpszPath)); 365 366 if (!lpszPath || lpszPath[1]!=':' || chr < 'a' || chr > 'z') return -1; 367 return tolowerW(lpszPath[0]) - 'a' ; 368 } 369 370 /************************************************************************* 371 * PathRemoveFileSpecA [SHLWAPI.@] 372 * 373 * NOTES 374 * truncates passed argument to a valid path 375 * returns if the string was modified or not. 376 * "\foo\xx\foo"-> "\foo\xx" 377 * "\" -> "\" 378 * "a:\foo" -> "a:\" 379 */ 380 BOOL WINAPI PathRemoveFileSpecA(LPSTR lpszPath) 381 { 382 LPSTR cutplace = lpszPath; 383 BOOL ret = FALSE; 384 385 TRACE("%s\n",lpszPath); 386 387 if(lpszPath) 388 { 389 while (*lpszPath == '\\') cutplace = ++lpszPath; 390 391 while (*lpszPath) 392 { 393 if(lpszPath[0] == '\\') cutplace = lpszPath; 394 395 if(lpszPath[0] == ':') 396 { 397 cutplace = lpszPath + 1; 398 if (lpszPath[1] == '\\') cutplace++; 399 lpszPath++; 400 } 401 lpszPath = CharNextA(lpszPath); 402 if (!lpszPath) break; 403 } 404 405 ret = (*cutplace!='\0'); 406 *cutplace = '\0'; 407 } 408 return ret; 409 } 410 411 /************************************************************************* 412 * PathRemoveFileSpecW [SHLWAPI.@] 413 */ 414 BOOL WINAPI PathRemoveFileSpecW(LPWSTR lpszPath) 415 { 416 LPWSTR cutplace = lpszPath; 417 BOOL ret = FALSE; 418 419 TRACE("%s\n",debugstr_w(lpszPath)); 420 421 if(lpszPath) 422 { 423 while (*lpszPath == '\\') cutplace = ++lpszPath; 424 425 while (*lpszPath) 426 { 427 if(lpszPath[0] == '\\') cutplace = lpszPath; 428 429 if(lpszPath[0] == ':') 430 { 431 cutplace = lpszPath + 1; 432 if (lpszPath[1] == '\\') cutplace++; 433 lpszPath++; 434 } 435 lpszPath = CharNextW(lpszPath); 436 if (!lpszPath) break; 437 } 438 439 ret = (*cutplace!='\0'); 440 *cutplace = '\0'; 441 } 442 return ret; 443 } 444 445 /************************************************************************* 446 * PathStripPathA [SHLWAPI.@] 447 * 448 * NOTES 449 * removes the path from the beginning of a filename 450 */ 451 void WINAPI PathStripPathA(LPSTR lpszPath) 452 { 453 LPSTR lpszFileName = PathFindFileNameA(lpszPath); 454 455 TRACE("%s\n", lpszPath); 456 457 if(lpszFileName) 458 RtlMoveMemory(lpszPath, lpszFileName, strlen(lpszFileName)+1); 459 } 460 461 /************************************************************************* 462 * PathStripPathW [SHLWAPI.@] 463 */ 464 void WINAPI PathStripPathW(LPWSTR lpszPath) 465 { 466 LPWSTR lpszFileName = PathFindFileNameW(lpszPath); 467 468 TRACE("%s\n", debugstr_w(lpszPath)); 469 if(lpszFileName) 470 RtlMoveMemory(lpszPath, lpszFileName, (strlenW(lpszFileName)+1)*sizeof(WCHAR)); 471 } 472 473 /************************************************************************* 474 * PathStripToRootA [SHLWAPI.@] 475 */ 476 BOOL WINAPI PathStripToRootA(LPSTR lpszPath) 477 { 478 TRACE("%s\n", lpszPath); 479 480 if (!lpszPath) return FALSE; 481 while(!PathIsRootA(lpszPath)) 482 if (!PathRemoveFileSpecA(lpszPath)) return FALSE; 483 return TRUE; 484 } 485 486 /************************************************************************* 487 * PathStripToRootW [SHLWAPI.@] 488 */ 489 BOOL WINAPI PathStripToRootW(LPWSTR lpszPath) 490 { 491 TRACE("%s\n", debugstr_w(lpszPath)); 492 493 if (!lpszPath) return FALSE; 494 while(!PathIsRootW(lpszPath)) 495 if (!PathRemoveFileSpecW(lpszPath)) return FALSE; 496 return TRUE; 497 } 498 499 /************************************************************************* 500 * PathRemoveArgsA [SHLWAPI.@] 501 * 502 */ 503 void WINAPI PathRemoveArgsA(LPSTR lpszPath) 504 { 505 TRACE("%s\n",lpszPath); 506 507 if(lpszPath) 508 { 509 LPSTR lpszArgs = PathGetArgsA(lpszPath); 510 if (!*lpszArgs) 511 { 512 LPSTR lpszLastChar = CharPrevA(lpszPath, lpszArgs); 513 if(*lpszLastChar==' ') *lpszLastChar = '\0'; 514 } 515 } 516 } 517 518 /************************************************************************* 519 * PathRemoveArgsW [SHLWAPI.@] 520 */ 521 void WINAPI PathRemoveArgsW(LPWSTR lpszPath) 522 { 523 TRACE("%s\n", debugstr_w(lpszPath)); 524 525 if(lpszPath) 526 { 527 LPWSTR lpszArgs = PathGetArgsW(lpszPath); 528 if (!*lpszArgs) 529 { 530 LPWSTR lpszLastChar = CharPrevW(lpszPath, lpszArgs); 531 if(*lpszLastChar==' ') *lpszLastChar = '\0'; 532 } 533 } 534 } 535 536 /************************************************************************* 537 * PathRemoveExtensionA [SHLWAPI.@] 538 */ 539 void WINAPI PathRemoveExtensionA(LPSTR lpszPath) 540 { 541 LPSTR lpszExtension = PathFindExtensionA(lpszPath); 542 543 TRACE("%s\n", lpszPath); 544 545 if (lpszExtension) *lpszExtension='\0'; 546 } 547 548 /************************************************************************* 549 * PathRemoveExtensionW [SHLWAPI.@] 550 */ 551 void WINAPI PathRemoveExtensionW(LPWSTR lpszPath) 552 { 553 LPWSTR lpszExtension = PathFindExtensionW(lpszPath); 554 555 TRACE("%s\n", debugstr_w(lpszPath)); 556 557 if (lpszExtension) *lpszExtension='\0'; 558 } 559 560 /************************************************************************* 561 * PathRemoveBackslashA [SHLWAPI.@] 562 * 563 * If the path ends in a backslash it is replaced by a NULL 564 * and the address of the NULL is returned 565 * Otherwise 566 * the address of the last character is returned. 567 * 568 * FIXME 569 * "c:\": keep backslash 570 */ 571 LPSTR WINAPI PathRemoveBackslashA( LPSTR lpszPath ) 572 { 573 int len; 574 LPSTR szTemp = NULL; 575 576 if(lpszPath) 577 { 578 len = strlen(lpszPath); 579 szTemp = CharPrevA(lpszPath, lpszPath+len); 580 if (! PathIsRootA(lpszPath)) 581 { 582 if (*szTemp == '\\') *szTemp = '\0'; 583 } 584 } 585 return szTemp; 586 } 587 588 /************************************************************************* 589 * PathRemoveBackslashW [SHLWAPI.@] 590 */ 591 LPWSTR WINAPI PathRemoveBackslashW( LPWSTR lpszPath ) 592 { 593 int len; 594 LPWSTR szTemp = NULL; 595 596 if(lpszPath) 597 { 598 len = strlenW(lpszPath); 599 szTemp = CharPrevW(lpszPath, lpszPath+len); 600 if (! PathIsRootW(lpszPath)) 601 { 602 if (*szTemp == '\\') *szTemp = '\0'; 603 } 604 } 605 return szTemp; 606 } 607 608 609 /* 610 Path Manipulations 611 */ 612 613 /************************************************************************* 614 * PathRemoveBlanksA [SHLWAPI.@] 615 * 616 * NOTES 617 * remove spaces from beginning and end of passed string 618 */ 619 void WINAPI PathRemoveBlanksA(LPSTR str) 620 { 621 LPSTR x = str; 622 623 TRACE("%s\n",str); 624 625 if(str) 626 { 627 while (*x==' ') x = CharNextA(x); 628 if (x!=str) strcpy(str,x); 629 x=str+strlen(str)-1; 630 while (*x==' ') x = CharPrevA(str, x); 631 if (*x==' ') *x='\0'; 632 } 633 } 634 635 /************************************************************************* 636 * PathRemoveBlanksW [SHLWAPI.@] 637 */ 638 void WINAPI PathRemoveBlanksW(LPWSTR str) 639 { 640 LPWSTR x = str; 641 642 TRACE("%s\n",debugstr_w(str)); 643 644 if(str) 645 { 646 while (*x==' ') x = CharNextW(x); 647 if (x!=str) strcpyW(str,x); 648 x=str+strlenW(str)-1; 649 while (*x==' ') x = CharPrevW(str, x); 650 if (*x==' ') *x='\0'; 651 } 652 } 653 654 /************************************************************************* 655 * PathQuoteSpacesA [SHLWAPI.@] 656 * 657 */ 658 LPSTR WINAPI PathQuoteSpacesA(LPSTR lpszPath) 659 { 660 TRACE("%s\n",lpszPath); 661 662 if(StrChrA(lpszPath,' ')) 663 { 664 int len = strlen(lpszPath); 665 RtlMoveMemory(lpszPath+1, lpszPath, len); 666 *(lpszPath++) = '"'; 667 lpszPath += len; 668 *(lpszPath++) = '"'; 669 *(lpszPath) = '\0'; 670 return --lpszPath; 671 } 672 return 0; 673 } 674 675 /************************************************************************* 676 * PathQuoteSpacesW [SHLWAPI.@] 677 */ 678 LPWSTR WINAPI PathQuoteSpacesW(LPWSTR lpszPath) 679 { 680 TRACE("%s\n",debugstr_w(lpszPath)); 681 682 if(StrChrW(lpszPath,' ')) 683 { 684 int len = strlenW(lpszPath); 685 RtlMoveMemory(lpszPath+1, lpszPath, len*sizeof(WCHAR)); 686 *(lpszPath++) = '"'; 687 lpszPath += len; 688 *(lpszPath++) = '"'; 689 *(lpszPath) = '\0'; 690 return --lpszPath; 691 } 692 return 0; 693 } 694 695 /************************************************************************* 696 * PathUnquoteSpacesA [SHLWAPI.@] 697 * 698 * NOTES 699 * unquote string (remove ") 700 */ 701 VOID WINAPI PathUnquoteSpacesA(LPSTR str) 702 { 703 DWORD len = strlen(str); 704 705 TRACE("%s\n",str); 706 707 if (*str!='"') 708 return; 709 if (str[len-1]!='"') 710 return; 711 str[len-1]='\0'; 712 strcpy(str,str+1); 713 return; 714 } 715 716 /************************************************************************* 717 * PathUnquoteSpacesW [SHLWAPI.@] 718 */ 719 VOID WINAPI PathUnquoteSpacesW(LPWSTR str) 720 { 721 DWORD len = strlenW(str); 722 723 TRACE("%s\n",debugstr_w(str)); 724 725 if (*str!='"') 726 return; 727 if (str[len-1]!='"') 728 return; 729 str[len-1]='\0'; 730 strcpyW(str,str+1); 731 return; 732 } 733 734 /************************************************************************* 735 * PathParseIconLocationA [SHLWAPI.@] 736 */ 737 int WINAPI PathParseIconLocationA(LPSTR lpszPath) 738 { 739 LPSTR lpstrComma = strchr(lpszPath, ','); 740 int ret = 0; 741 742 TRACE("%s\n", debugstr_a(lpszPath)); 743 744 if (lpstrComma && lpstrComma[1]) 745 { 746 lpstrComma[0]='\0'; 747 ret = atoi(&lpstrComma[1]); 748 } 749 750 PathUnquoteSpacesA(lpszPath); 751 return ret; 752 } 753 754 /************************************************************************* 755 * PathParseIconLocationW [SHLWAPI.@] 756 */ 757 int WINAPI PathParseIconLocationW(LPWSTR lpszPath) 758 { 759 LPWSTR lpstrComma = strchrW(lpszPath, ','); 760 int ret = 0; 761 762 TRACE("%s\n", debugstr_w(lpszPath)); 763 764 if (lpstrComma && lpstrComma[1]) 765 { 766 lpstrComma[0]='\0'; 767 ret = _wtoi(&lpstrComma[1]); 768 } 769 PathUnquoteSpacesW(lpszPath); 770 return ret; 771 } 772 773 /* 774 ########## cleaning and resolving paths ########## 775 */ 776 777 /************************************************************************* 778 * PathFindOnPathA [SHLWAPI.@] 779 */ 780 BOOL WINAPI PathFindOnPathA(LPSTR sFile, LPCSTR *sOtherDirs) 781 { 782 FIXME("%s %p\n",sFile, sOtherDirs); 783 return FALSE; 784 } 785 786 /************************************************************************* 787 * PathFindOnPathW [SHLWAPI.@] 788 */ 789 BOOL WINAPI PathFindOnPathW(LPWSTR sFile, LPCWSTR *sOtherDirs) 790 { 791 FIXME("%s %p\n",debugstr_w(sFile), sOtherDirs); 792 return FALSE; 793 } 794 795 /************************************************************************* 796 * PathCompactPathExA [SHLWAPI.@] 797 */ 798 BOOL WINAPI PathCompactPathExA( 799 LPSTR pszOut, 800 LPCSTR pszSrc, 801 UINT cchMax, 802 DWORD dwFlags) 803 { 804 FIXME("%p %s 0x%08x 0x%08lx\n", pszOut, pszSrc, cchMax, dwFlags); 805 return FALSE; 806 } 807 808 /************************************************************************* 809 * PathCompactPathExW [SHLWAPI.@] 810 */ 811 BOOL WINAPI PathCompactPathExW( 812 LPWSTR pszOut, 813 LPCWSTR pszSrc, 814 UINT cchMax, 815 DWORD dwFlags) 816 { 817 FIXME("%p %s 0x%08x 0x%08lx\n", pszOut, debugstr_w(pszSrc), cchMax, dwFlags); 818 return FALSE; 819 } 820 821 /* 822 ########## Path Testing ########## 823 */ 824 825 /************************************************************************* 826 * PathIsUNCA [SHLWAPI.@] 827 * 828 * NOTES 829 * PathIsUNC(char*path); 830 */ 831 BOOL WINAPI PathIsUNCA(LPCSTR lpszPath) 832 { 833 TRACE("%s\n",lpszPath); 834 835 return (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\')); 836 } 837 838 /************************************************************************* 839 * PathIsUNCW [SHLWAPI.@] 840 */ 841 BOOL WINAPI PathIsUNCW(LPCWSTR lpszPath) 842 { 843 TRACE("%s\n",debugstr_w(lpszPath)); 844 845 return (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\')); 846 } 847 848 /************************************************************************* 849 * PathIsRelativeA [SHLWAPI.@] 850 */ 851 BOOL WINAPI PathIsRelativeA (LPCSTR lpszPath) 852 { 853 TRACE("lpszPath=%s\n",lpszPath); 854 855 return (lpszPath && (lpszPath[0]!='\\' && lpszPath[1]!=':')); 856 } 857 858 /************************************************************************* 859 * PathIsRelativeW [SHLWAPI.@] 860 */ 861 BOOL WINAPI PathIsRelativeW (LPCWSTR lpszPath) 862 { 863 TRACE("lpszPath=%s\n",debugstr_w(lpszPath)); 864 865 return (lpszPath && (lpszPath[0]!='\\' && lpszPath[1]!=':')); 866 } 867 868 /************************************************************************* 869 * PathIsRootA [SHLWAPI.@] 870 * 871 * notes 872 * TRUE if the path points to a root directory 873 */ 874 BOOL WINAPI PathIsRootA(LPCSTR lpszPath) 875 { 876 TRACE("%s\n",lpszPath); 877 878 /* X:\ */ 879 if (lpszPath[1]==':' && lpszPath[2]=='\\' && lpszPath[3]=='\0') 880 return TRUE; 881 882 /* "\" */ 883 if (lpszPath[0]=='\\' && lpszPath[1]=='\0') 884 return TRUE; 885 886 /* UNC "\\<computer>\<share>" */ 887 if (lpszPath[0]=='\\' && lpszPath[1]=='\\') 888 { 889 int foundbackslash = 0; 890 lpszPath += 2; 891 while (*lpszPath) 892 { 893 if (*lpszPath=='\\') foundbackslash++; 894 lpszPath = CharNextA(lpszPath); 895 } 896 if (foundbackslash <= 1) 897 return TRUE; 898 } 899 return FALSE; 900 } 901 902 /************************************************************************* 903 * PathIsRootW [SHLWAPI.@] 904 */ 905 BOOL WINAPI PathIsRootW(LPCWSTR lpszPath) 906 { 907 TRACE("%s\n",debugstr_w(lpszPath)); 908 909 /* X:\ */ 910 if (lpszPath[1]==':' && lpszPath[2]=='\\' && lpszPath[3]=='\0') 911 return TRUE; 912 913 /* "\" */ 914 if (lpszPath[0]=='\\' && lpszPath[1]=='\0') 915 return TRUE; 916 917 /* UNC "\\<computer>\<share>" */ 918 if (lpszPath[0]=='\\' && lpszPath[1]=='\\') 919 { 920 int foundbackslash = 0; 921 lpszPath += 2; 922 while (*lpszPath) 923 { 924 if (*lpszPath=='\\') foundbackslash++; 925 lpszPath = CharNextW(lpszPath); 926 } 927 if (foundbackslash <= 1) 928 return TRUE; 929 } 930 return FALSE; 931 932 } 933 934 /************************************************************************* 935 * PathIsDirectoryA [SHLWAPI.@] 1485 * Although this function is prototyped as returning a BOOL, it returns 1486 * FILE_ATTRIBUTE_DIRECTORY for success. This means that code such as: 1487 * 1488 * if (PathIsDirectoryA("c:\\windows\\") == TRUE) 1489 * ... 1490 * 1491 * will always fail. 936 1492 */ 937 1493 BOOL WINAPI PathIsDirectoryA(LPCSTR lpszPath) 938 1494 { 939 DWORD dwAttr; 940 941 TRACE("%s\n", debugstr_a(lpszPath)); 942 943 dwAttr = GetFileAttributesA(lpszPath); 944 return (dwAttr != -1) ? dwAttr & FILE_ATTRIBUTE_DIRECTORY : 0; 1495 DWORD dwAttr; 1496 1497 TRACE("(%s)\n", debugstr_a(lpszPath)); 1498 1499 if (!lpszPath || PathIsUNCServerA(lpszPath)) 1500 return FALSE; 1501 1502 if (PathIsUNCServerShareA(lpszPath)) 1503 { 1504 FIXME("UNC Server Share not yet supported - FAILING\n"); 1505 return FALSE; 1506 } 1507 1508 if ((dwAttr = GetFileAttributesA(lpszPath)) == -1) 1509 return FALSE; 1510 return dwAttr & FILE_ATTRIBUTE_DIRECTORY; 945 1511 } 946 1512 947 1513 /************************************************************************* 948 1514 * PathIsDirectoryW [SHLWAPI.@] 1515 * 1516 * See PathIsDirectoryA. 949 1517 */ 950 1518 BOOL WINAPI PathIsDirectoryW(LPCWSTR lpszPath) 951 1519 { 952 DWORD dwAttr; 953 954 TRACE("%s\n", debugstr_w(lpszPath)); 955 956 dwAttr = GetFileAttributesW(lpszPath); 957 return (dwAttr != -1) ? dwAttr & FILE_ATTRIBUTE_DIRECTORY : 0; 1520 DWORD dwAttr; 1521 1522 TRACE("(%s)\n", debugstr_w(lpszPath)); 1523 1524 if (!lpszPath || PathIsUNCServerW(lpszPath)) 1525 return FALSE; 1526 1527 if (PathIsUNCServerShareW(lpszPath)) 1528 { 1529 FIXME("UNC Server Share not yet supported - FAILING\n"); 1530 return FALSE; 1531 } 1532 1533 if ((dwAttr = GetFileAttributesW(lpszPath)) == -1) 1534 return FALSE; 1535 return dwAttr & FILE_ATTRIBUTE_DIRECTORY; 958 1536 } 959 1537 960 1538 /************************************************************************* 961 1539 * PathFileExistsA [SHLWAPI.@] 962 * 963 * NOTES 964 * file_exists(char *fn); 965 */ 966 BOOL WINAPI PathFileExistsA(LPCSTR lpszPath) 967 { 968 TRACE("%s\n",lpszPath); 969 return (GetFileAttributesA(lpszPath)!=-1); 1540 * 1541 * Determine if a file exists. 1542 * 1543 * PARAMS 1544 * lpszPath [I] Path to check 1545 * 1546 * RETURNS 1547 * TRUE If the file exists and is readable 1548 * FALSE Otherwise 1549 */ 1550 BOOL WINAPI PathFileExistsA(LPCSTR lpszPath) 1551 { 1552 UINT iPrevErrMode; 1553 DWORD dwAttr; 1554 1555 TRACE("(%s)\n",debugstr_a(lpszPath)); 1556 1557 if (!lpszPath) 1558 return FALSE; 1559 1560 iPrevErrMode = SetErrorMode(1); 1561 dwAttr = GetFileAttributesA(lpszPath); 1562 SetErrorMode(iPrevErrMode); 1563 return dwAttr == -1 ? FALSE : TRUE; 970 1564 } 971 1565 972 1566 /************************************************************************* 973 1567 * PathFileExistsW [SHLWAPI.@] 974 */ 975 BOOL WINAPI PathFileExistsW(LPCWSTR lpszPath) 976 { 977 TRACE("%s\n",debugstr_w(lpszPath)); 978 return (GetFileAttributesW(lpszPath)!=-1); 1568 * 1569 * See PathFileExistsA 1570 */ 1571 BOOL WINAPI PathFileExistsW(LPCWSTR lpszPath) 1572 { 1573 UINT iPrevErrMode; 1574 DWORD dwAttr; 1575 1576 TRACE("(%s)\n",debugstr_w(lpszPath)); 1577 1578 if (!lpszPath) 1579 return FALSE; 1580 1581 iPrevErrMode = SetErrorMode(1); 1582 dwAttr = GetFileAttributesW(lpszPath); 1583 SetErrorMode(iPrevErrMode); 1584 return dwAttr == -1 ? FALSE : TRUE; 979 1585 } 980 1586 981 1587 /************************************************************************* 982 1588 * PathMatchSingleMaskA [internal] 983 * 1589 * 984 1590 * NOTES 985 1591 * internal (used by PathMatchSpec) … … 987 1593 static BOOL PathMatchSingleMaskA(LPCSTR name, LPCSTR mask) 988 1594 { 989 while (*name && *mask && *mask!=';') 1595 while (*name && *mask && *mask!=';') 990 1596 { 991 if (*mask=='*') 1597 if (*mask=='*') 992 1598 { 993 do 1599 do 994 1600 { 995 1601 if (PathMatchSingleMaskA(name,mask+1)) return 1; /* try substrings */ … … 1001 1607 mask = CharNextA(mask); 1002 1608 } 1003 if (!*name) 1609 if (!*name) 1004 1610 { 1005 1611 while (*mask=='*') mask++; … … 1014 1620 static BOOL PathMatchSingleMaskW(LPCWSTR name, LPCWSTR mask) 1015 1621 { 1016 while (*name && *mask && *mask!=';') 1622 while (*name && *mask && *mask!=';') 1017 1623 { 1018 if (*mask=='*') 1624 if (*mask=='*') 1019 1625 { 1020 do 1626 do 1021 1627 { 1022 1628 if (PathMatchSingleMaskW(name,mask+1)) return 1; /* try substrings */ … … 1028 1634 mask = CharNextW(mask); 1029 1635 } 1030 if (!*name) 1636 if (!*name) 1031 1637 { 1032 1638 while (*mask=='*') mask++; … … 1035 1641 return 0; 1036 1642 } 1643 1037 1644 /************************************************************************* 1038 1645 * PathMatchSpecA [SHLWAPI.@] 1039 * 1646 * 1647 * Determine if a path matches one or more search masks. 1648 * 1649 * PARAMS 1650 * lpszPath [I] Path to check 1651 * lpszMask [I} Search mask(s) 1652 * 1653 * RETURNS 1654 * TRUE If lpszPath is valid and is matched 1655 * FALSE Otherwise 1656 * 1040 1657 * NOTES 1041 * used from COMDLG32 1042 */ 1043 BOOL WINAPI PathMatchSpecA(LPCSTR name, LPCSTR mask) 1658 * Multiple search masks may be given if they are seperated by ";". The 1659 * pattern "*.*" is treated specially in that it matches all paths (for 1660 * backwards compatability with DOS). 1661 */ 1662 BOOL WINAPI PathMatchSpecA(LPCSTR name, LPCSTR mask) 1044 1663 { 1045 1664 TRACE("%s %s\n",name,mask); … … 1047 1666 if (!lstrcmpA( mask, "*.*" )) return 1; /* we don't require a period */ 1048 1667 1049 while (*mask) 1668 while (*mask) 1050 1669 { 1051 1670 if (PathMatchSingleMaskA(name,mask)) return 1; /* helper function */ 1052 1671 while (*mask && *mask!=';') mask = CharNextA(mask); 1053 if (*mask==';') 1672 if (*mask==';') 1054 1673 { 1055 1674 mask++; … … 1062 1681 /************************************************************************* 1063 1682 * PathMatchSpecW [SHLWAPI.@] 1064 */ 1065 BOOL WINAPI PathMatchSpecW(LPCWSTR name, LPCWSTR mask) 1683 * 1684 * See PathMatchSpecA. 1685 */ 1686 BOOL WINAPI PathMatchSpecW(LPCWSTR name, LPCWSTR mask) 1066 1687 { 1067 1688 static const WCHAR stemp[] = { '*','.','*',0 }; … … 1070 1691 if (!lstrcmpW( mask, stemp )) return 1; /* we don't require a period */ 1071 1692 1072 while (*mask) 1693 while (*mask) 1073 1694 { 1074 1695 if (PathMatchSingleMaskW(name,mask)) return 1; /* helper function */ 1075 1696 while (*mask && *mask!=';') mask = CharNextW(mask); 1076 if (*mask==';') 1697 if (*mask==';') 1077 1698 { 1078 1699 mask++; … … 1086 1707 * PathIsSameRootA [SHLWAPI.@] 1087 1708 * 1088 * FIXME 1089 * what to do with "\path" ?? 1709 * Determine if two paths share the same root. 1710 * 1711 * PARAMS 1712 * lpszPath1 [I] Source path 1713 * lpszPath2 [I] Path to compare with 1714 * 1715 * RETURNS 1716 * TRUE If both paths are valid and share the same root. 1717 * FALSE If either path is invalid or the paths do not share the same root. 1090 1718 */ 1091 1719 BOOL WINAPI PathIsSameRootA(LPCSTR lpszPath1, LPCSTR lpszPath2) 1092 1720 { 1093 TRACE("%s %s\n", lpszPath1, lpszPath2); 1094 1095 if (PathIsRelativeA(lpszPath1) || PathIsRelativeA(lpszPath2)) return FALSE; 1096 1097 /* usual path */ 1098 if ( toupper(lpszPath1[0])==toupper(lpszPath2[0]) && 1099 lpszPath1[1]==':' && lpszPath2[1]==':' && 1100 lpszPath1[2]=='\\' && lpszPath2[2]=='\\') 1101 return TRUE; 1102 1103 /* UNC */ 1104 if (lpszPath1[0]=='\\' && lpszPath2[0]=='\\' && 1105 lpszPath1[1]=='\\' && lpszPath2[1]=='\\') 1106 { 1107 int pos=2, bsfound=0; 1108 while (lpszPath1[pos] && lpszPath2[pos] && 1109 (lpszPath1[pos] == lpszPath2[pos])) 1110 { 1111 if (lpszPath1[pos]=='\\') bsfound++; 1112 if (bsfound == 2) return TRUE; 1113 pos++; /* FIXME: use CharNext*/ 1114 } 1115 return (lpszPath1[pos] == lpszPath2[pos]); 1116 } 1117 return FALSE; 1721 LPCSTR lpszStart; 1722 DWORD dwLen; 1723 1724 TRACE("(%s,%s)\n", debugstr_a(lpszPath1), debugstr_a(lpszPath2)); 1725 1726 if (!lpszPath1 || !lpszPath2 || !(lpszStart = PathSkipRootA(lpszPath1))) 1727 return FALSE; 1728 1729 dwLen = PathCommonPrefixA(lpszPath1, lpszPath2, NULL) + 1; 1730 if (lpszStart - lpszPath1 > dwLen) 1731 return FALSE; /* Paths not common up to length of the root */ 1732 return TRUE; 1118 1733 } 1119 1734 1120 1735 /************************************************************************* 1121 1736 * PathIsSameRootW [SHLWAPI.@] 1737 * 1738 * See PathIsSameRootA. 1122 1739 */ 1123 1740 BOOL WINAPI PathIsSameRootW(LPCWSTR lpszPath1, LPCWSTR lpszPath2) 1124 1741 { 1125 TRACE("%s %s\n", debugstr_w(lpszPath1), debugstr_w(lpszPath2)); 1126 1127 if (PathIsRelativeW(lpszPath1) || PathIsRelativeW(lpszPath2)) return FALSE; 1128 1129 /* usual path */ 1130 if ( toupperW(lpszPath1[0])==toupperW(lpszPath2[0]) && 1131 lpszPath1[1]==':' && lpszPath2[1]==':' && 1132 lpszPath1[2]=='\\' && lpszPath2[2]=='\\') 1133 return TRUE; 1134 1135 /* UNC */ 1136 if (lpszPath1[0]=='\\' && lpszPath2[0]=='\\' && 1137 lpszPath1[1]=='\\' && lpszPath2[1]=='\\') 1138 { 1139 int pos=2, bsfound=0; 1140 while (lpszPath1[pos] && lpszPath2[pos] && 1141 (lpszPath1[pos] == lpszPath2[pos])) 1142 { 1143 if (lpszPath1[pos]=='\\') bsfound++; 1144 if (bsfound == 2) return TRUE; 1145 pos++;/* FIXME: use CharNext*/ 1146 } 1147 return (lpszPath1[pos] == lpszPath2[pos]); 1148 } 1149 return FALSE; 1150 } 1151 1152 /************************************************************************* 1153 * PathIsURLA (SHLWAPI.@) 1742 LPCWSTR lpszStart; 1743 DWORD dwLen; 1744 1745 TRACE("(%s,%s)\n", debugstr_w(lpszPath1), debugstr_w(lpszPath2)); 1746 1747 if (!lpszPath1 || !lpszPath2 || !(lpszStart = PathSkipRootW(lpszPath1))) 1748 return FALSE; 1749 1750 dwLen = PathCommonPrefixW(lpszPath1, lpszPath2, NULL) + 1; 1751 if (lpszStart - lpszPath1 > dwLen) 1752 return FALSE; /* Paths not common up to length of the root */ 1753 return TRUE; 1754 } 1755 1756 /************************************************************************* 1757 * PathIsURLA [SHLWAPI.@] 1758 * 1759 * Check if the given path is a URL. 1760 * 1761 * PARAMS 1762 * lpszPath [I] Path to check. 1763 * 1764 * RETURNS 1765 * TRUE if lpszPath is a URL. 1766 * FALSE if lpszPath is NULL or not a URL. 1154 1767 */ 1155 1768 BOOL WINAPI PathIsURLA(LPCSTR lpstrPath) … … 1163 1776 base.size = 24; 1164 1777 res1 = SHLWAPI_1(lpstrPath, &base); 1165 1166 #ifdef __WIN32OS2__1167 // PH 2002-02-26 Fixes crash on Flask->About1168 // ShellExecute("..\doc\readme.html")1169 if (S_OK != res1)1170 return FALSE;1171 #endif1172 1173 1778 return (base.fcncde) ? TRUE : FALSE; 1174 } 1175 1176 /************************************************************************* 1177 * PathIsURLW (SHLWAPI.@)1779 } 1780 1781 /************************************************************************* 1782 * PathIsURLW [SHLWAPI.@] 1178 1783 */ 1179 1784 BOOL WINAPI PathIsURLW(LPCWSTR lpstrPath) … … 1187 1792 base.size = 24; 1188 1793 res1 = SHLWAPI_2(lpstrPath, &base); 1189 1190 #ifdef __WIN32OS2__ 1191 // PH 2002-02-26 Fixes crash on Flask->About 1192 // ShellExecute("..\doc\readme.html") 1193 if (S_OK != res1) 1794 return (base.fcncde) ? TRUE : FALSE; 1795 } 1796 1797 /************************************************************************* 1798 * PathIsContentTypeA [SHLWAPI.@] 1799 * 1800 * Determine if a file is of a registered content type. 1801 * 1802 * PARAMS 1803 * lpszPath [I] file to chack 1804 * 1805 * RETURNS 1806 * TRUE If lpszPath is a registered content type 1807 * FALSE Otherwise. 1808 */ 1809 BOOL WINAPI PathIsContentTypeA(LPCSTR lpszPath, LPCSTR lpszContentType) 1810 { 1811 LPCSTR szExt; 1812 DWORD dwDummy; 1813 char szBuff[MAX_PATH]; 1814 1815 TRACE("(%s,%s)\n", debugstr_a(lpszPath), debugstr_a(lpszContentType)); 1816 1817 if (lpszPath && (szExt = PathFindExtensionA(lpszPath)) && *szExt && 1818 !SHGetValueA(HKEY_CLASSES_ROOT, szExt, "Content Type", 1819 REG_NONE, szBuff, &dwDummy) && 1820 !strcasecmp(lpszContentType, szBuff)) 1821 { 1822 return TRUE; 1823 } 1824 return FALSE; 1825 } 1826 1827 /************************************************************************* 1828 * PathIsContentTypeW [SHLWAPI.@] 1829 * 1830 * See PathIsContentTypeA. 1831 */ 1832 BOOL WINAPI PathIsContentTypeW(LPCWSTR lpszPath, LPCWSTR lpszContentType) 1833 { 1834 static const WCHAR szContentType[] = { 'C','o','n','t','e','n','t',' ','T','y','p','e','\0' }; 1835 LPCWSTR szExt; 1836 DWORD dwDummy; 1837 WCHAR szBuff[MAX_PATH]; 1838 1839 TRACE("(%s,%s)\n", debugstr_w(lpszPath), debugstr_w(lpszContentType)); 1840 1841 if (lpszPath && (szExt = PathFindExtensionW(lpszPath)) && *szExt && 1842 !SHGetValueW(HKEY_CLASSES_ROOT, szExt, szContentType, 1843 REG_NONE, szBuff, &dwDummy) && 1844 !strcmpiW(lpszContentType, szBuff)) 1845 { 1846 return TRUE; 1847 } 1848 return FALSE; 1849 } 1850 1851 /************************************************************************* 1852 * PathIsFileSpecA [SHLWAPI.@] 1853 * 1854 * Determine if a path is a file specification. 1855 * 1856 * PARAMS 1857 * lpszPath [I] Path to chack 1858 * 1859 * RETURNS 1860 * TRUE If lpszPath is a file spec (contains no directories). 1861 * FALSE Otherwise. 1862 */ 1863 BOOL WINAPI PathIsFileSpecA(LPCSTR lpszPath) 1864 { 1865 TRACE("(%s)\n", debugstr_a(lpszPath)); 1866 1867 if (!lpszPath) 1868 return FALSE; 1869 1870 while (*lpszPath) 1871 { 1872 if (*lpszPath == '\\' || *lpszPath == ':') 1194 1873 return FALSE; 1195 #endif 1196 1197 return (base.fcncde) ? TRUE : FALSE; 1198 } 1199 1200 1201 /************************************************************************* 1202 * PathIsContentTypeA [SHLWAPI.@] 1203 */ 1204 BOOL WINAPI PathIsContentTypeA(LPCSTR pszPath, LPCSTR pszContentType) 1205 { 1206 FIXME("%s %s\n", pszPath, pszContentType); 1207 return FALSE; 1208 } 1209 1210 /************************************************************************* 1211 * PathIsContentTypeW [SHLWAPI.@] 1212 */ 1213 BOOL WINAPI PathIsContentTypeW(LPCWSTR pszPath, LPCWSTR pszContentType) 1214 { 1215 FIXME("%s %s\n", debugstr_w(pszPath), debugstr_w(pszContentType)); 1216 return FALSE; 1217 } 1218 1219 /************************************************************************* 1220 * PathIsFileSpecA [SHLWAPI.@] 1221 */ 1222 BOOL WINAPI PathIsFileSpecA(LPCSTR pszPath) 1223 { 1224 FIXME("%s\n", pszPath); 1225 return FALSE; 1226 } 1227 1228 /************************************************************************* 1229 * PathIsFileSpecW [SHLWAPI.@] 1230 */ 1231 BOOL WINAPI PathIsFileSpecW(LPCWSTR pszPath) 1232 { 1233 FIXME("%s\n", debugstr_w(pszPath)); 1234 return FALSE; 1235 } 1236 1237 /************************************************************************* 1238 * PathIsPrefixA [SHLWAPI.@] 1239 */ 1240 BOOL WINAPI PathIsPrefixA(LPCSTR pszPrefix, LPCSTR pszPath) 1241 { 1242 FIXME("%s %s\n", pszPrefix, pszPath); 1243 return FALSE; 1244 } 1245 1246 /************************************************************************* 1247 * PathIsPrefixW [SHLWAPI.@] 1248 */ 1249 BOOL WINAPI PathIsPrefixW(LPCWSTR pszPrefix, LPCWSTR pszPath) 1250 { 1251 FIXME("%s %s\n", debugstr_w(pszPrefix), debugstr_w(pszPath)); 1252 return FALSE; 1253 } 1254 1255 /************************************************************************* 1256 * PathIsSystemFolderA [SHLWAPI.@] 1257 */ 1258 BOOL WINAPI PathIsSystemFolderA(LPCSTR pszPath, DWORD dwAttrb) 1259 { 1260 FIXME("%s 0x%08lx\n", pszPath, dwAttrb); 1261 return FALSE; 1262 } 1263 1264 /************************************************************************* 1265 * PathIsSystemFolderW [SHLWAPI.@] 1266 */ 1267 BOOL WINAPI PathIsSystemFolderW(LPCWSTR pszPath, DWORD dwAttrb) 1268 { 1269 FIXME("%s 0x%08lx\n", debugstr_w(pszPath), dwAttrb); 1270 return FALSE; 1271 } 1272 1273 /************************************************************************* 1274 * PathIsUNCServerA [SHLWAPI.@] 1275 */ 1276 BOOL WINAPI PathIsUNCServerA( 1277 LPCSTR lpszPath) 1278 { 1279 TRACE("%s\n", debugstr_a(lpszPath)); 1280 if (lpszPath[0]=='\\' && lpszPath[1]=='\\') 1281 { 1282 int foundbackslash = 0; 1283 lpszPath += 2; 1284 while (*lpszPath) 1285 { 1286 if (*lpszPath=='\\') foundbackslash++; 1287 lpszPath = CharNextA(lpszPath); 1288 } 1289 if (foundbackslash == 0) 1290 return TRUE; 1291 } 1292 return FALSE; 1293 } 1294 1295 /************************************************************************* 1296 * PathIsUNCServerW [SHLWAPI.@] 1297 */ 1298 BOOL WINAPI PathIsUNCServerW( 1299 LPCWSTR lpszPath) 1300 { 1301 TRACE("%s\n", debugstr_w(lpszPath)); 1302 if (lpszPath[0]=='\\' && lpszPath[1]=='\\') 1303 { 1304 int foundbackslash = 0; 1305 lpszPath += 2; 1306 while (*lpszPath) 1307 { 1308 if (*lpszPath=='\\') foundbackslash++; 1309 lpszPath = CharNextW(lpszPath); 1310 } 1311 if (foundbackslash == 0) 1312 return TRUE; 1313 } 1314 return FALSE; 1315 } 1316 1317 /************************************************************************* 1318 * PathIsUNCServerShareA [SHLWAPI.@] 1319 */ 1320 BOOL WINAPI PathIsUNCServerShareA( 1321 LPCSTR lpszPath) 1322 { 1323 TRACE("%s\n", debugstr_a(lpszPath)); 1324 if (lpszPath[0]=='\\' && lpszPath[1]=='\\') 1325 { 1326 int foundbackslash = 0; 1327 lpszPath += 2; 1328 while (*lpszPath) 1329 { 1330 if (*lpszPath=='\\') foundbackslash++; 1331 lpszPath = CharNextA(lpszPath); 1332 } 1333 if (foundbackslash == 1) 1334 return TRUE; 1335 } 1336 return FALSE; 1337 } 1338 1339 /************************************************************************* 1340 * PathIsUNCServerShareW [SHLWAPI.@] 1341 */ 1342 BOOL WINAPI PathIsUNCServerShareW( 1343 LPCWSTR lpszPath) 1344 { 1345 TRACE("%s\n", debugstr_w(lpszPath)); 1346 if (lpszPath[0]=='\\' && lpszPath[1]=='\\') 1347 { 1348 int foundbackslash = 0; 1349 lpszPath += 2; 1350 while (*lpszPath) 1351 { 1352 if (*lpszPath=='\\') foundbackslash++; 1353 lpszPath = CharNextW(lpszPath); 1354 } 1355 if (foundbackslash == 1) 1356 return TRUE; 1357 } 1358 return FALSE; 1874 lpszPath = CharNextA(lpszPath); 1875 } 1876 return TRUE; 1877 } 1878 1879 /************************************************************************* 1880 * PathIsFileSpecW [SHLWAPI.@] 1881 * 1882 * See PathIsFileSpecA. 1883 */ 1884 BOOL WINAPI PathIsFileSpecW(LPCWSTR lpszPath) 1885 { 1886 TRACE("(%s)\n", debugstr_w(lpszPath)); 1887 1888 if (!lpszPath) 1889 return FALSE; 1890 1891 while (*lpszPath) 1892 { 1893 if (*lpszPath == '\\' || *lpszPath == ':') 1894 return FALSE; 1895 lpszPath = CharNextW(lpszPath); 1896 } 1897 return TRUE; 1898 } 1899 1900 /************************************************************************* 1901 * PathIsPrefixA [SHLWAPI.@] 1902 * 1903 * Determine if a path is a prefix of another. 1904 * 1905 * PARAMS 1906 * lpszPrefix [I] Prefix 1907 * lpszPath [i] Path to check 1908 * 1909 * RETURNS 1910 * TRUE If lpszPath has lpszPrefix as its prefix 1911 * FALSE If either path is NULL or lpszPrefix is not a prefix 1912 */ 1913 BOOL WINAPI PathIsPrefixA (LPCSTR lpszPrefix, LPCSTR lpszPath) 1914 { 1915 TRACE("(%s,%s)\n", debugstr_a(lpszPrefix), debugstr_a(lpszPath)); 1916 1917 if (lpszPrefix && lpszPath && 1918 PathCommonPrefixA(lpszPath, lpszPrefix, NULL) == strlen(lpszPrefix)) 1919 return TRUE; 1920 return FALSE; 1921 } 1922 1923 /************************************************************************* 1924 * PathIsPrefixW [SHLWAPI.@] 1925 * 1926 * See PathIsPrefixA. 1927 */ 1928 BOOL WINAPI PathIsPrefixW(LPCWSTR lpszPrefix, LPCWSTR lpszPath) 1929 { 1930 TRACE("(%s,%s)\n", debugstr_w(lpszPrefix), debugstr_w(lpszPath)); 1931 1932 if (lpszPrefix && lpszPath && 1933 PathCommonPrefixW(lpszPath, lpszPrefix, NULL) == strlenW(lpszPrefix)) 1934 return TRUE; 1935 return FALSE; 1936 } 1937 1938 /************************************************************************* 1939 * PathIsSystemFolderA [SHLWAPI.@] 1940 * 1941 * Determine if a path or file attributes are a system folder. 1942 * 1943 * PARAMS 1944 * lpszPath [I] Path to check. 1945 * dwAttrib [I] Attributes to check, if lpszPath is NULL. 1946 * 1947 * RETURNS 1948 * TRUE If lpszPath or dwAttrib are a system folder. 1949 * FALSE If GetFileAttributesA fails or neither parameter is a system folder. 1950 */ 1951 BOOL WINAPI PathIsSystemFolderA(LPCSTR lpszPath, DWORD dwAttrib) 1952 { 1953 TRACE("(%s,0x%08lx)\n", debugstr_a(lpszPath), dwAttrib); 1954 1955 if (lpszPath && *lpszPath) 1956 dwAttrib = GetFileAttributesA(lpszPath); 1957 1958 if (dwAttrib == -1 || !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY) || 1959 !(dwAttrib & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY))) 1960 return FALSE; 1961 return TRUE; 1962 } 1963 1964 /************************************************************************* 1965 * PathIsSystemFolderW [SHLWAPI.@] 1966 * 1967 * See PathIsSystemFolderA. 1968 */ 1969 BOOL WINAPI PathIsSystemFolderW(LPCWSTR lpszPath, DWORD dwAttrib) 1970 { 1971 TRACE("(%s,0x%08lx)\n", debugstr_w(lpszPath), dwAttrib); 1972 1973 if (lpszPath && *lpszPath) 1974 dwAttrib = GetFileAttributesW(lpszPath); 1975 1976 if (dwAttrib == -1 || !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY) || 1977 !(dwAttrib & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY))) 1978 return FALSE; 1979 return TRUE; 1980 } 1981 1982 /************************************************************************* 1983 * PathIsUNCA [SHLWAPI.@] 1984 * 1985 * Determine if a path is in UNC format. 1986 * 1987 * PARAMS 1988 * lpszPath [I] Path to check 1989 * 1990 * RETURNS 1991 * TRUE: The path is UNC. 1992 * FALSE: The path is not UNC or is NULL. 1993 */ 1994 BOOL WINAPI PathIsUNCA(LPCSTR lpszPath) 1995 { 1996 TRACE("(%s)\n",debugstr_a(lpszPath)); 1997 1998 if (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\')) 1999 return TRUE; 2000 return FALSE; 2001 } 2002 2003 /************************************************************************* 2004 * PathIsUNCW [SHLWAPI.@] 2005 * 2006 * See PathIsUNCA. 2007 */ 2008 BOOL WINAPI PathIsUNCW(LPCWSTR lpszPath) 2009 { 2010 TRACE("(%s)\n",debugstr_w(lpszPath)); 2011 2012 if (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\')) 2013 return TRUE; 2014 return FALSE; 2015 } 2016 2017 /************************************************************************* 2018 * PathIsUNCServerA [SHLWAPI.@] 2019 * 2020 * Determine if a path is a UNC server name ("\\SHARENAME"). 2021 * 2022 * PARAMS 2023 * lpszPath [I] Path to check. 2024 * 2025 * RETURNS 2026 * TRUE If lpszPath is a valid UNC server name. 2027 * FALSE Otherwise. 2028 * 2029 * NOTES 2030 * This routine is bug compatible with Win32: Server names with a 2031 * trailing backslash (e.g. "\\FOO\"), return FALSE incorrectly. 2032 * Fixing this bug may break other shlwapi functions! 2033 */ 2034 BOOL WINAPI PathIsUNCServerA(LPCSTR lpszPath) 2035 { 2036 TRACE("(%s)\n", debugstr_a(lpszPath)); 2037 2038 if (lpszPath && *lpszPath++ == '\\' && *lpszPath++ == '\\') 2039 { 2040 while (*lpszPath) 2041 { 2042 if (*lpszPath == '\\') 2043 return FALSE; 2044 lpszPath = CharNextA(lpszPath); 2045 } 2046 return TRUE; 2047 } 2048 return FALSE; 2049 } 2050 2051 /************************************************************************* 2052 * PathIsUNCServerW [SHLWAPI.@] 2053 * 2054 * See PathIsUNCServerA. 2055 */ 2056 BOOL WINAPI PathIsUNCServerW(LPCWSTR lpszPath) 2057 { 2058 TRACE("(%s)\n", debugstr_w(lpszPath)); 2059 2060 if (lpszPath && *lpszPath++ == '\\' && *lpszPath++ == '\\') 2061 { 2062 while (*lpszPath) 2063 { 2064 if (*lpszPath == '\\') 2065 return FALSE; 2066 lpszPath = CharNextW(lpszPath); 2067 } 2068 return TRUE; 2069 } 2070 return FALSE; 2071 } 2072 2073 /************************************************************************* 2074 * PathIsUNCServerShareA [SHLWAPI.@] 2075 * 2076 * Determine if a path is a UNC server share ("\\SHARENAME\SHARE"). 2077 * 2078 * PARAMS 2079 * lpszPath [I] Path to check. 2080 * 2081 * RETURNS 2082 * TRUE If lpszPath is a valid UNC server share. 2083 * FALSE Otherwise. 2084 * 2085 * NOTES 2086 * This routine is bug compatible with Win32: Server shares with a 2087 * trailing backslash (e.g. "\\FOO\BAR\"), return FALSE incorrectly. 2088 * Fixing this bug may break other shlwapi functions! 2089 */ 2090 BOOL WINAPI PathIsUNCServerShareA(LPCSTR lpszPath) 2091 { 2092 TRACE("(%s)\n", debugstr_a(lpszPath)); 2093 2094 if (lpszPath && *lpszPath++ == '\\' && *lpszPath++ == '\\') 2095 { 2096 BOOL bSeenSlash = FALSE; 2097 while (*lpszPath) 2098 { 2099 if (*lpszPath == '\\') 2100 { 2101 if (bSeenSlash) 2102 return FALSE; 2103 bSeenSlash = TRUE; 2104 } 2105 lpszPath = CharNextA(lpszPath); 2106 } 2107 return bSeenSlash; 2108 } 2109 return FALSE; 2110 } 2111 2112 /************************************************************************* 2113 * PathIsUNCServerShareW [SHLWAPI.@] 2114 * 2115 * See PathIsUNCServerShareA. 2116 */ 2117 BOOL WINAPI PathIsUNCServerShareW(LPCWSTR lpszPath) 2118 { 2119 TRACE("(%s)\n", debugstr_w(lpszPath)); 2120 2121 if (lpszPath && *lpszPath++ == '\\' && *lpszPath++ == '\\') 2122 { 2123 BOOL bSeenSlash = FALSE; 2124 while (*lpszPath) 2125 { 2126 if (*lpszPath == '\\') 2127 { 2128 if (bSeenSlash) 2129 return FALSE; 2130 bSeenSlash = TRUE; 2131 } 2132 lpszPath = CharNextW(lpszPath); 2133 } 2134 return bSeenSlash; 2135 } 2136 return FALSE; 1359 2137 } 1360 2138 … … 1362 2140 * PathCanonicalizeA [SHLWAPI.@] 1363 2141 * 1364 * FIXME 1365 * returnvalue, use CharNext 1366 */ 1367 1368 BOOL WINAPI PathCanonicalizeA(LPSTR pszBuf, LPCSTR pszPath) 1369 { 1370 int OffsetMin = 0, OffsetSrc = 0, OffsetDst = 0, LenSrc = strlen(pszPath); 1371 BOOL bModifyed = FALSE; 1372 1373 TRACE("%p %s\n", pszBuf, pszPath); 1374 1375 pszBuf[OffsetDst]='\0'; 1376 1377 /* keep the root of the path */ 1378 if( LenSrc && (pszPath[OffsetSrc]=='\\')) 1379 { 1380 pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--; 1381 } 1382 else if ( (LenSrc >= 2) && (pszPath[OffsetSrc+1] == ':')) 1383 { 1384 pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--; 1385 pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--; 1386 if (LenSrc && (pszPath[OffsetSrc] == '\\')) 1387 { 1388 pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--; 1389 if (LenSrc == 1 && pszPath[OffsetSrc]=='.') 1390 { 1391 /* C:\. */ 1392 OffsetSrc++; LenSrc--; bModifyed = TRUE; 1393 } 1394 else if (LenSrc == 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='.') 1395 { 1396 /* C:\.. */ 1397 OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE; 1398 } 2142 * Convert a path to its canonical form. 2143 * 2144 * PARAMS 2145 * lpszBuf [O] Output path 2146 * lpszPath [I] Path to cnonicalize 2147 * 2148 * RETURNS 2149 * Success: TRUE. lpszBuf contains the output path 2150 * Failure: FALSE, If input path is invalid. lpszBuf is undefined 2151 */ 2152 BOOL WINAPI PathCanonicalizeA(LPSTR lpszBuf, LPCSTR lpszPath) 2153 { 2154 BOOL bRet = FALSE; 2155 2156 TRACE("(%p,%s)\n", lpszBuf, debugstr_a(lpszPath)); 2157 2158 if (lpszBuf) 2159 *lpszBuf = '\0'; 2160 2161 if (!lpszBuf || !lpszPath) 2162 SetLastError(ERROR_INVALID_PARAMETER); 2163 else 2164 { 2165 WCHAR szPath[MAX_PATH]; 2166 WCHAR szBuff[MAX_PATH]; 2167 MultiByteToWideChar(0,0,lpszPath,-1,szPath,MAX_PATH); 2168 bRet = PathCanonicalizeW(szBuff, szPath); 2169 WideCharToMultiByte(0,0,szBuff,-1,lpszBuf,MAX_PATH,0,0); 2170 } 2171 return bRet; 2172 } 2173 2174 2175 /************************************************************************* 2176 * PathCanonicalizeW [SHLWAPI.@] 2177 * 2178 * See PathCanonicalizeA. 2179 */ 2180 BOOL WINAPI PathCanonicalizeW(LPWSTR lpszBuf, LPCWSTR lpszPath) 2181 { 2182 LPWSTR lpszDst = lpszBuf; 2183 LPCWSTR lpszSrc = lpszPath; 2184 2185 TRACE("(%p,%s)\n", lpszBuf, debugstr_w(lpszPath)); 2186 2187 if (lpszBuf) 2188 *lpszDst = '\0'; 2189 2190 if (!lpszBuf || !lpszPath) 2191 { 2192 SetLastError(ERROR_INVALID_PARAMETER); 2193 return FALSE; 2194 } 2195 2196 if (!*lpszPath) 2197 { 2198 *lpszBuf++ = '\\'; 2199 *lpszBuf = '\0'; 2200 return TRUE; 2201 } 2202 2203 /* Copy path root */ 2204 if (*lpszSrc == '\\') 2205 { 2206 *lpszDst++ = *lpszSrc++; 2207 } 2208 else if (*lpszSrc && lpszSrc[1] == ':') 2209 { 2210 /* X:\ */ 2211 *lpszDst++ = *lpszSrc++; 2212 *lpszDst++ = *lpszSrc++; 2213 if (*lpszSrc == '\\') 2214 *lpszDst++ = *lpszSrc++; 2215 } 2216 2217 /* Canonicalize the rest of the path */ 2218 while (*lpszSrc) 2219 { 2220 if (*lpszSrc == '.') 2221 { 2222 if (lpszSrc[1] == '\\' && (lpszSrc == lpszPath || lpszSrc[-1] == '\\' || lpszSrc[-1] == ':')) 2223 { 2224 lpszSrc += 2; /* Skip .\ */ 2225 } 2226 else if (lpszSrc[1] == '.' && (lpszDst == lpszBuf || lpszDst[-1] == '\\')) 2227 { 2228 /* \.. backs up a directory, over the root if it has no \ following X:. 2229 * .. is ignored if it would remove a UNC server name or inital \\ 2230 */ 2231 if (lpszDst != lpszBuf) 2232 { 2233 *lpszDst = '\0'; /* Allow PathIsUNCServerShareA test on lpszBuf */ 2234 if (lpszDst > lpszBuf+1 && lpszDst[-1] == '\\' && 2235 (lpszDst[-2] != '\\' || lpszDst > lpszBuf+2)) 2236 { 2237 if (lpszDst[-2] == ':' && (lpszDst > lpszBuf+3 || lpszDst[-3] == ':')) 2238 { 2239 lpszDst -= 2; 2240 while (lpszDst > lpszBuf && *lpszDst != '\\') 2241 lpszDst--; 2242 if (*lpszDst == '\\') 2243 lpszDst++; /* Reset to last '\' */ 2244 else 2245 lpszDst = lpszBuf; /* Start path again from new root */ 2246 } 2247 else if (lpszDst[-2] != ':' && !PathIsUNCServerShareW(lpszBuf)) 2248 lpszDst -= 2; 1399 2249 } 1400 } 1401 1402 /* ".\" at the beginning of the path */ 1403 if (LenSrc >= 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='\\') 1404 { 1405 OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE; 1406 } 1407 1408 while ( LenSrc ) 1409 { 1410 if((LenSrc>=3) && (pszPath[OffsetSrc]=='\\') && (pszPath[OffsetSrc+1]=='.') && (pszPath[OffsetSrc+2]=='.')) 1411 { 1412 /* "\.." found, go one deeper */ 1413 while((OffsetDst > OffsetMin) && (pszBuf[OffsetDst]!='\\')) OffsetDst--; 1414 OffsetSrc += 3; LenSrc -= 3; bModifyed = TRUE; 1415 if(OffsetDst == OffsetMin && pszPath[OffsetSrc]=='\\') OffsetSrc++; 1416 pszBuf[OffsetDst] = '\0'; /* important for \..\.. */ 1417 } 1418 else if(LenSrc>=2 && pszPath[OffsetSrc]=='\\' && pszPath[OffsetSrc+1]=='.' ) 1419 { 1420 /* "\." found, skip it */ 1421 OffsetSrc += 2; LenSrc-=2; bModifyed = TRUE; 1422 } 1423 else 1424 { 1425 pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; LenSrc--; 1426 } 1427 } 1428 pszBuf[OffsetDst] = '\0'; 1429 TRACE("-- %s %u\n", pszBuf, bModifyed); 1430 return bModifyed; 1431 } 1432 1433 1434 /************************************************************************* 1435 * PathCanonicalizeW [SHLWAPI.@] 1436 * 1437 * FIXME 1438 * returnvalue, use CharNext 1439 */ 1440 BOOL WINAPI PathCanonicalizeW(LPWSTR pszBuf, LPCWSTR pszPath) 1441 { 1442 int OffsetMin = 0, OffsetSrc = 0, OffsetDst = 0, LenSrc = strlenW(pszPath); 1443 BOOL bModifyed = FALSE; 1444 1445 TRACE("%p %s\n", pszBuf, debugstr_w(pszPath)); 1446 1447 pszBuf[OffsetDst]='\0'; 1448 1449 /* keep the root of the path */ 1450 if( LenSrc && (pszPath[OffsetSrc]=='\\')) 1451 { 1452 pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--; 1453 } 1454 else if ( (LenSrc >= 2) && (pszPath[OffsetSrc+1] == ':')) 1455 { 1456 pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--; 1457 pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--; 1458 if (LenSrc && (pszPath[OffsetSrc] == '\\')) 1459 { 1460 pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--; 1461 if (LenSrc == 1 && pszPath[OffsetSrc]=='.') 1462 { 1463 /* C:\. */ 1464 OffsetSrc++; LenSrc--; bModifyed = TRUE; 1465 } 1466 else if (LenSrc == 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='.') 1467 { 1468 /* C:\.. */ 1469 OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE; 1470 } 2250 while (lpszDst > lpszBuf && *lpszDst != '\\') 2251 lpszDst--; 2252 if (lpszDst == lpszBuf) 2253 { 2254 *lpszDst++ = '\\'; 2255 lpszSrc++; 1471 2256 } 1472 } 1473 1474 /* ".\" at the beginning of the path */ 1475 if (LenSrc >= 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='\\') 1476 { 1477 OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE; 1478 } 1479 1480 while ( LenSrc ) 1481 { 1482 if((LenSrc>=3) && (pszPath[OffsetSrc]=='\\') && (pszPath[OffsetSrc+1]=='.') && (pszPath[OffsetSrc+2]=='.')) 1483 { 1484 /* "\.." found, go one deeper */ 1485 while((OffsetDst > OffsetMin) && (pszBuf[OffsetDst]!='\\')) OffsetDst--; 1486 OffsetSrc += 3; LenSrc -= 3; bModifyed = TRUE; 1487 if(OffsetDst == OffsetMin && pszPath[OffsetSrc]=='\\') OffsetSrc++; 1488 pszBuf[OffsetDst] = '\0'; /* important for \..\.. */ 1489 } 1490 else if(LenSrc>=2 && pszPath[OffsetSrc]=='\\' && pszPath[OffsetSrc+1]=='.' ) 1491 { 1492 /* "\." found, skip it */ 1493 OffsetSrc += 2; LenSrc-=2; bModifyed = TRUE; 1494 } 1495 else 1496 { 1497 pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; LenSrc--; 1498 } 1499 } 1500 pszBuf[OffsetDst] = '\0'; 1501 TRACE("-- %s %u\n", debugstr_w(pszBuf), bModifyed); 1502 return bModifyed; 2257 } 2258 lpszSrc += 2; /* Skip .. in src path */ 2259 } 2260 else 2261 *lpszDst++ = *lpszSrc++; 2262 } 2263 else 2264 *lpszDst++ = *lpszSrc++; 2265 } 2266 /* Append \ to naked drive specs */ 2267 if (lpszDst - lpszBuf == 2 && lpszDst[-1] == ':') 2268 *lpszDst++ = '\\'; 2269 *lpszDst++ = '\0'; 2270 return TRUE; 1503 2271 } 1504 2272 … … 1506 2274 * PathFindNextComponentA [SHLWAPI.@] 1507 2275 * 2276 * Find the next component in a path. 2277 * 2278 * PARAMS 2279 * lpszPath [I] Path to find next component in 2280 * 2281 * RETURNS 2282 * Success: A pointer to the next component, or the end of the string 2283 * Failure: NULL, If lpszPath is invalid 2284 * 1508 2285 * NOTES 1509 * special cases: 1510 * "" null 1511 * aa "" (pointer to traling NULL) 1512 * aa\ "" (pointer to traling NULL) 1513 * aa\\ "" (pointer to traling NULL) 1514 * aa\\bb bb 1515 * aa\\\bb \bb 1516 * c:\aa\ "aa\" 1517 * \\aa aa 1518 * \\aa\b aa\b 1519 */ 1520 LPSTR WINAPI PathFindNextComponentA(LPCSTR pszPath) 1521 { 1522 LPSTR pos; 1523 1524 TRACE("%s\n", pszPath); 1525 1526 if(!pszPath || !*pszPath) return NULL; 1527 if(!(pos = StrChrA(pszPath, '\\'))) 1528 return (LPSTR) pszPath + strlen(pszPath); 1529 pos++; 1530 if(pos[0] == '\\') pos++; 1531 return pos; 2286 * A 'component' is either a backslash character (\) or UNC marker (\\). 2287 * Because of this, relative paths (e.g "c:foo") are regarded as having 2288 * only one component. 2289 */ 2290 LPSTR WINAPI PathFindNextComponentA(LPCSTR lpszPath) 2291 { 2292 LPSTR lpszSlash; 2293 2294 TRACE("(%s)\n", debugstr_a(lpszPath)); 2295 2296 if(!lpszPath || !*lpszPath) 2297 return NULL; 2298 2299 if ((lpszSlash = StrChrA(lpszPath, '\\'))) 2300 { 2301 if (lpszSlash[1] == '\\') 2302 lpszSlash++; 2303 return lpszSlash + 1; 2304 } 2305 return (LPSTR)lpszPath + strlen(lpszPath); 1532 2306 } 1533 2307 1534 2308 /************************************************************************* 1535 2309 * PathFindNextComponentW [SHLWAPI.@] 1536 */ 1537 LPWSTR WINAPI PathFindNextComponentW(LPCWSTR pszPath) 1538 { 1539 LPWSTR pos; 1540 1541 TRACE("%s\n", debugstr_w(pszPath)); 1542 1543 if(!pszPath || !*pszPath) return NULL; 1544 if (!(pos = StrChrW(pszPath, '\\'))) 1545 return (LPWSTR) pszPath + strlenW(pszPath); 1546 pos++; 1547 if(pos[0] == '\\') pos++; 1548 return pos; 2310 * 2311 * See PathFindNextComponentA. 2312 */ 2313 LPWSTR WINAPI PathFindNextComponentW(LPCWSTR lpszPath) 2314 { 2315 LPWSTR lpszSlash; 2316 2317 TRACE("(%s)\n", debugstr_w(lpszPath)); 2318 2319 if(!lpszPath || !*lpszPath) 2320 return NULL; 2321 2322 if ((lpszSlash = StrChrW(lpszPath, '\\'))) 2323 { 2324 if (lpszSlash[1] == '\\') 2325 lpszSlash++; 2326 return lpszSlash + 1; 2327 } 2328 return (LPWSTR)lpszPath + strlenW(lpszPath); 1549 2329 } 1550 2330 … … 1552 2332 * PathAddExtensionA [SHLWAPI.@] 1553 2333 * 2334 * Add a file extension to a path 2335 * 2336 * PARAMS 2337 * lpszPath [O] Path to add extension to 2338 * lpszExtension [I} Extension to add to lpszPath 2339 * 2340 * RETURNS 2341 * TRUE If the path was modified 2342 * FALSE If lpszPath or lpszExtension are invalid, lpszPath has an 2343 * extension allready, or the new path length is too big. 2344 * 2345 * FIXME 2346 * What version of shlwapi.dll adds "exe" if pszExtension is NULL? Win2k 2347 * does not do this, so the behaviour was removed. 2348 */ 2349 BOOL WINAPI PathAddExtensionA(LPSTR lpszPath, LPCSTR lpszExtension) 2350 { 2351 DWORD dwLen; 2352 2353 TRACE("(%s,%s)\n", debugstr_a(lpszPath), debugstr_a(lpszExtension)); 2354 2355 if (!lpszPath || !lpszExtension || *(PathFindExtensionA(lpszPath))) 2356 return FALSE; 2357 2358 dwLen = strlen(lpszPath); 2359 2360 if (dwLen + strlen(lpszExtension) >= MAX_PATH) 2361 return FALSE; 2362 2363 strcpy(lpszPath + dwLen, lpszExtension); 2364 return TRUE; 2365 } 2366 2367 /************************************************************************* 2368 * PathAddExtensionW [SHLWAPI.@] 2369 * 2370 * See PathAddExtensionA. 2371 */ 2372 BOOL WINAPI PathAddExtensionW(LPWSTR lpszPath, LPCWSTR lpszExtension) 2373 { 2374 DWORD dwLen; 2375 2376 TRACE("(%s,%s)\n", debugstr_w(lpszPath), debugstr_w(lpszExtension)); 2377 2378 if (!lpszPath || !lpszExtension || *(PathFindExtensionW(lpszPath))) 2379 return FALSE; 2380 2381 dwLen = strlenW(lpszPath); 2382 2383 if (dwLen + strlenW(lpszExtension) >= MAX_PATH) 2384 return FALSE; 2385 2386 strcpyW(lpszPath + dwLen, lpszExtension); 2387 return TRUE; 2388 } 2389 2390 /************************************************************************* 2391 * PathMakePrettyA [SHLWAPI.@] 2392 * 2393 * Convert an uppercase DOS filename into lowercase. 2394 * 2395 * PARAMS 2396 * lpszPath [O] Path to convert. 2397 * 2398 * RETURNS 2399 * TRUE If the path was an uppercase DOS path and was converted 2400 * FALSE Otherwise. 2401 */ 2402 BOOL WINAPI PathMakePrettyA(LPSTR lpszPath) 2403 { 2404 LPSTR pszIter = lpszPath; 2405 2406 TRACE("(%s)\n", debugstr_a(lpszPath)); 2407 2408 if (!pszIter || !*pszIter) 2409 return FALSE; 2410 2411 while (*pszIter) 2412 { 2413 if (islower(*pszIter) || IsDBCSLeadByte(*pszIter)) 2414 return FALSE; /* Not DOS path */ 2415 pszIter++; 2416 } 2417 pszIter = lpszPath + 1; 2418 while (*pszIter) 2419 { 2420 *pszIter = tolower(*pszIter); 2421 pszIter++; 2422 } 2423 return TRUE; 2424 } 2425 2426 /************************************************************************* 2427 * PathMakePrettyW [SHLWAPI.@] 2428 * 2429 * See PathMakePrettyA 2430 */ 2431 BOOL WINAPI PathMakePrettyW(LPWSTR lpszPath) 2432 { 2433 LPWSTR pszIter = lpszPath; 2434 2435 TRACE("(%s)\n", debugstr_w(lpszPath)); 2436 2437 if (!pszIter || !*pszIter) 2438 return FALSE; 2439 2440 while (*pszIter) 2441 { 2442 if (islowerW(*pszIter)) 2443 return FALSE; /* Not DOS path */ 2444 pszIter++; 2445 } 2446 pszIter = lpszPath + 1; 2447 while (*pszIter) 2448 { 2449 *pszIter = tolowerW(*pszIter); 2450 pszIter++; 2451 } 2452 return TRUE; 2453 } 2454 2455 /************************************************************************* 2456 * PathCommonPrefixA [SHLWAPI.@] 2457 * 2458 * Determine the length of the common prefix between two paths. 2459 * 2460 * PARAMS 2461 * lpszFile1 [I] First path for comparason 2462 * lpszFile2 [I] Second path for comparason 2463 * achPath [O] Destination for common prefix string 2464 * 2465 * RETURNS 2466 * The length of the common prefix. This is 0 if there is no common 2467 * prefix between the paths or if any parameters are invalid. If the prefix 2468 * is non-zero and achPath is not NULL, achPath is filled with the common 2469 * part of the prefix and NUL terminated. 2470 * 1554 2471 * NOTES 1555 * it adds never a dot 1556 */ 1557 1558 BOOL WINAPI PathAddExtensionA( 1559 LPSTR pszPath, 1560 LPCSTR pszExtension) 1561 { 1562 if (*pszPath) 1563 { 1564 if (*(PathFindExtensionA(pszPath))) return FALSE; 1565 1566 if (!pszExtension || *pszExtension=='\0') 1567 strcat(pszPath, "exe"); 1568 else 1569 strcat(pszPath, pszExtension); 1570 } 1571 1572 return TRUE; 1573 } 1574 1575 /************************************************************************* 1576 * PathAddExtensionW [SHLWAPI.@] 1577 */ 1578 BOOL WINAPI PathAddExtensionW( 1579 LPWSTR pszPath, 1580 LPCWSTR pszExtension) 1581 { 1582 static const WCHAR ext[] = { 'e','x','e',0 }; 1583 1584 if (*pszPath) 1585 { 1586 if (*(PathFindExtensionW(pszPath))) return FALSE; 1587 1588 if (!pszExtension || *pszExtension=='\0') 1589 strcatW(pszPath, ext); 1590 else 1591 strcatW(pszPath, pszExtension); 1592 } 1593 return TRUE; 1594 1595 } 1596 1597 /************************************************************************* 1598 * PathMakePrettyA [SHLWAPI.@] 1599 */ 1600 BOOL WINAPI PathMakePrettyA( 1601 LPSTR lpPath) 1602 { 1603 FIXME("%s\n", lpPath); 1604 return TRUE; 1605 } 1606 1607 /************************************************************************* 1608 * PathMakePrettyW [SHLWAPI.@] 1609 */ 1610 BOOL WINAPI PathMakePrettyW( 1611 LPWSTR lpPath) 1612 { 1613 FIXME("%s\n", debugstr_w(lpPath)); 1614 return TRUE; 1615 1616 } 1617 1618 /************************************************************************* 1619 * PathCommonPrefixA [SHLWAPI.@] 1620 */ 1621 int WINAPI PathCommonPrefixA( 1622 LPCSTR pszFile1, 1623 LPCSTR pszFile2, 1624 LPSTR achPath) 1625 { 1626 FIXME("%s %s %p\n", pszFile1, pszFile2, achPath); 1627 return 0; 1628 } 1629 1630 /************************************************************************* 1631 * PathCommonPrefixW [SHLWAPI.@] 1632 */ 1633 int WINAPI PathCommonPrefixW( 1634 LPCWSTR pszFile1, 1635 LPCWSTR pszFile2, 1636 LPWSTR achPath) 1637 { 1638 FIXME("%s %s %p\n", debugstr_w(pszFile1), debugstr_w(pszFile2),achPath ); 1639 return 0; 1640 } 1641 1642 /************************************************************************* 1643 * PathCompactPathA [SHLWAPI.@] 1644 */ 1645 BOOL WINAPI PathCompactPathA(HDC hDC, LPSTR pszPath, UINT dx) 1646 { 1647 FIXME("0x%08x %s 0x%08x\n", hDC, pszPath, dx); 1648 return FALSE; 1649 } 1650 1651 /************************************************************************* 1652 * PathCompactPathW [SHLWAPI.@] 1653 */ 1654 BOOL WINAPI PathCompactPathW(HDC hDC, LPWSTR pszPath, UINT dx) 1655 { 1656 FIXME("0x%08x %s 0x%08x\n", hDC, debugstr_w(pszPath), dx); 1657 return FALSE; 1658 } 1659 1660 /************************************************************************* 1661 * PathGetCharTypeA [SHLWAPI.@] 2472 * A common prefix of 2 is always returned as 3. It is thus possible for 2473 * the length returned to be invalid (i.e. Longer than one or both of the 2474 * strings given as parameters). This Win32 behaviour has been implimented 2475 * here, and cannot be changed (fixed?) without breaking other SHLWAPI calls. 2476 * To work around this when using this function, always check that the byte 2477 * at [common_prefix_len-1] is not a NUL. If it is, deduct 1 from the prefix. 2478 */ 2479 int WINAPI PathCommonPrefixA(LPCSTR lpszFile1, LPCSTR lpszFile2, LPSTR achPath) 2480 { 2481 int iLen = 0; 2482 LPCSTR lpszIter1 = lpszFile1; 2483 LPCSTR lpszIter2 = lpszFile2; 2484 2485 TRACE("(%s,%s,%p)\n", debugstr_a(lpszFile1), debugstr_a(lpszFile2), achPath); 2486 2487 if (achPath) 2488 *achPath = '\0'; 2489 2490 if (!lpszFile1 || !lpszFile2) 2491 return 0; 2492 2493 /* Handle roots first */ 2494 if (PathIsUNCA(lpszFile1)) 2495 { 2496 if (!PathIsUNCA(lpszFile2)) 2497 return 0; 2498 lpszIter1 += 2; 2499 lpszIter2 += 2; 2500 } 2501 else if (PathIsUNCA(lpszFile2)) 2502 return 0; /* Know already lpszFile1 is not UNC */ 2503 2504 do 2505 { 2506 /* Update len */ 2507 if ((!*lpszIter1 || *lpszIter1 == '\\') && 2508 (!*lpszIter2 || *lpszIter2 == '\\')) 2509 iLen = lpszIter1 - lpszFile1; /* Common to this point */ 2510 2511 if (!*lpszIter1 || (tolower(*lpszIter1) != tolower(*lpszIter2))) 2512 break; /* Strings differ at this point */ 2513 2514 lpszIter1++; 2515 lpszIter2++; 2516 } while (1); 2517 2518 if (iLen == 2) 2519 iLen++; /* Feature/Bug compatable with Win32 */ 2520 2521 if (iLen && achPath) 2522 { 2523 memcpy(achPath,lpszFile1,iLen); 2524 achPath[iLen] = '\0'; 2525 } 2526 return iLen; 2527 } 2528 2529 /************************************************************************* 2530 * PathCommonPrefixW [SHLWAPI.@] 2531 * 2532 * See PathCommonPrefixA. 2533 */ 2534 int WINAPI PathCommonPrefixW(LPCWSTR lpszFile1, LPCWSTR lpszFile2, LPWSTR achPath) 2535 { 2536 int iLen = 0; 2537 LPCWSTR lpszIter1 = lpszFile1; 2538 LPCWSTR lpszIter2 = lpszFile2; 2539 2540 TRACE("(%s,%s,%p)\n", debugstr_w(lpszFile1), debugstr_w(lpszFile2), achPath); 2541 2542 if (achPath) 2543 *achPath = '\0'; 2544 2545 if (!lpszFile1 || !lpszFile2) 2546 return 0; 2547 2548 /* Handle roots first */ 2549 if (PathIsUNCW(lpszFile1)) 2550 { 2551 if (!PathIsUNCW(lpszFile2)) 2552 return 0; 2553 lpszIter1 += 2; 2554 lpszIter2 += 2; 2555 } 2556 else if (PathIsUNCW(lpszFile2)) 2557 return 0; /* Know already lpszFile1 is not UNC */ 2558 2559 do 2560 { 2561 /* Update len */ 2562 if ((!*lpszIter1 || *lpszIter1 == '\\') && 2563 (!*lpszIter2 || *lpszIter2 == '\\')) 2564 iLen = lpszIter1 - lpszFile1; /* Common to this point */ 2565 2566 if (!*lpszIter1 || (tolowerW(*lpszIter1) != tolowerW(*lpszIter2))) 2567 break; /* Strings differ at this point */ 2568 2569 lpszIter1++; 2570 lpszIter2++; 2571 } while (1); 2572 2573 if (iLen == 2) 2574 iLen++; /* Feature/Bug compatable with Win32 */ 2575 2576 if (iLen && achPath) 2577 { 2578 memcpy(achPath,lpszFile1,iLen * sizeof(WCHAR)); 2579 achPath[iLen] = '\0'; 2580 } 2581 return iLen; 2582 } 2583 2584 /************************************************************************* 2585 * PathCompactPathA [SHLWAPI.@] 2586 * 2587 * Make a path fit into a given width when printed to a DC. 2588 * 2589 * PARAMS 2590 * hDc [I] Destination DC 2591 * lpszPath [O] Path to be printed to hDc 2592 * dx [i] Desired width 2593 * 2594 * RETURNS 2595 * TRUE If the path was modified. 2596 * FALSE Otherwise. 2597 */ 2598 BOOL WINAPI PathCompactPathA(HDC hDC, LPSTR lpszPath, UINT dx) 2599 { 2600 BOOL bRet = FALSE; 2601 2602 TRACE("(%08x,%s,%d)\n", hDC, debugstr_a(lpszPath), dx); 2603 2604 if (lpszPath) 2605 { 2606 WCHAR szPath[MAX_PATH]; 2607 MultiByteToWideChar(0,0,lpszPath,-1,szPath,MAX_PATH); 2608 bRet = PathCompactPathW(hDC, szPath, dx); 2609 WideCharToMultiByte(0,0,szPath,-1,lpszPath,MAX_PATH,0,0); 2610 } 2611 return bRet; 2612 } 2613 2614 /************************************************************************* 2615 * PathCompactPathW [SHLWAPI.@] 2616 * 2617 * See PathCompactPathA. 2618 */ 2619 BOOL WINAPI PathCompactPathW(HDC hDC, LPWSTR lpszPath, UINT dx) 2620 { 2621 static const WCHAR szEllipses[] = { '.', '.', '.', '\0' }; 2622 BOOL bRet = TRUE; 2623 HDC hdc = 0; 2624 WCHAR buff[MAX_PATH]; 2625 SIZE size; 2626 DWORD dwLen; 2627 2628 TRACE("(%08x,%s,%d)\n", hDC, debugstr_w(lpszPath), dx); 2629 2630 if (!lpszPath) 2631 return bRet; 2632 2633 if (!hDC) 2634 hdc = hDC = GetDC(0); 2635 2636 /* Get the length of the whole path */ 2637 dwLen = strlenW(lpszPath); 2638 GetTextExtentPointW(hDC, lpszPath, dwLen, &size); 2639 2640 if (size.cx > dx) 2641 { 2642 /* Path too big, must reduce it */ 2643 LPWSTR sFile; 2644 DWORD dwEllipsesLen = 0, dwPathLen = 0; 2645 2646 sFile = PathFindFileNameW(lpszPath); 2647 if (sFile != lpszPath) 2648 sFile = CharPrevW(lpszPath, sFile); 2649 2650 /* Get the size of ellipses */ 2651 GetTextExtentPointW(hDC, szEllipses, 3, &size); 2652 dwEllipsesLen = size.cx; 2653 /* Get the size of the file name */ 2654 GetTextExtentPointW(hDC, sFile, strlenW(sFile), &size); 2655 dwPathLen = size.cx; 2656 2657 if (sFile != lpszPath) 2658 { 2659 LPWSTR sPath = sFile; 2660 BOOL bEllipses = FALSE; 2661 2662 /* The path includes a file name. Include as much of the path prior to 2663 * the file name as possible, allowing for the ellipses, e.g: 2664 * c:\some very long path\filename ==> c:\some v...\filename 2665 */ 2666 strncpyW(buff, sFile, MAX_PATH); 2667 2668 do 2669 { 2670 DWORD dwTotalLen = bEllipses? dwPathLen + dwEllipsesLen : dwPathLen; 2671 2672 GetTextExtentPointW(hDC, lpszPath, sPath - lpszPath, &size); 2673 dwTotalLen += size.cx; 2674 if (dwTotalLen <= dx) 2675 break; 2676 sPath = CharPrevW(lpszPath, sPath); 2677 if (!bEllipses) 2678 { 2679 bEllipses = TRUE; 2680 sPath = CharPrevW(lpszPath, sPath); 2681 sPath = CharPrevW(lpszPath, sPath); 2682 } 2683 } while (sPath > lpszPath); 2684 2685 if (sPath > lpszPath) 2686 { 2687 if (bEllipses) 2688 { 2689 strcpyW(sPath, szEllipses); 2690 strcpyW(sPath+3, buff); 2691 } 2692 if (hdc) 2693 ReleaseDC(0, hdc); 2694 return TRUE; 2695 } 2696 strcpyW(lpszPath, szEllipses); 2697 strcpyW(lpszPath+3, buff); 2698 return FALSE; 2699 } 2700 2701 /* Trim the path by adding ellipses to the end, e.g: 2702 * A very long file name.txt ==> A very... 2703 */ 2704 dwLen = strlenW(lpszPath); 2705 2706 if (dwLen > MAX_PATH - 3) 2707 dwLen = MAX_PATH - 3; 2708 strncpyW(buff, sFile, dwLen); 2709 2710 do { 2711 dwLen--; 2712 GetTextExtentPointW(hDC, buff, dwLen, &size); 2713 } while (dwLen && size.cx + dwEllipsesLen > dx); 2714 2715 if (!dwLen) 2716 { 2717 DWORD dwWritten = 0; 2718 2719 dwEllipsesLen /= 3; /* Size of a single '.' */ 2720 2721 /* Write as much of the Ellipses string as possible */ 2722 while (dwWritten + dwEllipsesLen < dx && dwLen < 3) 2723 { 2724 *lpszPath++ = '.'; 2725 dwWritten += dwEllipsesLen; 2726 dwLen++; 2727 } 2728 *lpszPath = '\0'; 2729 bRet = FALSE; 2730 } 2731 else 2732 { 2733 strcpyW(buff + dwLen, szEllipses); 2734 strcpyW(lpszPath, buff); 2735 } 2736 } 2737 2738 if (hdc) 2739 ReleaseDC(0, hdc); 2740 2741 return bRet; 2742 } 2743 2744 /************************************************************************* 2745 * PathGetCharTypeA [SHLWAPI.@] 2746 * 2747 * Categorise a character from a file path. 2748 * 2749 * PARAMS 2750 * ch [I] Character to get the type of 2751 * 2752 * RETURNS 2753 * A set of GCT_ bit flags (from shlwapi.h) indicating the character type. 1662 2754 */ 1663 2755 UINT WINAPI PathGetCharTypeA(UCHAR ch) 1664 2756 { 1665 UINT flags = 0; 1666 1667 TRACE("%c\n", ch); 1668 1669 /* We could use them in filenames, but this would confuse 'ls' */ 1670 if (iscntrl(ch)) 1671 return GCT_INVALID; 1672 if ((ch == '*') || (ch=='?')) 1673 return GCT_WILD; 1674 if ((ch == '\\') || (ch=='/')) 1675 return GCT_SEPARATOR; 1676 flags = 0; 1677 /* all normal characters, no lower case letters */ 1678 if ((ch > ' ') && (ch < 0x7f) && !islower(ch)) 1679 flags |= GCT_SHORTCHAR; 1680 /* All other characters are valid in long filenames, even umlauts */ 1681 return flags | GCT_LFNCHAR; 1682 } 1683 1684 /************************************************************************* 1685 * PathGetCharTypeW [SHLWAPI.@] 2757 return PathGetCharTypeW(ch); 2758 } 2759 2760 /************************************************************************* 2761 * PathGetCharTypeW [SHLWAPI.@] 2762 * 2763 * See PathGetCharTypeA. 1686 2764 */ 1687 2765 UINT WINAPI PathGetCharTypeW(WCHAR ch) 1688 2766 { 1689 FIXME("%c, using ascii version\n", ch); 1690 return PathGetCharTypeA(ch); 1691 } 1692 1693 /************************************************************************* 1694 * PathMakeSystemFolderA [SHLWAPI.@] 1695 */ 1696 BOOL WINAPI PathMakeSystemFolderA(LPCSTR pszPath) 1697 { 1698 FIXME("%s\n", pszPath); 1699 return FALSE; 1700 } 1701 1702 /************************************************************************* 1703 * PathMakeSystemFolderW [SHLWAPI.@] 1704 */ 1705 BOOL WINAPI PathMakeSystemFolderW(LPCWSTR pszPath) 1706 { 1707 FIXME("%s\n", debugstr_w(pszPath)); 1708 return FALSE; 1709 } 1710 1711 /************************************************************************* 1712 * PathRenameExtensionA [SHLWAPI.@] 1713 */ 1714 BOOL WINAPI PathRenameExtensionA(LPSTR pszPath, LPCSTR pszExt) 1715 { 1716 LPSTR pszExtension = PathFindExtensionA(pszPath); 1717 1718 if (!pszExtension) return FALSE; 1719 if (pszExtension-pszPath + strlen(pszExt) > MAX_PATH) return FALSE; 1720 1721 strcpy(pszExtension, pszExt); 1722 TRACE("%s\n", pszPath); 1723 return TRUE; 1724 } 1725 1726 /************************************************************************* 1727 * PathRenameExtensionW [SHLWAPI.@] 1728 */ 1729 BOOL WINAPI PathRenameExtensionW(LPWSTR pszPath, LPCWSTR pszExt) 1730 { 1731 LPWSTR pszExtension = PathFindExtensionW(pszPath); 1732 1733 if (!pszExtension) return FALSE; 1734 if (pszExtension-pszPath + strlenW(pszExt) > MAX_PATH) return FALSE; 1735 1736 strcpyW(pszExtension, pszExt); 1737 TRACE("%s\n", debugstr_w(pszPath)); 1738 return TRUE; 1739 } 1740 1741 /************************************************************************* 1742 * PathSearchAndQualifyA [SHLWAPI.@] 1743 */ 1744 BOOL WINAPI PathSearchAndQualifyA( 1745 LPCSTR pszPath, 1746 LPSTR pszBuf, 1747 UINT cchBuf) 1748 { 1749 FIXME("%s %s 0x%08x\n", pszPath, pszBuf, cchBuf); 1750 return FALSE; 1751 } 1752 1753 /************************************************************************* 1754 * PathSearchAndQualifyW [SHLWAPI.@] 1755 */ 1756 BOOL WINAPI PathSearchAndQualifyW( 1757 LPCWSTR pszPath, 1758 LPWSTR pszBuf, 1759 UINT cchBuf) 1760 { 1761 FIXME("%s %s 0x%08x\n", debugstr_w(pszPath), debugstr_w(pszBuf), cchBuf); 1762 return FALSE; 1763 } 1764 1765 #ifndef __WIN32OS2__ 1766 /************************************************************************* 1767 * PathSkipRootA [SHLWAPI.@] 1768 */ 1769 LPSTR WINAPI PathSkipRootA(LPCSTR pszPath) 1770 { 1771 FIXME("%s\n", pszPath); 1772 return (LPSTR)pszPath; 1773 } 1774 1775 /************************************************************************* 1776 * PathSkipRootW [SHLWAPI.@] 1777 */ 1778 LPWSTR WINAPI PathSkipRootW(LPCWSTR pszPath) 1779 { 1780 FIXME("%s\n", debugstr_w(pszPath)); 1781 return (LPWSTR)pszPath; 1782 } 1783 #endif 1784 1785 /************************************************************************* 1786 * PathCreateFromUrlA [SHLWAPI.@] 1787 */ 1788 HRESULT WINAPI PathCreateFromUrlA( 1789 LPCSTR pszUrl, 1790 LPSTR pszPath, 1791 LPDWORD pcchPath, 1792 DWORD dwFlags) 1793 { 2767 UINT flags = 0; 2768 2769 TRACE("(%d)\n", ch); 2770 2771 if (!ch || ch < ' ' || ch == '<' || ch == '>' || 2772 ch == '"' || ch == '|' || ch == 255) 2773 flags = GCT_INVALID; /* Invalid */ 2774 else if (ch == '*' || ch=='?') 2775 flags = GCT_WILD; /* Wildchars */ 2776 else if ((ch == '\\') || (ch=='/') || (ch == ':')) 2777 return GCT_SEPARATOR; /* Path separators */ 2778 else 2779 { 2780 if (ch < 126) 2781 { 2782 if (!ch || isalnum(ch) || ch == '$' || ch == '&' || ch == '(' || 2783 ch == '.' || ch == '@' || ch == '^' || 2784 ch == '\'' || ch == 130 || ch == '`') 2785 flags |= GCT_SHORTCHAR; /* All these are valid for DOS */ 2786 } 2787 else 2788 if (!(ch & 0x1)) 2789 flags |= GCT_SHORTCHAR; /* Bug compatable with win32 */ 2790 flags |= GCT_LFNCHAR; /* Valid for long file names */ 2791 } 2792 return flags; 2793 } 2794 2795 /************************************************************************* 2796 * SHLWAPI_UseSystemForSystemFolders 2797 * 2798 * Internal helper for PathMakeSystemFolderW. 2799 */ 2800 static BOOL SHLWAPI_UseSystemForSystemFolders() 2801 { 2802 static BOOL bCheckedReg = FALSE; 2803 static BOOL bUseSystemForSystemFolders = FALSE; 2804 2805 if (!bCheckedReg) 2806 { 2807 bCheckedReg = TRUE; 2808 2809 /* Key tells Win what file attributes to use on system folders */ 2810 if (SHGetValueA(HKEY_LOCAL_MACHINE, 2811 "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer", 2812 "UseSystemForSystemFolders", 0, 0, 0)) 2813 bUseSystemForSystemFolders = TRUE; 2814 } 2815 return bUseSystemForSystemFolders; 2816 } 2817 2818 /************************************************************************* 2819 * PathMakeSystemFolderA [SHLWAPI.@] 2820 * 2821 * Set system folder attribute for a path. 2822 * 2823 * PARAMS 2824 * lpszPath [I] The path to turn into a system folder 2825 * 2826 * RETURNS 2827 * TRUE If the path was changed to/already was a system folder 2828 * FALSE If the path is invalid or SetFileAttributesA fails 2829 */ 2830 BOOL WINAPI PathMakeSystemFolderA(LPCSTR lpszPath) 2831 { 2832 BOOL bRet = FALSE; 2833 2834 TRACE("(%s)\n", debugstr_a(lpszPath)); 2835 2836 if (lpszPath && *lpszPath) 2837 { 2838 WCHAR szPath[MAX_PATH]; 2839 MultiByteToWideChar(0,0,lpszPath,-1,szPath,MAX_PATH); 2840 bRet = PathMakeSystemFolderW(szPath); 2841 } 2842 return bRet; 2843 } 2844 2845 /************************************************************************* 2846 * PathMakeSystemFolderW [SHLWAPI.@] 2847 * 2848 * See PathMakeSystemFolderA. 2849 */ 2850 BOOL WINAPI PathMakeSystemFolderW(LPCWSTR lpszPath) 2851 { 2852 DWORD dwDefaultAttr = FILE_ATTRIBUTE_READONLY, dwAttr; 2853 WCHAR buff[MAX_PATH]; 2854 2855 TRACE("(%s)\n", debugstr_w(lpszPath)); 2856 2857 if (!lpszPath || !*lpszPath) 2858 return FALSE; 2859 2860 /* If the directory is already a system directory, dont do anything */ 2861 GetSystemDirectoryW(buff, MAX_PATH); 2862 if (!strcmpW(buff, lpszPath)) 2863 return TRUE; 2864 2865 GetWindowsDirectoryW(buff, MAX_PATH); 2866 if (!strcmpW(buff, lpszPath)) 2867 return TRUE; 2868 2869 /* "UseSystemForSystemFolders" Tells Win what attributes to use */ 2870 if (SHLWAPI_UseSystemForSystemFolders()) 2871 dwDefaultAttr = FILE_ATTRIBUTE_SYSTEM; 2872 2873 if ((dwAttr = GetFileAttributesW(lpszPath)) == -1) 2874 return FALSE; 2875 2876 /* Change file attributes to system attributes */ 2877 dwAttr &= ~(FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_READONLY); 2878 return SetFileAttributesW(lpszPath, dwAttr | dwDefaultAttr); 2879 } 2880 2881 /************************************************************************* 2882 * PathRenameExtensionA [SHLWAPI.@] 2883 * 2884 * Swap the file extension in a path with another extension. 2885 * 2886 * PARAMS 2887 * pszPath [O] Path to swap the extension in 2888 * pszExt [I] The new extension 2889 * 2890 * RETURNS 2891 * TRUE if pszPath was modified 2892 * FALSE if pszPath or pszExt is NULL, or the new path is too long 2893 */ 2894 BOOL WINAPI PathRenameExtensionA(LPSTR lpszPath, LPCSTR lpszExt) 2895 { 2896 LPSTR lpszExtension; 2897 2898 TRACE("(%s,%s)\n", debugstr_a(lpszPath), debugstr_a(lpszExt)); 2899 2900 lpszExtension = PathFindExtensionA(lpszPath); 2901 2902 if (!lpszExtension || (lpszExtension - lpszPath + strlen(lpszExt) >= MAX_PATH)) 2903 return FALSE; 2904 2905 strcpy(lpszExtension, lpszExt); 2906 return TRUE; 2907 } 2908 2909 /************************************************************************* 2910 * PathRenameExtensionW [SHLWAPI.@] 2911 * 2912 * See PathRenameExtensionA. 2913 */ 2914 BOOL WINAPI PathRenameExtensionW(LPWSTR lpszPath, LPCWSTR lpszExt) 2915 { 2916 LPWSTR lpszExtension; 2917 2918 TRACE("(%s,%s)\n", debugstr_w(lpszPath), debugstr_w(lpszExt)); 2919 2920 lpszExtension = PathFindExtensionW(lpszPath); 2921 2922 if (!lpszExtension || (lpszExtension - lpszPath + strlenW(lpszExt) >= MAX_PATH)) 2923 return FALSE; 2924 2925 strcpyW(lpszExtension, lpszExt); 2926 return TRUE; 2927 } 2928 2929 /************************************************************************* 2930 * PathSearchAndQualifyA [SHLWAPI.@] 2931 * 2932 * Unimplemented. 2933 * 2934 * PARAMS 2935 * lpszPath [I] 2936 * lpszBuf [O] 2937 * cchBuf [I] Size of lpszBuf 2938 * 2939 * RETURNS 2940 * Unknown. 2941 */ 2942 BOOL WINAPI PathSearchAndQualifyA(LPCSTR lpszPath, LPSTR lpszBuf, UINT cchBuf) 2943 { 2944 FIXME("(%s,%p,0x%08x)-stub\n", debugstr_a(lpszPath), lpszBuf, cchBuf); 2945 return FALSE; 2946 } 2947 2948 /************************************************************************* 2949 * PathSearchAndQualifyW [SHLWAPI.@] 2950 * 2951 * See PathSearchAndQualifyA 2952 */ 2953 BOOL WINAPI PathSearchAndQualifyW(LPCWSTR lpszPath, LPWSTR lpszBuf, UINT cchBuf) 2954 { 2955 FIXME("(%s,%p,0x%08x)-stub\n", debugstr_w(lpszPath), lpszBuf, cchBuf); 2956 return FALSE; 2957 } 2958 2959 /************************************************************************* 2960 * PathSkipRootA [SHLWAPI.@] 2961 * 2962 * Return the portion of a path following the drive letter or mount point. 2963 * 2964 * PARAMS 2965 * lpszPath [I] The path to skip on 2966 * 2967 * RETURNS 2968 * Success: A pointer to the next character after the root. 2969 * Failure: NULL, if lpszPath is invalid, has no root or is a MB string. 2970 */ 2971 LPSTR WINAPI PathSkipRootA(LPCSTR lpszPath) 2972 { 2973 TRACE("(%s)\n", debugstr_a(lpszPath)); 2974 2975 if (!lpszPath || !*lpszPath) 2976 return NULL; 2977 2978 if (*lpszPath == '\\' && lpszPath[1] == '\\') 2979 { 2980 /* Network share: skip share server and mount point */ 2981 lpszPath += 2; 2982 if ((lpszPath = StrChrA(lpszPath, '\\')) && 2983 (lpszPath = StrChrA(lpszPath + 1, '\\'))) 2984 lpszPath++; 2985 return (LPSTR)lpszPath; 2986 } 2987 2988 if (IsDBCSLeadByte(*lpszPath)) 2989 return NULL; 2990 2991 /* Check x:\ */ 2992 if (lpszPath[0] && lpszPath[1] == ':' && lpszPath[2] == '\\') 2993 return (LPSTR)lpszPath + 3; 2994 return NULL; 2995 } 2996 2997 /************************************************************************* 2998 * PathSkipRootW [SHLWAPI.@] 2999 * 3000 * See PathSkipRootA. 3001 */ 3002 LPWSTR WINAPI PathSkipRootW(LPCWSTR lpszPath) 3003 { 3004 TRACE("(%s)\n", debugstr_w(lpszPath)); 3005 3006 if (!lpszPath || !*lpszPath) 3007 return NULL; 3008 3009 if (*lpszPath == '\\' && lpszPath[1] == '\\') 3010 { 3011 /* Network share: skip share server and mount point */ 3012 lpszPath += 2; 3013 if ((lpszPath = StrChrW(lpszPath, '\\')) && 3014 (lpszPath = StrChrW(lpszPath + 1, '\\'))) 3015 lpszPath++; 3016 return (LPWSTR)lpszPath; 3017 } 3018 3019 /* Check x:\ */ 3020 if (lpszPath[0] && lpszPath[1] == ':' && lpszPath[2] == '\\') 3021 return (LPWSTR)lpszPath + 3; 3022 return NULL; 3023 } 3024 3025 /************************************************************************* 3026 * PathCreateFromUrlA [SHLWAPI.@] 3027 * 3028 * Create a path from a URL 3029 * 3030 * PARAMS 3031 * lpszUrl [I] URL to convert into a path 3032 * lpszPath [O] Output buffer for the resulting Path 3033 * pcchPath [I] Length of lpszPath 3034 * dwFlags [I] Flags controlling the conversion 3035 * 3036 * RETURNS 3037 * Success: S_OK. lpszPath contains the URL in path format 3038 * Failure: An HRESULT error code such as E_INVALIDARG. 3039 */ 3040 HRESULT WINAPI PathCreateFromUrlA(LPCSTR lpszUrl, LPSTR lpszPath, 3041 LPDWORD pcchPath, DWORD dwFlags) 3042 { 3043 FIXME("(%s,%p,%p,0x%08lx)-stub\n", debugstr_a(lpszUrl), lpszPath, pcchPath, dwFlags); 3044 3045 if (!lpszUrl || !lpszPath || !pcchPath || !*pcchPath) 3046 return E_INVALIDARG; 3047 1794 3048 /* extracts thing prior to : in pszURL and checks against: 1795 3049 * https … … 1798 3052 * about - if match returns E_INVALIDARG 1799 3053 */ 1800 FIXME("%s %p %p 0x%08lx\n", 1801 pszUrl, pszPath, pcchPath, dwFlags); 1802 return E_INVALIDARG; 1803 } 1804 1805 /************************************************************************* 1806 * PathCreateFromUrlW [SHLWAPI.@] 1807 */ 1808 HRESULT WINAPI PathCreateFromUrlW( 1809 LPCWSTR pszUrl, 1810 LPWSTR pszPath, 1811 LPDWORD pcchPath, 1812 DWORD dwFlags) 1813 { 1814 /* extracts thing prior to : in pszURL and checks against: 1815 * https 1816 * shell 1817 * local 1818 * about - if match returns E_INVALIDARG 1819 */ 1820 FIXME("%s %p %p 0x%08lx\n", 1821 debugstr_w(pszUrl), pszPath, pcchPath, dwFlags); 1822 return E_INVALIDARG; 1823 } 1824 1825 /************************************************************************* 1826 * PathRelativePathToA [SHLWAPI.@] 1827 */ 1828 BOOL WINAPI PathRelativePathToA( 1829 LPSTR pszPath, 1830 LPCSTR pszFrom, 1831 DWORD dwAttrFrom, 1832 LPCSTR pszTo, 1833 DWORD dwAttrTo) 1834 { 1835 FIXME("%s %s 0x%08lx %s 0x%08lx\n", 1836 pszPath, pszFrom, dwAttrFrom, pszTo, dwAttrTo); 1837 return FALSE; 1838 } 1839 1840 /************************************************************************* 1841 * PathRelativePathToW [SHLWAPI.@] 1842 */ 1843 BOOL WINAPI PathRelativePathToW( 1844 LPWSTR pszPath, 1845 LPCWSTR pszFrom, 1846 DWORD dwAttrFrom, 1847 LPCWSTR pszTo, 1848 DWORD dwAttrTo) 1849 { 1850 FIXME("%s %s 0x%08lx %s 0x%08lx\n", 1851 debugstr_w(pszPath), debugstr_w(pszFrom), dwAttrFrom, debugstr_w(pszTo), dwAttrTo); 1852 return FALSE; 1853 } 1854 1855 /************************************************************************* 1856 * PathUnmakeSystemFolderA [SHLWAPI.@] 1857 */ 1858 BOOL WINAPI PathUnmakeSystemFolderA(LPCSTR pszPath) 1859 { 1860 FIXME("%s\n", pszPath); 1861 return FALSE; 1862 } 1863 1864 /************************************************************************* 1865 * PathUnmakeSystemFolderW [SHLWAPI.@] 1866 */ 1867 BOOL WINAPI PathUnmakeSystemFolderW(LPCWSTR pszPath) 1868 { 1869 FIXME("%s\n", debugstr_w(pszPath)); 1870 return FALSE; 1871 } 1872 1873 /* 1874 ########## special ########## 1875 */ 3054 3055 return S_OK; 3056 } 3057 3058 /************************************************************************* 3059 * PathCreateFromUrlW [SHLWAPI.@] 3060 * 3061 * See PathCreateFromUrlA. 3062 */ 3063 HRESULT WINAPI PathCreateFromUrlW(LPCWSTR lpszUrl, LPWSTR lpszPath, 3064 LPDWORD pcchPath, DWORD dwFlags) 3065 { 3066 FIXME("(%s,%p,%p,0x%08lx)-stub\n", debugstr_w(lpszUrl), lpszPath, pcchPath, dwFlags); 3067 3068 if (!lpszUrl || !lpszPath || !pcchPath || !*pcchPath) 3069 return E_INVALIDARG; 3070 3071 return S_OK; 3072 } 3073 3074 /************************************************************************* 3075 * PathRelativePathToA [SHLWAPI.@] 3076 * 3077 * Create a relative path from one path to another. 3078 * 3079 * PARAMS 3080 * lpszPath [O] Destination for relative path 3081 * lpszFrom [I] Source path 3082 * dwAttrFrom [I] File attribute of source path 3083 * lpszTo [I] Destination path 3084 * dwAttrTo [I] File attributes of destination path 3085 * 3086 * RETURNS 3087 * TRUE If a relative path can be formed. lpszPath contains the new path 3088 * FALSE If the paths are not relavtive or any parameters are invalid 3089 * 3090 * NOTES 3091 * lpszTo should be at least MAX_PATH in length. 3092 * Calling this function with relative paths for lpszFrom or lpszTo may 3093 * give erroneous results. 3094 * 3095 * The Win32 version of this function contains a bug where the lpszTo string 3096 * may be referenced 1 byte beyond the end of the string. As a result random 3097 * garbage may be written to the output path, depending on what lies beyond 3098 * the last byte of the string. This bug occurs because of the behaviour of 3099 * PathCommonPrefix (see notes for that function), and no workaround seems 3100 * possible with Win32. 3101 * This bug has been fixed here, so for example the relative path from "\\" 3102 * to "\\" is correctly determined as "." in this implementation. 3103 */ 3104 BOOL WINAPI PathRelativePathToA(LPSTR lpszPath, LPCSTR lpszFrom, DWORD dwAttrFrom, 3105 LPCSTR lpszTo, DWORD dwAttrTo) 3106 { 3107 BOOL bRet = FALSE; 3108 3109 TRACE("(%p,%s,0x%08lx,%s,0x%08lx)\n", lpszPath, debugstr_a(lpszFrom), 3110 dwAttrFrom, debugstr_a(lpszTo), dwAttrTo); 3111 3112 if(lpszPath && lpszFrom && lpszTo) 3113 { 3114 WCHAR szPath[MAX_PATH]; 3115 WCHAR szFrom[MAX_PATH]; 3116 WCHAR szTo[MAX_PATH]; 3117 MultiByteToWideChar(0,0,lpszFrom,-1,szFrom,MAX_PATH); 3118 MultiByteToWideChar(0,0,lpszTo,-1,szTo,MAX_PATH); 3119 bRet = PathRelativePathToW(szPath,szFrom,dwAttrFrom,szTo,dwAttrTo); 3120 WideCharToMultiByte(0,0,szPath,-1,lpszPath,MAX_PATH,0,0); 3121 } 3122 return bRet; 3123 } 3124 3125 /************************************************************************* 3126 * PathRelativePathToW [SHLWAPI.@] 3127 * 3128 * See PathRelativePathToA. 3129 */ 3130 BOOL WINAPI PathRelativePathToW(LPWSTR lpszPath, LPCWSTR lpszFrom, DWORD dwAttrFrom, 3131 LPCWSTR lpszTo, DWORD dwAttrTo) 3132 { 3133 static const WCHAR szPrevDirSlash[] = { '.', '.', '\\', '\0' }; 3134 static const WCHAR szPrevDir[] = { '.', '.', '\0' }; 3135 WCHAR szFrom[MAX_PATH]; 3136 WCHAR szTo[MAX_PATH]; 3137 DWORD dwLen; 3138 3139 TRACE("(%p,%s,0x%08lx,%s,0x%08lx)\n", lpszPath, debugstr_w(lpszFrom), 3140 dwAttrFrom, debugstr_w(lpszTo), dwAttrTo); 3141 3142 if(!lpszPath || !lpszFrom || !lpszTo) 3143 return FALSE; 3144 3145 *lpszPath = '\0'; 3146 strncpyW(szFrom, lpszFrom, MAX_PATH); 3147 strncpyW(szTo, lpszTo, MAX_PATH); 3148 3149 if(!(dwAttrFrom & FILE_ATTRIBUTE_DIRECTORY)) 3150 PathRemoveFileSpecW(szFrom); 3151 if(!(dwAttrFrom & FILE_ATTRIBUTE_DIRECTORY)) 3152 PathRemoveFileSpecW(szTo); 3153 3154 /* Paths can only be relative if they have a common root */ 3155 if(!(dwLen = PathCommonPrefixW(szFrom, szTo, 0))) 3156 return FALSE; 3157 3158 /* Strip off lpszFrom components to the root, by adding "..\" */ 3159 lpszFrom = szFrom + dwLen; 3160 if (!*lpszFrom) 3161 { 3162 lpszPath[0] = '.'; 3163 lpszPath[1] = '\0'; 3164 } 3165 if (*lpszFrom == '\\') 3166 lpszFrom++; 3167 3168 while (*lpszFrom) 3169 { 3170 lpszFrom = PathFindNextComponentW(lpszFrom); 3171 strcatW(lpszPath, *lpszFrom ? szPrevDirSlash : szPrevDir); 3172 } 3173 3174 /* From the root add the components of lpszTo */ 3175 lpszTo += dwLen; 3176 /* We check lpszTo[-1] to avoid skipping end of string. See the notes for 3177 * this function. 3178 */ 3179 if (*lpszTo && lpszTo[-1]) 3180 { 3181 if (*lpszTo != '\\') 3182 lpszTo--; 3183 dwLen = strlenW(lpszPath); 3184 if (dwLen + strlenW(lpszTo) >= MAX_PATH) 3185 { 3186 *lpszPath = '\0'; 3187 return FALSE; 3188 } 3189 strcpyW(lpszPath + dwLen, lpszTo); 3190 } 3191 return TRUE; 3192 } 3193 3194 /************************************************************************* 3195 * PathUnmakeSystemFolderA [SHLWAPI.@] 3196 * 3197 * Remove the system folder attributes from a path. 3198 * 3199 * PARAMS 3200 * lpszPath [I] The path to remove attributes from 3201 * 3202 * RETURNS 3203 * Success: TRUE. 3204 * Failure: FALSE, if lpszPath is NULL, empty, not a directory, or calling 3205 * SetFileAttributesA fails. 3206 */ 3207 BOOL WINAPI PathUnmakeSystemFolderA(LPCSTR lpszPath) 3208 { 3209 DWORD dwAttr; 3210 3211 TRACE("(%s)\n", debugstr_a(lpszPath)); 3212 3213 if (!lpszPath || !*lpszPath || (dwAttr = GetFileAttributesA(lpszPath)) == -1 || 3214 !(dwAttr & FILE_ATTRIBUTE_DIRECTORY)) 3215 return FALSE; 3216 3217 dwAttr &= ~(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM); 3218 return SetFileAttributesA(lpszPath, dwAttr); 3219 } 3220 3221 /************************************************************************* 3222 * PathUnmakeSystemFolderW [SHLWAPI.@] 3223 * 3224 * See PathUnmakeSystemFolderA. 3225 */ 3226 BOOL WINAPI PathUnmakeSystemFolderW(LPCWSTR lpszPath) 3227 { 3228 DWORD dwAttr; 3229 3230 TRACE("(%s)\n", debugstr_w(lpszPath)); 3231 3232 if (!lpszPath || !*lpszPath || (dwAttr = GetFileAttributesW(lpszPath)) == -1 || 3233 !(dwAttr & FILE_ATTRIBUTE_DIRECTORY)) 3234 return FALSE; 3235 3236 dwAttr &= ~(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM); 3237 return SetFileAttributesW(lpszPath, dwAttr); 3238 } 3239 1876 3240 1877 3241 /************************************************************************* 1878 3242 * PathSetDlgItemPathA [SHLWAPI.@] 1879 3243 * 3244 * Set the text of a dialog item to a path, shrinking the path to fit 3245 * if it is too big for the item. 3246 * 3247 * PARAMS 3248 * hDlg [I] Dialog handle 3249 * id [I] ID of item in the dialog 3250 * lpszPath [I] Path to set as the items text 3251 * 3252 * RETURNS 3253 * Nothing. 3254 * 1880 3255 * NOTES 1881 * use PathCompactPath to make sure, the path fits into the control 1882 */ 1883 BOOL WINAPI PathSetDlgItemPathA(HWND hDlg, int id, LPCSTR pszPath) 1884 { TRACE("%x %x %s\n",hDlg, id, pszPath); 1885 return SetDlgItemTextA(hDlg, id, pszPath); 3256 * If lpszPath is NULL, a blank string ("") is set (i.e. The previous 3257 * window text is erased). 3258 */ 3259 VOID WINAPI PathSetDlgItemPathA(HWND hDlg, int id, LPCSTR lpszPath) 3260 { 3261 WCHAR szPath[MAX_PATH]; 3262 3263 TRACE("(%8x,%8x,%s)\n",hDlg, id, debugstr_a(lpszPath)); 3264 3265 if (lpszPath) 3266 MultiByteToWideChar(0,0,lpszPath,-1,szPath,MAX_PATH); 3267 else 3268 szPath[0] = '\0'; 3269 PathSetDlgItemPathW(hDlg, id, szPath); 1886 3270 } 1887 3271 1888 3272 /************************************************************************* 1889 3273 * PathSetDlgItemPathW [SHLWAPI.@] 1890 */ 1891 BOOL WINAPI PathSetDlgItemPathW(HWND hDlg, int id, LPCWSTR pszPath) 1892 { TRACE("%x %x %s\n",hDlg, id, debugstr_w(pszPath)); 1893 return SetDlgItemTextW(hDlg, id, pszPath); 1894 } 3274 * 3275 * See PathSetDlgItemPathA. 3276 */ 3277 VOID WINAPI PathSetDlgItemPathW(HWND hDlg, int id, LPCWSTR lpszPath) 3278 { 3279 WCHAR path[MAX_PATH + 1]; 3280 HWND hwItem; 3281 RECT rect; 3282 HDC hdc; 3283 HGDIOBJ hPrevObj; 3284 3285 TRACE("(%8x,%8x,%s)\n",hDlg, id, debugstr_w(lpszPath)); 3286 3287 if (!(hwItem = GetDlgItem(hDlg, id))) 3288 return; 3289 3290 if (lpszPath) 3291 strncpyW(path, lpszPath, sizeof(path)); 3292 else 3293 path[0] = '\0'; 3294 3295 GetClientRect(hwItem, &rect); 3296 hdc = GetDC(hDlg); 3297 hPrevObj = SelectObject(hdc, (HGDIOBJ)SendMessageW(hwItem,WM_GETFONT,0,0)); 3298 3299 if (hPrevObj) 3300 { 3301 PathCompactPathW(hdc, path, rect.right); 3302 SelectObject(hdc, hPrevObj); 3303 } 3304 3305 ReleaseDC(hDlg, hdc); 3306 SetWindowTextW(hwItem, path); 3307 } 3308 3309 /************************************************************************* 3310 * PathIsNetworkPathA [SHLWAPI.@] 3311 * 3312 * Determine if the given path is a network path. 3313 * 3314 * PARAMS 3315 * lpszPath [I] Path to check 3316 * 3317 * RETURNS 3318 * TRUE If path is a UNC share or mapped network drive 3319 * FALSE If path is a local drive or cannot be determined 3320 */ 3321 BOOL WINAPI PathIsNetworkPathA(LPCSTR lpszPath) 3322 { 3323 DWORD dwDriveNum; 3324 3325 TRACE("(%s)\n",debugstr_a(lpszPath)); 3326 3327 if (!lpszPath) 3328 return FALSE; 3329 if (*lpszPath == '\\' && lpszPath[1] == '\\') 3330 return TRUE; 3331 dwDriveNum = PathGetDriveNumberA(lpszPath); 3332 if (dwDriveNum == -1) 3333 return FALSE; 3334 GET_FUNC(pIsNetDrive, shell32, (LPCSTR)66, FALSE); /* ord 66 = shell32.IsNetDrive */ 3335 return pIsNetDrive(dwDriveNum); 3336 } 3337 3338 /************************************************************************* 3339 * PathIsNetworkPathW [SHLWAPI.@] 3340 * 3341 * See PathIsNetworkPathA. 3342 */ 3343 BOOL WINAPI PathIsNetworkPathW(LPCWSTR lpszPath) 3344 { 3345 DWORD dwDriveNum; 3346 3347 TRACE("(%s)\n", debugstr_w(lpszPath)); 3348 3349 if (!lpszPath) 3350 return FALSE; 3351 if (*lpszPath == '\\' && lpszPath[1] == '\\') 3352 return TRUE; 3353 dwDriveNum = PathGetDriveNumberW(lpszPath); 3354 if (dwDriveNum == -1) 3355 return FALSE; 3356 GET_FUNC(pIsNetDrive, shell32, (LPCSTR)66, FALSE); /* ord 66 = shell32.IsNetDrive */ 3357 return pIsNetDrive(dwDriveNum); 3358 } 3359 3360 /************************************************************************* 3361 * PathIsLFNFileSpecA [SHLWAPI.@] 3362 * 3363 * Determine if the given path is a long file name 3364 * 3365 * PARAMS 3366 * lpszPath [I] Path to check 3367 * 3368 * RETURNS 3369 * TRUE If path is a long file name 3370 * FALSE If path is a valid DOS 8.3 file name 3371 */ 3372 BOOL WINAPI PathIsLFNFileSpecA(LPCSTR lpszPath) 3373 { 3374 DWORD dwNameLen = 0, dwExtLen = 0; 3375 3376 TRACE("(%s)\n",debugstr_a(lpszPath)); 3377 3378 if (!lpszPath) 3379 return FALSE; 3380 3381 while (*lpszPath) 3382 { 3383 if (*lpszPath == ' ') 3384 return TRUE; /* DOS names cannot have spaces */ 3385 if (*lpszPath == '.') 3386 { 3387 if (dwExtLen) 3388 return TRUE; /* DOS names have only one dot */ 3389 dwExtLen = 1; 3390 } 3391 else if (dwExtLen) 3392 { 3393 dwExtLen++; 3394 if (dwExtLen > 4) 3395 return TRUE; /* DOS extensions are <= 3 chars*/ 3396 } 3397 else 3398 { 3399 dwNameLen++; 3400 if (dwNameLen > 8) 3401 return TRUE; /* DOS names are <= 8 chars */ 3402 } 3403 lpszPath += IsDBCSLeadByte(*lpszPath) ? 2 : 1; 3404 } 3405 return FALSE; /* Valid DOS path */ 3406 } 3407 3408 /************************************************************************* 3409 * PathIsLFNFileSpecW [SHLWAPI.@] 3410 * 3411 * See PathIsLFNFileSpecA. 3412 */ 3413 BOOL WINAPI PathIsLFNFileSpecW(LPCWSTR lpszPath) 3414 { 3415 DWORD dwNameLen = 0, dwExtLen = 0; 3416 3417 TRACE("(%s)\n",debugstr_w(lpszPath)); 3418 3419 if (!lpszPath) 3420 return FALSE; 3421 3422 while (*lpszPath) 3423 { 3424 if (*lpszPath == ' ') 3425 return TRUE; /* DOS names cannot have spaces */ 3426 if (*lpszPath == '.') 3427 { 3428 if (dwExtLen) 3429 return TRUE; /* DOS names have only one dot */ 3430 dwExtLen = 1; 3431 } 3432 else if (dwExtLen) 3433 { 3434 dwExtLen++; 3435 if (dwExtLen > 4) 3436 return TRUE; /* DOS extensions are <= 3 chars*/ 3437 } 3438 else 3439 { 3440 dwNameLen++; 3441 if (dwNameLen > 8) 3442 return TRUE; /* DOS names are <= 8 chars */ 3443 } 3444 lpszPath++; 3445 } 3446 return FALSE; /* Valid DOS path */ 3447 } 3448 3449 /************************************************************************* 3450 * PathIsDirectoryEmptyA [SHLWAPI.@] 3451 * 3452 * Determine if a given directory is empty. 3453 * 3454 * PARAMS 3455 * lpszPath [I] Directory to check 3456 * 3457 * RETURNS 3458 * TRUE If the directory exists and contains no files 3459 * FALSE Otherwise 3460 */ 3461 BOOL WINAPI PathIsDirectoryEmptyA(LPCSTR lpszPath) 3462 { 3463 BOOL bRet = FALSE; 3464 3465 TRACE("(%s)\n",debugstr_a(lpszPath)); 3466 3467 if (lpszPath) 3468 { 3469 WCHAR szPath[MAX_PATH]; 3470 MultiByteToWideChar(0,0,lpszPath,-1,szPath,MAX_PATH); 3471 bRet = PathIsDirectoryEmptyW(szPath); 3472 } 3473 return bRet; 3474 } 3475 3476 /************************************************************************* 3477 * PathIsDirectoryEmptyW [SHLWAPI.@] 3478 * 3479 * See PathIsDirectoryEmptyA. 3480 */ 3481 BOOL WINAPI PathIsDirectoryEmptyW(LPCWSTR lpszPath) 3482 { 3483 static const WCHAR szAllFiles[] = { '*', '.', '*', '\0' }; 3484 WCHAR szSearch[MAX_PATH]; 3485 DWORD dwLen; 3486 HANDLE hfind; 3487 BOOL retVal = FALSE; 3488 WIN32_FIND_DATAW find_data; 3489 3490 TRACE("(%s)\n",debugstr_w(lpszPath)); 3491 3492 if (!lpszPath || !PathIsDirectoryW(lpszPath)) 3493 return FALSE; 3494 3495 strncpyW(szSearch, lpszPath, MAX_PATH); 3496 PathAddBackslashW(szSearch); 3497 dwLen = strlenW(szSearch); 3498 if (dwLen > MAX_PATH - 4) 3499 return FALSE; 3500 3501 strcpyW(szSearch + dwLen, szAllFiles); 3502 hfind = FindFirstFileW(szSearch, &find_data); 3503 3504 if (hfind != INVALID_HANDLE_VALUE && 3505 find_data.cFileName[0] == '.' && 3506 find_data.cFileName[1] == '.') 3507 { 3508 /* The only directory entry should be the parent */ 3509 if (!FindNextFileW(hfind, &find_data)) 3510 retVal = TRUE; 3511 FindClose(hfind); 3512 } 3513 return retVal; 3514 } 3515 3516 3517 /************************************************************************* 3518 * PathFindSuffixArrayA [SHLWAPI.@] 3519 * 3520 * Find a suffix string in an array of suffix strings 3521 * 3522 * PARAMS 3523 * lpszSuffix [I] Suffix string to search for 3524 * lppszArray [I] Array of suffix strings to search 3525 * dwCount [I] Number of elements in lppszArray 3526 * 3527 * RETURNS 3528 * Success The index of the position of lpszSuffix in lppszArray 3529 * Failure 0, if any parameters are invalid or lpszSuffix is not found 3530 * 3531 * NOTES 3532 * The search is case sensitive. 3533 * The match is made against the end of the suffix string, so for example: 3534 * lpszSuffix=fooBAR matches BAR, but lpszSuffix=fooBARfoo does not. 3535 */ 3536 int WINAPI PathFindSuffixArrayA(LPCSTR lpszSuffix, LPCSTR *lppszArray, int dwCount) 3537 { 3538 DWORD dwLen; 3539 int dwRet = 0; 3540 3541 TRACE("(%s,%p,%d)\n",debugstr_a(lpszSuffix), lppszArray, dwCount); 3542 3543 if (lpszSuffix && lppszArray && dwCount > 0) 3544 { 3545 dwLen = strlen(lpszSuffix); 3546 3547 while (dwRet < dwCount) 3548 { 3549 DWORD dwCompareLen = strlen(*lppszArray); 3550 if (dwCompareLen < dwLen) 3551 { 3552 if (!strcmp(lpszSuffix + dwLen - dwCompareLen, *lppszArray)) 3553 return dwRet; /* Found */ 3554 } 3555 dwRet++; 3556 lppszArray++; 3557 } 3558 } 3559 return 0; 3560 } 3561 3562 /************************************************************************* 3563 * PathFindSuffixArrayW [SHLWAPI.@] 3564 * 3565 * See PathFindSuffixArrayA. 3566 */ 3567 int WINAPI PathFindSuffixArrayW(LPCWSTR lpszSuffix, LPCWSTR *lppszArray, int dwCount) 3568 { 3569 DWORD dwLen; 3570 int dwRet = 0; 3571 3572 TRACE("(%s,%p,%d)\n",debugstr_w(lpszSuffix), lppszArray, dwCount); 3573 3574 if (lpszSuffix && lppszArray && dwCount > 0) 3575 { 3576 dwLen = strlenW(lpszSuffix); 3577 3578 while (dwRet < dwCount) 3579 { 3580 DWORD dwCompareLen = strlenW(*lppszArray); 3581 if (dwCompareLen < dwLen) 3582 { 3583 if (!strcmpW(lpszSuffix + dwLen - dwCompareLen, *lppszArray)) 3584 return dwRet; /* Found */ 3585 } 3586 dwRet++; 3587 lppszArray++; 3588 } 3589 } 3590 return 0; 3591 } 3592 3593 /************************************************************************* 3594 * PathUndecorateA [SHLWAPI.@] 3595 * 3596 * Undecorate a file path 3597 * 3598 * PARAMS 3599 * lpszPath [O] Path to undecorate 3600 * 3601 * RETURNS 3602 * Nothing 3603 * 3604 * NOTES 3605 * A decorations form is "path[n].ext" where n is an optional decimal number. 3606 */ 3607 VOID WINAPI PathUndecorateA(LPSTR lpszPath) 3608 { 3609 TRACE("(%s)\n",debugstr_a(lpszPath)); 3610 3611 if (lpszPath) 3612 { 3613 LPSTR lpszExt = PathFindExtensionA(lpszPath); 3614 if (lpszExt > lpszPath && lpszExt[-1] == ']') 3615 { 3616 LPSTR lpszSkip = lpszExt - 2; 3617 if (*lpszSkip == '[') 3618 lpszSkip++; /* [] (no number) */ 3619 else 3620 while (lpszSkip > lpszPath && isdigit(lpszSkip[-1])) 3621 lpszSkip--; 3622 if (lpszSkip > lpszPath && lpszSkip[-1] == '[' && lpszSkip[-2] != '\\') 3623 { 3624 /* remove the [n] */ 3625 lpszSkip--; 3626 while (*lpszExt) 3627 *lpszSkip++ = *lpszExt++; 3628 *lpszSkip = '\0'; 3629 } 3630 } 3631 } 3632 } 3633 3634 /************************************************************************* 3635 * PathUndecorateW [SHLWAPI.@] 3636 * 3637 * See PathUndecorateA. 3638 */ 3639 VOID WINAPI PathUndecorateW(LPWSTR lpszPath) 3640 { 3641 TRACE("(%s)\n",debugstr_w(lpszPath)); 3642 3643 if (lpszPath) 3644 { 3645 LPWSTR lpszExt = PathFindExtensionW(lpszPath); 3646 if (lpszExt > lpszPath && lpszExt[-1] == ']') 3647 { 3648 LPWSTR lpszSkip = lpszExt - 2; 3649 if (*lpszSkip == '[') 3650 lpszSkip++; /* [] (no number) */ 3651 else 3652 while (lpszSkip > lpszPath && isdigitW(lpszSkip[-1])) 3653 lpszSkip--; 3654 if (lpszSkip > lpszPath && lpszSkip[-1] == '[' && lpszSkip[-2] != '\\') 3655 { 3656 /* remove the [n] */ 3657 lpszSkip--; 3658 while (*lpszExt) 3659 *lpszSkip++ = *lpszExt++; 3660 *lpszSkip = '\0'; 3661 } 3662 } 3663 } 3664 }
Note:
See TracChangeset
for help on using the changeset viewer.