1 // Windows/FileName.cpp 2 3 #include "StdAfx.h" 4 5 #include "FileName.h" 6 7 #ifndef _UNICODE 8 extern bool g_IsNT; 9 #endif 10 11 namespace NWindows { 12 namespace NFile { 13 namespace NName { 14 15 #define IS_SEPAR(c) IS_PATH_SEPAR(c) 16 17 int FindSepar(const wchar_t *s) throw() 18 { 19 for (const wchar_t *p = s;; p++) 20 { 21 const wchar_t c = *p; 22 if (c == 0) 23 return -1; 24 if (IS_SEPAR(c)) 25 return (int)(p - s); 26 } 27 } 28 29 #ifndef USE_UNICODE_FSTRING 30 int FindSepar(const FChar *s) throw() 31 { 32 for (const FChar *p = s;; p++) 33 { 34 const FChar c = *p; 35 if (c == 0) 36 return -1; 37 if (IS_SEPAR(c)) 38 return (int)(p - s); 39 } 40 } 41 #endif 42 43 #ifndef USE_UNICODE_FSTRING 44 void NormalizeDirPathPrefix(FString &dirPath) 45 { 46 if (dirPath.IsEmpty()) 47 return; 48 if (!IsPathSepar(dirPath.Back())) 49 dirPath.Add_PathSepar(); 50 } 51 #endif 52 53 void NormalizeDirPathPrefix(UString &dirPath) 54 { 55 if (dirPath.IsEmpty()) 56 return; 57 if (!IsPathSepar(dirPath.Back())) 58 dirPath.Add_PathSepar(); 59 } 60 61 #define IS_LETTER_CHAR(c) ((c) >= 'a' && (c) <= 'z' || (c) >= 'A' && (c) <= 'Z') 62 63 bool IsDrivePath(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); } 64 65 bool IsAltPathPrefix(CFSTR s) throw() 66 { 67 unsigned len = MyStringLen(s); 68 if (len == 0) 69 return false; 70 if (s[len - 1] != ':') 71 return false; 72 73 #if defined(_WIN32) && !defined(UNDER_CE) 74 if (IsDevicePath(s)) 75 return false; 76 if (IsSuperPath(s)) 77 { 78 s += kSuperPathPrefixSize; 79 len -= kSuperPathPrefixSize; 80 } 81 if (len == 2 && IsDrivePath2(s)) 82 return false; 83 #endif 84 85 return true; 86 } 87 88 #if defined(_WIN32) && !defined(UNDER_CE) 89 90 const wchar_t *kSuperPathPrefix = L"\\\\?\\"; 91 static const wchar_t *kSuperUncPrefix = L"\\\\?\\UNC\\"; 92 93 #define IS_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '.' && IS_SEPAR((s)[3])) 94 #define IS_SUPER_PREFIX(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '?' && IS_SEPAR((s)[3])) 95 #define IS_SUPER_OR_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && ((s)[2] == '?' || (s)[2] == '.') && IS_SEPAR((s)[3])) 96 97 #define IS_UNC_WITH_SLASH(s) ( \ 98 ((s)[0] == 'U' || (s)[0] == 'u') \ 99 && ((s)[1] == 'N' || (s)[1] == 'n') \ 100 && ((s)[2] == 'C' || (s)[2] == 'c') \ 101 && IS_SEPAR((s)[3])) 102 103 bool IsDevicePath(CFSTR s) throw() 104 { 105 #ifdef UNDER_CE 106 107 s = s; 108 return false; 109 /* 110 // actually we don't know the way to open device file in WinCE. 111 unsigned len = MyStringLen(s); 112 if (len < 5 || len > 5 || memcmp(s, FTEXT("DSK"), 3 * sizeof(FChar)) != 0) 113 return false; 114 if (s[4] != ':') 115 return false; 116 // for reading use SG_REQ sg; if (DeviceIoControl(dsk, IOCTL_DISK_READ)); 117 */ 118 119 #else 120 121 if (!IS_DEVICE_PATH(s)) 122 return false; 123 unsigned len = MyStringLen(s); 124 if (len == 6 && s[5] == ':') 125 return true; 126 if (len < 18 || len > 22 || memcmp(s + kDevicePathPrefixSize, FTEXT("PhysicalDrive"), 13 * sizeof(FChar)) != 0) 127 return false; 128 for (unsigned i = 17; i < len; i++) 129 if (s[i] < '0' || s[i] > '9') 130 return false; 131 return true; 132 133 #endif 134 } 135 136 bool IsSuperUncPath(CFSTR s) throw() { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); } 137 bool IsNetworkPath(CFSTR s) throw() 138 { 139 if (!IS_SEPAR(s[0]) || !IS_SEPAR(s[1])) 140 return false; 141 if (IsSuperUncPath(s)) 142 return true; 143 FChar c = s[2]; 144 return (c != '.' && c != '?'); 145 } 146 147 unsigned GetNetworkServerPrefixSize(CFSTR s) throw() 148 { 149 if (!IS_SEPAR(s[0]) || !IS_SEPAR(s[1])) 150 return 0; 151 unsigned prefixSize = 2; 152 if (IsSuperUncPath(s)) 153 prefixSize = kSuperUncPathPrefixSize; 154 else 155 { 156 FChar c = s[2]; 157 if (c == '.' || c == '?') 158 return 0; 159 } 160 int pos = FindSepar(s + prefixSize); 161 if (pos < 0) 162 return 0; 163 return prefixSize + pos + 1; 164 } 165 166 bool IsNetworkShareRootPath(CFSTR s) throw() 167 { 168 unsigned prefixSize = GetNetworkServerPrefixSize(s); 169 if (prefixSize == 0) 170 return false; 171 s += prefixSize; 172 int pos = FindSepar(s); 173 if (pos < 0) 174 return true; 175 return s[(unsigned)pos + 1] == 0; 176 } 177 178 static const unsigned kDrivePrefixSize = 3; /* c:\ */ 179 180 bool IsDrivePath2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':'; } 181 // bool IsDriveName2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && s[2] == 0; } 182 bool IsSuperPath(const wchar_t *s) throw() { return IS_SUPER_PREFIX(s); } 183 bool IsSuperOrDevicePath(const wchar_t *s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); } 184 // bool IsSuperUncPath(const wchar_t *s) throw() { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); } 185 186 #ifndef USE_UNICODE_FSTRING 187 bool IsDrivePath2(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':'; } 188 // bool IsDriveName2(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && s[2] == 0; } 189 bool IsDrivePath(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); } 190 bool IsSuperPath(CFSTR s) throw() { return IS_SUPER_PREFIX(s); } 191 bool IsSuperOrDevicePath(CFSTR s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); } 192 #endif // USE_UNICODE_FSTRING 193 194 /* 195 bool IsDrivePath_SuperAllowed(CFSTR s) 196 { 197 if (IsSuperPath(s)) 198 s += kSuperPathPrefixSize; 199 return IsDrivePath(s); 200 } 201 */ 202 203 bool IsDriveRootPath_SuperAllowed(CFSTR s) throw() 204 { 205 if (IsSuperPath(s)) 206 s += kSuperPathPrefixSize; 207 return IsDrivePath(s) && s[kDrivePrefixSize] == 0; 208 } 209 210 bool IsAbsolutePath(const wchar_t *s) throw() 211 { 212 return IS_SEPAR(s[0]) || IsDrivePath2(s); 213 } 214 215 int FindAltStreamColon(CFSTR path) 216 { 217 unsigned i = 0; 218 if (IsDrivePath2(path)) 219 i = 2; 220 int colonPos = -1; 221 for (;; i++) 222 { 223 FChar c = path[i]; 224 if (c == 0) 225 return colonPos; 226 if (c == ':') 227 { 228 if (colonPos < 0) 229 colonPos = i; 230 continue; 231 } 232 if (IS_SEPAR(c)) 233 colonPos = -1; 234 } 235 } 236 237 #ifndef USE_UNICODE_FSTRING 238 239 static unsigned GetRootPrefixSize_Of_NetworkPath(CFSTR s) 240 { 241 // Network path: we look "server\path\" as root prefix 242 int pos = FindSepar(s); 243 if (pos < 0) 244 return 0; 245 int pos2 = FindSepar(s + (unsigned)pos + 1); 246 if (pos2 < 0) 247 return 0; 248 return pos + pos2 + 2; 249 } 250 251 static unsigned GetRootPrefixSize_Of_SimplePath(CFSTR s) 252 { 253 if (IsDrivePath(s)) 254 return kDrivePrefixSize; 255 if (!IS_SEPAR(s[0])) 256 return 0; 257 if (s[1] == 0 || !IS_SEPAR(s[1])) 258 return 1; 259 unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2); 260 return (size == 0) ? 0 : 2 + size; 261 } 262 263 static unsigned GetRootPrefixSize_Of_SuperPath(CFSTR s) 264 { 265 if (IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)) 266 { 267 unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize); 268 return (size == 0) ? 0 : kSuperUncPathPrefixSize + size; 269 } 270 // we support \\?\c:\ paths and volume GUID paths \\?\Volume{GUID}\" 271 int pos = FindSepar(s + kSuperPathPrefixSize); 272 if (pos < 0) 273 return 0; 274 return kSuperPathPrefixSize + pos + 1; 275 } 276 277 unsigned GetRootPrefixSize(CFSTR s) 278 { 279 if (IS_DEVICE_PATH(s)) 280 return kDevicePathPrefixSize; 281 if (IsSuperPath(s)) 282 return GetRootPrefixSize_Of_SuperPath(s); 283 return GetRootPrefixSize_Of_SimplePath(s); 284 } 285 286 #endif // USE_UNICODE_FSTRING 287 288 static unsigned GetRootPrefixSize_Of_NetworkPath(const wchar_t *s) 289 { 290 // Network path: we look "server\path\" as root prefix 291 int pos = FindSepar(s); 292 if (pos < 0) 293 return 0; 294 int pos2 = FindSepar(s + (unsigned)pos + 1); 295 if (pos2 < 0) 296 return 0; 297 return pos + pos2 + 2; 298 } 299 300 static unsigned GetRootPrefixSize_Of_SimplePath(const wchar_t *s) 301 { 302 if (IsDrivePath(s)) 303 return kDrivePrefixSize; 304 if (!IS_SEPAR(s[0])) 305 return 0; 306 if (s[1] == 0 || !IS_SEPAR(s[1])) 307 return 1; 308 unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2); 309 return (size == 0) ? 0 : 2 + size; 310 } 311 312 static unsigned GetRootPrefixSize_Of_SuperPath(const wchar_t *s) 313 { 314 if (IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)) 315 { 316 unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize); 317 return (size == 0) ? 0 : kSuperUncPathPrefixSize + size; 318 } 319 // we support \\?\c:\ paths and volume GUID paths \\?\Volume{GUID}\" 320 int pos = FindSepar(s + kSuperPathPrefixSize); 321 if (pos < 0) 322 return 0; 323 return kSuperPathPrefixSize + pos + 1; 324 } 325 326 unsigned GetRootPrefixSize(const wchar_t *s) throw() 327 { 328 if (IS_DEVICE_PATH(s)) 329 return kDevicePathPrefixSize; 330 if (IsSuperPath(s)) 331 return GetRootPrefixSize_Of_SuperPath(s); 332 return GetRootPrefixSize_Of_SimplePath(s); 333 } 334 335 #else // _WIN32 336 337 bool IsAbsolutePath(const wchar_t *s) { return IS_SEPAR(s[0]); } 338 339 #ifndef USE_UNICODE_FSTRING 340 unsigned GetRootPrefixSize(CFSTR s) { return IS_SEPAR(s[0]) ? 1 : 0; } 341 #endif 342 unsigned GetRootPrefixSize(const wchar_t *s) { return IS_SEPAR(s[0]) ? 1 : 0; } 343 344 #endif // _WIN32 345 346 347 #ifndef UNDER_CE 348 349 static bool GetCurDir(UString &path) 350 { 351 path.Empty(); 352 DWORD needLength; 353 #ifndef _UNICODE 354 if (!g_IsNT) 355 { 356 TCHAR s[MAX_PATH + 2]; 357 s[0] = 0; 358 needLength = ::GetCurrentDirectory(MAX_PATH + 1, s); 359 path = fs2us(fas2fs(s)); 360 } 361 else 362 #endif 363 { 364 WCHAR s[MAX_PATH + 2]; 365 s[0] = 0; 366 needLength = ::GetCurrentDirectoryW(MAX_PATH + 1, s); 367 path = s; 368 } 369 return (needLength > 0 && needLength <= MAX_PATH); 370 } 371 372 static bool ResolveDotsFolders(UString &s) 373 { 374 #ifdef _WIN32 375 // s.Replace(L'/', WCHAR_PATH_SEPARATOR); 376 #endif 377 378 for (unsigned i = 0;;) 379 { 380 const wchar_t c = s[i]; 381 if (c == 0) 382 return true; 383 if (c == '.' && (i == 0 || IS_SEPAR(s[i - 1]))) 384 { 385 const wchar_t c1 = s[i + 1]; 386 if (c1 == '.') 387 { 388 const wchar_t c2 = s[i + 2]; 389 if (IS_SEPAR(c2) || c2 == 0) 390 { 391 if (i == 0) 392 return false; 393 int k = i - 2; 394 i += 2; 395 396 for (;; k--) 397 { 398 if (k < 0) 399 return false; 400 if (!IS_SEPAR(s[(unsigned)k])) 401 break; 402 } 403 404 do 405 k--; 406 while (k >= 0 && !IS_SEPAR(s[(unsigned)k])); 407 408 unsigned num; 409 410 if (k >= 0) 411 { 412 num = i - k; 413 i = k; 414 } 415 else 416 { 417 num = (c2 == 0 ? i : (i + 1)); 418 i = 0; 419 } 420 421 s.Delete(i, num); 422 continue; 423 } 424 } 425 else if (IS_SEPAR(c1) || c1 == 0) 426 { 427 unsigned num = 2; 428 if (i != 0) 429 i--; 430 else if (c1 == 0) 431 num = 1; 432 s.Delete(i, num); 433 continue; 434 } 435 } 436 437 i++; 438 } 439 } 440 441 #endif // UNDER_CE 442 443 #define LONG_PATH_DOTS_FOLDERS_PARSING 444 445 446 /* 447 Windows (at least 64-bit XP) can't resolve "." or ".." in paths that start with SuperPrefix \\?\ 448 To solve that problem we check such path: 449 - super path contains "." or ".." - we use kSuperPathType_UseOnlySuper 450 - super path doesn't contain "." or ".." - we use kSuperPathType_UseOnlyMain 451 */ 452 #ifdef LONG_PATH_DOTS_FOLDERS_PARSING 453 #ifndef UNDER_CE 454 static bool AreThereDotsFolders(CFSTR s) 455 { 456 for (unsigned i = 0;; i++) 457 { 458 FChar c = s[i]; 459 if (c == 0) 460 return false; 461 if (c == '.' && (i == 0 || IS_SEPAR(s[i - 1]))) 462 { 463 FChar c1 = s[i + 1]; 464 if (c1 == 0 || IS_SEPAR(c1) || 465 (c1 == '.' && (s[i + 2] == 0 || IS_SEPAR(s[i + 2])))) 466 return true; 467 } 468 } 469 } 470 #endif 471 #endif // LONG_PATH_DOTS_FOLDERS_PARSING 472 473 #ifdef WIN_LONG_PATH 474 475 /* 476 Most of Windows versions have problems, if some file or dir name 477 contains '.' or ' ' at the end of name (Bad Path). 478 To solve that problem, we always use Super Path ("\\?\" prefix and full path) 479 in such cases. Note that "." and ".." are not bad names. 480 481 There are 3 cases: 482 1) If the path is already Super Path, we use that path 483 2) If the path is not Super Path : 484 2.1) Bad Path; we use only Super Path. 485 2.2) Good Path; we use Main Path. If it fails, we use Super Path. 486 487 NeedToUseOriginalPath returns: 488 kSuperPathType_UseOnlyMain : Super already 489 kSuperPathType_UseOnlySuper : not Super, Bad Path 490 kSuperPathType_UseMainAndSuper : not Super, Good Path 491 */ 492 493 int GetUseSuperPathType(CFSTR s) throw() 494 { 495 if (IsSuperOrDevicePath(s)) 496 { 497 #ifdef LONG_PATH_DOTS_FOLDERS_PARSING 498 if ((s)[2] != '.') 499 if (AreThereDotsFolders(s + kSuperPathPrefixSize)) 500 return kSuperPathType_UseOnlySuper; 501 #endif 502 return kSuperPathType_UseOnlyMain; 503 } 504 505 for (unsigned i = 0;; i++) 506 { 507 FChar c = s[i]; 508 if (c == 0) 509 return kSuperPathType_UseMainAndSuper; 510 if (c == '.' || c == ' ') 511 { 512 FChar c2 = s[i + 1]; 513 if (c2 == 0 || IS_SEPAR(c2)) 514 { 515 // if it's "." or "..", it's not bad name. 516 if (c == '.') 517 { 518 if (i == 0 || IS_SEPAR(s[i - 1])) 519 continue; 520 if (s[i - 1] == '.') 521 { 522 if (i - 1 == 0 || IS_SEPAR(s[i - 2])) 523 continue; 524 } 525 } 526 return kSuperPathType_UseOnlySuper; 527 } 528 } 529 } 530 } 531 532 533 /* 534 returns false in two cases: 535 - if GetCurDir was used, and GetCurDir returned error. 536 - if we can't resolve ".." name. 537 if path is ".", "..", res is empty. 538 if it's Super Path already, res is empty. 539 for \**** , and if GetCurDir is not drive (c:\), res is empty 540 for absolute paths, returns true, res is Super path. 541 */ 542 543 544 static bool GetSuperPathBase(CFSTR s, UString &res) 545 { 546 res.Empty(); 547 548 FChar c = s[0]; 549 if (c == 0) 550 return true; 551 if (c == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0))) 552 return true; 553 554 if (IsSuperOrDevicePath(s)) 555 { 556 #ifdef LONG_PATH_DOTS_FOLDERS_PARSING 557 558 if ((s)[2] == '.') 559 return true; 560 561 // we will return true here, so we will try to use these problem paths. 562 563 if (!AreThereDotsFolders(s + kSuperPathPrefixSize)) 564 return true; 565 566 UString temp = fs2us(s); 567 unsigned fixedSize = GetRootPrefixSize_Of_SuperPath(temp); 568 if (fixedSize == 0) 569 return true; 570 571 UString rem = &temp[fixedSize]; 572 if (!ResolveDotsFolders(rem)) 573 return true; 574 575 temp.DeleteFrom(fixedSize); 576 res += temp; 577 res += rem; 578 579 #endif 580 581 return true; 582 } 583 584 if (IS_SEPAR(c)) 585 { 586 if (IS_SEPAR(s[1])) 587 { 588 UString temp = fs2us(s + 2); 589 unsigned fixedSize = GetRootPrefixSize_Of_NetworkPath(temp); 590 // we ignore that error to allow short network paths server\share? 591 /* 592 if (fixedSize == 0) 593 return false; 594 */ 595 UString rem = &temp[fixedSize]; 596 if (!ResolveDotsFolders(rem)) 597 return false; 598 res += kSuperUncPrefix; 599 temp.DeleteFrom(fixedSize); 600 res += temp; 601 res += rem; 602 return true; 603 } 604 } 605 else 606 { 607 if (IsDrivePath2(s)) 608 { 609 UString temp = fs2us(s); 610 unsigned prefixSize = 2; 611 if (IsDrivePath(s)) 612 prefixSize = kDrivePrefixSize; 613 UString rem = temp.Ptr(prefixSize); 614 if (!ResolveDotsFolders(rem)) 615 return true; 616 res += kSuperPathPrefix; 617 temp.DeleteFrom(prefixSize); 618 res += temp; 619 res += rem; 620 return true; 621 } 622 } 623 624 UString curDir; 625 if (!GetCurDir(curDir)) 626 return false; 627 NormalizeDirPathPrefix(curDir); 628 629 unsigned fixedSizeStart = 0; 630 unsigned fixedSize = 0; 631 const wchar_t *superMarker = NULL; 632 if (IsSuperPath(curDir)) 633 { 634 fixedSize = GetRootPrefixSize_Of_SuperPath(curDir); 635 if (fixedSize == 0) 636 return false; 637 } 638 else 639 { 640 if (IsDrivePath(curDir)) 641 { 642 superMarker = kSuperPathPrefix; 643 fixedSize = kDrivePrefixSize; 644 } 645 else 646 { 647 if (!IsPathSepar(curDir[0]) || !IsPathSepar(curDir[1])) 648 return false; 649 fixedSizeStart = 2; 650 fixedSize = GetRootPrefixSize_Of_NetworkPath(curDir.Ptr(2)); 651 if (fixedSize == 0) 652 return false; 653 superMarker = kSuperUncPrefix; 654 } 655 } 656 657 UString temp; 658 if (IS_SEPAR(c)) 659 { 660 temp = fs2us(s + 1); 661 } 662 else 663 { 664 temp += &curDir[fixedSizeStart + fixedSize]; 665 temp += fs2us(s); 666 } 667 if (!ResolveDotsFolders(temp)) 668 return false; 669 if (superMarker) 670 res += superMarker; 671 res += curDir.Mid(fixedSizeStart, fixedSize); 672 res += temp; 673 return true; 674 } 675 676 677 /* 678 In that case if GetSuperPathBase doesn't return new path, we don't need 679 to use same path that was used as main path 680 681 GetSuperPathBase superPath.IsEmpty() onlyIfNew 682 false * * GetCurDir Error 683 true false * use Super path 684 true true true don't use any path, we already used mainPath 685 true true false use main path as Super Path, we don't try mainMath 686 That case is possible now if GetCurDir returns unknow 687 type of path (not drive and not network) 688 689 We can change that code if we want to try mainPath, if GetSuperPathBase returns error, 690 and we didn't try mainPath still. 691 If we want to work that way, we don't need to use GetSuperPathBase return code. 692 */ 693 694 bool GetSuperPath(CFSTR path, UString &superPath, bool onlyIfNew) 695 { 696 if (GetSuperPathBase(path, superPath)) 697 { 698 if (superPath.IsEmpty()) 699 { 700 // actually the only possible when onlyIfNew == true and superPath is empty 701 // is case when 702 703 if (onlyIfNew) 704 return false; 705 superPath = fs2us(path); 706 } 707 return true; 708 } 709 return false; 710 } 711 712 bool GetSuperPaths(CFSTR s1, CFSTR s2, UString &d1, UString &d2, bool onlyIfNew) 713 { 714 if (!GetSuperPathBase(s1, d1) || 715 !GetSuperPathBase(s2, d2)) 716 return false; 717 if (d1.IsEmpty() && d2.IsEmpty() && onlyIfNew) 718 return false; 719 if (d1.IsEmpty()) d1 = fs2us(s1); 720 if (d2.IsEmpty()) d2 = fs2us(s2); 721 return true; 722 } 723 724 725 /* 726 // returns true, if we need additional use with New Super path. 727 bool GetSuperPath(CFSTR path, UString &superPath) 728 { 729 if (GetSuperPathBase(path, superPath)) 730 return !superPath.IsEmpty(); 731 return false; 732 } 733 */ 734 #endif // WIN_LONG_PATH 735 736 bool GetFullPath(CFSTR dirPrefix, CFSTR s, FString &res) 737 { 738 res = s; 739 740 #ifdef UNDER_CE 741 742 if (!IS_SEPAR(s[0])) 743 { 744 if (!dirPrefix) 745 return false; 746 res = dirPrefix; 747 res += s; 748 } 749 750 #else 751 752 unsigned prefixSize = GetRootPrefixSize(s); 753 if (prefixSize != 0) 754 { 755 if (!AreThereDotsFolders(s + prefixSize)) 756 return true; 757 758 UString rem = fs2us(s + prefixSize); 759 if (!ResolveDotsFolders(rem)) 760 return true; // maybe false; 761 res.DeleteFrom(prefixSize); 762 res += us2fs(rem); 763 return true; 764 } 765 766 /* 767 FChar c = s[0]; 768 if (c == 0) 769 return true; 770 if (c == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0))) 771 return true; 772 if (IS_SEPAR(c) && IS_SEPAR(s[1])) 773 return true; 774 if (IsDrivePath(s)) 775 return true; 776 */ 777 778 UString curDir; 779 if (dirPrefix) 780 curDir = fs2us(dirPrefix); 781 else 782 { 783 if (!GetCurDir(curDir)) 784 return false; 785 } 786 NormalizeDirPathPrefix(curDir); 787 788 unsigned fixedSize = 0; 789 790 #ifdef _WIN32 791 792 if (IsSuperPath(curDir)) 793 { 794 fixedSize = GetRootPrefixSize_Of_SuperPath(curDir); 795 if (fixedSize == 0) 796 return false; 797 } 798 else 799 { 800 if (IsDrivePath(curDir)) 801 fixedSize = kDrivePrefixSize; 802 else 803 { 804 if (!IsPathSepar(curDir[0]) || !IsPathSepar(curDir[1])) 805 return false; 806 fixedSize = GetRootPrefixSize_Of_NetworkPath(curDir.Ptr(2)); 807 if (fixedSize == 0) 808 return false; 809 fixedSize += 2; 810 } 811 } 812 813 #endif // _WIN32 814 815 UString temp; 816 if (IS_SEPAR(s[0])) 817 { 818 temp = fs2us(s + 1); 819 } 820 else 821 { 822 temp += curDir.Ptr(fixedSize); 823 temp += fs2us(s); 824 } 825 if (!ResolveDotsFolders(temp)) 826 return false; 827 curDir.DeleteFrom(fixedSize); 828 res = us2fs(curDir); 829 res += us2fs(temp); 830 831 #endif // UNDER_CE 832 833 return true; 834 } 835 836 bool GetFullPath(CFSTR path, FString &fullPath) 837 { 838 return GetFullPath(NULL, path, fullPath); 839 } 840 841 }}} 842