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 char * const kSuperPathPrefix = "\\\\?\\"; 91 static const char * const kSuperUncPrefix = "\\\\?\\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 || !IsString1PrefixedByString2(s, "DSK")) 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 || !IsString1PrefixedByString2(s + kDevicePathPrefixSize, "PhysicalDrive")) 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 bool IsDrivePath_SuperAllowed(CFSTR s) throw() 195 { 196 if (IsSuperPath(s)) 197 s += kSuperPathPrefixSize; 198 return IsDrivePath(s); 199 } 200 201 bool IsDriveRootPath_SuperAllowed(CFSTR s) throw() 202 { 203 if (IsSuperPath(s)) 204 s += kSuperPathPrefixSize; 205 return IsDrivePath(s) && s[kDrivePrefixSize] == 0; 206 } 207 208 bool IsAbsolutePath(const wchar_t *s) throw() 209 { 210 return IS_SEPAR(s[0]) || IsDrivePath2(s); 211 } 212 213 int FindAltStreamColon(CFSTR path) throw() 214 { 215 unsigned i = 0; 216 if (IsDrivePath2(path)) 217 i = 2; 218 int colonPos = -1; 219 for (;; i++) 220 { 221 FChar c = path[i]; 222 if (c == 0) 223 return colonPos; 224 if (c == ':') 225 { 226 if (colonPos < 0) 227 colonPos = i; 228 continue; 229 } 230 if (IS_SEPAR(c)) 231 colonPos = -1; 232 } 233 } 234 235 #ifndef USE_UNICODE_FSTRING 236 237 static unsigned GetRootPrefixSize_Of_NetworkPath(CFSTR s) 238 { 239 // Network path: we look "server\path\" as root prefix 240 int pos = FindSepar(s); 241 if (pos < 0) 242 return 0; 243 int pos2 = FindSepar(s + (unsigned)pos + 1); 244 if (pos2 < 0) 245 return 0; 246 return pos + pos2 + 2; 247 } 248 249 static unsigned GetRootPrefixSize_Of_SimplePath(CFSTR s) 250 { 251 if (IsDrivePath(s)) 252 return kDrivePrefixSize; 253 if (!IS_SEPAR(s[0])) 254 return 0; 255 if (s[1] == 0 || !IS_SEPAR(s[1])) 256 return 1; 257 unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2); 258 return (size == 0) ? 0 : 2 + size; 259 } 260 261 static unsigned GetRootPrefixSize_Of_SuperPath(CFSTR s) 262 { 263 if (IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)) 264 { 265 unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize); 266 return (size == 0) ? 0 : kSuperUncPathPrefixSize + size; 267 } 268 // we support \\?\c:\ paths and volume GUID paths \\?\Volume{GUID}\" 269 int pos = FindSepar(s + kSuperPathPrefixSize); 270 if (pos < 0) 271 return 0; 272 return kSuperPathPrefixSize + pos + 1; 273 } 274 275 unsigned GetRootPrefixSize(CFSTR s) throw() 276 { 277 if (IS_DEVICE_PATH(s)) 278 return kDevicePathPrefixSize; 279 if (IsSuperPath(s)) 280 return GetRootPrefixSize_Of_SuperPath(s); 281 return GetRootPrefixSize_Of_SimplePath(s); 282 } 283 284 #endif // USE_UNICODE_FSTRING 285 286 static unsigned GetRootPrefixSize_Of_NetworkPath(const wchar_t *s) throw() 287 { 288 // Network path: we look "server\path\" as root prefix 289 int pos = FindSepar(s); 290 if (pos < 0) 291 return 0; 292 int pos2 = FindSepar(s + (unsigned)pos + 1); 293 if (pos2 < 0) 294 return 0; 295 return pos + pos2 + 2; 296 } 297 298 static unsigned GetRootPrefixSize_Of_SimplePath(const wchar_t *s) throw() 299 { 300 if (IsDrivePath(s)) 301 return kDrivePrefixSize; 302 if (!IS_SEPAR(s[0])) 303 return 0; 304 if (s[1] == 0 || !IS_SEPAR(s[1])) 305 return 1; 306 unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2); 307 return (size == 0) ? 0 : 2 + size; 308 } 309 310 static unsigned GetRootPrefixSize_Of_SuperPath(const wchar_t *s) throw() 311 { 312 if (IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)) 313 { 314 unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize); 315 return (size == 0) ? 0 : kSuperUncPathPrefixSize + size; 316 } 317 // we support \\?\c:\ paths and volume GUID paths \\?\Volume{GUID}\" 318 int pos = FindSepar(s + kSuperPathPrefixSize); 319 if (pos < 0) 320 return 0; 321 return kSuperPathPrefixSize + pos + 1; 322 } 323 324 unsigned GetRootPrefixSize(const wchar_t *s) throw() 325 { 326 if (IS_DEVICE_PATH(s)) 327 return kDevicePathPrefixSize; 328 if (IsSuperPath(s)) 329 return GetRootPrefixSize_Of_SuperPath(s); 330 return GetRootPrefixSize_Of_SimplePath(s); 331 } 332 333 #else // _WIN32 334 335 bool IsAbsolutePath(const wchar_t *s) { return IS_SEPAR(s[0]); } 336 337 #ifndef USE_UNICODE_FSTRING 338 unsigned GetRootPrefixSize(CFSTR s) { return IS_SEPAR(s[0]) ? 1 : 0; } 339 #endif 340 unsigned GetRootPrefixSize(const wchar_t *s) { return IS_SEPAR(s[0]) ? 1 : 0; } 341 342 #endif // _WIN32 343 344 345 #ifndef UNDER_CE 346 347 static bool GetCurDir(UString &path) 348 { 349 path.Empty(); 350 DWORD needLength; 351 #ifndef _UNICODE 352 if (!g_IsNT) 353 { 354 TCHAR s[MAX_PATH + 2]; 355 s[0] = 0; 356 needLength = ::GetCurrentDirectory(MAX_PATH + 1, s); 357 path = fs2us(fas2fs(s)); 358 } 359 else 360 #endif 361 { 362 WCHAR s[MAX_PATH + 2]; 363 s[0] = 0; 364 needLength = ::GetCurrentDirectoryW(MAX_PATH + 1, s); 365 path = s; 366 } 367 return (needLength > 0 && needLength <= MAX_PATH); 368 } 369 370 static bool ResolveDotsFolders(UString &s) 371 { 372 #ifdef _WIN32 373 // s.Replace(L'/', WCHAR_PATH_SEPARATOR); 374 #endif 375 376 for (unsigned i = 0;;) 377 { 378 const wchar_t c = s[i]; 379 if (c == 0) 380 return true; 381 if (c == '.' && (i == 0 || IS_SEPAR(s[i - 1]))) 382 { 383 const wchar_t c1 = s[i + 1]; 384 if (c1 == '.') 385 { 386 const wchar_t c2 = s[i + 2]; 387 if (IS_SEPAR(c2) || c2 == 0) 388 { 389 if (i == 0) 390 return false; 391 int k = i - 2; 392 i += 2; 393 394 for (;; k--) 395 { 396 if (k < 0) 397 return false; 398 if (!IS_SEPAR(s[(unsigned)k])) 399 break; 400 } 401 402 do 403 k--; 404 while (k >= 0 && !IS_SEPAR(s[(unsigned)k])); 405 406 unsigned num; 407 408 if (k >= 0) 409 { 410 num = i - k; 411 i = k; 412 } 413 else 414 { 415 num = (c2 == 0 ? i : (i + 1)); 416 i = 0; 417 } 418 419 s.Delete(i, num); 420 continue; 421 } 422 } 423 else if (IS_SEPAR(c1) || c1 == 0) 424 { 425 unsigned num = 2; 426 if (i != 0) 427 i--; 428 else if (c1 == 0) 429 num = 1; 430 s.Delete(i, num); 431 continue; 432 } 433 } 434 435 i++; 436 } 437 } 438 439 #endif // UNDER_CE 440 441 #define LONG_PATH_DOTS_FOLDERS_PARSING 442 443 444 /* 445 Windows (at least 64-bit XP) can't resolve "." or ".." in paths that start with SuperPrefix \\?\ 446 To solve that problem we check such path: 447 - super path contains "." or ".." - we use kSuperPathType_UseOnlySuper 448 - super path doesn't contain "." or ".." - we use kSuperPathType_UseOnlyMain 449 */ 450 #ifdef LONG_PATH_DOTS_FOLDERS_PARSING 451 #ifndef UNDER_CE 452 static bool AreThereDotsFolders(CFSTR s) 453 { 454 for (unsigned i = 0;; i++) 455 { 456 FChar c = s[i]; 457 if (c == 0) 458 return false; 459 if (c == '.' && (i == 0 || IS_SEPAR(s[i - 1]))) 460 { 461 FChar c1 = s[i + 1]; 462 if (c1 == 0 || IS_SEPAR(c1) || 463 (c1 == '.' && (s[i + 2] == 0 || IS_SEPAR(s[i + 2])))) 464 return true; 465 } 466 } 467 } 468 #endif 469 #endif // LONG_PATH_DOTS_FOLDERS_PARSING 470 471 #ifdef WIN_LONG_PATH 472 473 /* 474 Most of Windows versions have problems, if some file or dir name 475 contains '.' or ' ' at the end of name (Bad Path). 476 To solve that problem, we always use Super Path ("\\?\" prefix and full path) 477 in such cases. Note that "." and ".." are not bad names. 478 479 There are 3 cases: 480 1) If the path is already Super Path, we use that path 481 2) If the path is not Super Path : 482 2.1) Bad Path; we use only Super Path. 483 2.2) Good Path; we use Main Path. If it fails, we use Super Path. 484 485 NeedToUseOriginalPath returns: 486 kSuperPathType_UseOnlyMain : Super already 487 kSuperPathType_UseOnlySuper : not Super, Bad Path 488 kSuperPathType_UseMainAndSuper : not Super, Good Path 489 */ 490 491 int GetUseSuperPathType(CFSTR s) throw() 492 { 493 if (IsSuperOrDevicePath(s)) 494 { 495 #ifdef LONG_PATH_DOTS_FOLDERS_PARSING 496 if ((s)[2] != '.') 497 if (AreThereDotsFolders(s + kSuperPathPrefixSize)) 498 return kSuperPathType_UseOnlySuper; 499 #endif 500 return kSuperPathType_UseOnlyMain; 501 } 502 503 for (unsigned i = 0;; i++) 504 { 505 FChar c = s[i]; 506 if (c == 0) 507 return kSuperPathType_UseMainAndSuper; 508 if (c == '.' || c == ' ') 509 { 510 FChar c2 = s[i + 1]; 511 if (c2 == 0 || IS_SEPAR(c2)) 512 { 513 // if it's "." or "..", it's not bad name. 514 if (c == '.') 515 { 516 if (i == 0 || IS_SEPAR(s[i - 1])) 517 continue; 518 if (s[i - 1] == '.') 519 { 520 if (i - 1 == 0 || IS_SEPAR(s[i - 2])) 521 continue; 522 } 523 } 524 return kSuperPathType_UseOnlySuper; 525 } 526 } 527 } 528 } 529 530 531 /* 532 returns false in two cases: 533 - if GetCurDir was used, and GetCurDir returned error. 534 - if we can't resolve ".." name. 535 if path is ".", "..", res is empty. 536 if it's Super Path already, res is empty. 537 for \**** , and if GetCurDir is not drive (c:\), res is empty 538 for absolute paths, returns true, res is Super path. 539 */ 540 541 542 static bool GetSuperPathBase(CFSTR s, UString &res) 543 { 544 res.Empty(); 545 546 FChar c = s[0]; 547 if (c == 0) 548 return true; 549 if (c == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0))) 550 return true; 551 552 if (IsSuperOrDevicePath(s)) 553 { 554 #ifdef LONG_PATH_DOTS_FOLDERS_PARSING 555 556 if ((s)[2] == '.') 557 return true; 558 559 // we will return true here, so we will try to use these problem paths. 560 561 if (!AreThereDotsFolders(s + kSuperPathPrefixSize)) 562 return true; 563 564 UString temp = fs2us(s); 565 unsigned fixedSize = GetRootPrefixSize_Of_SuperPath(temp); 566 if (fixedSize == 0) 567 return true; 568 569 UString rem = &temp[fixedSize]; 570 if (!ResolveDotsFolders(rem)) 571 return true; 572 573 temp.DeleteFrom(fixedSize); 574 res += temp; 575 res += rem; 576 577 #endif 578 579 return true; 580 } 581 582 if (IS_SEPAR(c)) 583 { 584 if (IS_SEPAR(s[1])) 585 { 586 UString temp = fs2us(s + 2); 587 unsigned fixedSize = GetRootPrefixSize_Of_NetworkPath(temp); 588 // we ignore that error to allow short network paths server\share? 589 /* 590 if (fixedSize == 0) 591 return false; 592 */ 593 UString rem = &temp[fixedSize]; 594 if (!ResolveDotsFolders(rem)) 595 return false; 596 res += kSuperUncPrefix; 597 temp.DeleteFrom(fixedSize); 598 res += temp; 599 res += rem; 600 return true; 601 } 602 } 603 else 604 { 605 if (IsDrivePath2(s)) 606 { 607 UString temp = fs2us(s); 608 unsigned prefixSize = 2; 609 if (IsDrivePath(s)) 610 prefixSize = kDrivePrefixSize; 611 UString rem = temp.Ptr(prefixSize); 612 if (!ResolveDotsFolders(rem)) 613 return true; 614 res += kSuperPathPrefix; 615 temp.DeleteFrom(prefixSize); 616 res += temp; 617 res += rem; 618 return true; 619 } 620 } 621 622 UString curDir; 623 if (!GetCurDir(curDir)) 624 return false; 625 NormalizeDirPathPrefix(curDir); 626 627 unsigned fixedSizeStart = 0; 628 unsigned fixedSize = 0; 629 const char *superMarker = NULL; 630 if (IsSuperPath(curDir)) 631 { 632 fixedSize = GetRootPrefixSize_Of_SuperPath(curDir); 633 if (fixedSize == 0) 634 return false; 635 } 636 else 637 { 638 if (IsDrivePath(curDir)) 639 { 640 superMarker = kSuperPathPrefix; 641 fixedSize = kDrivePrefixSize; 642 } 643 else 644 { 645 if (!IsPathSepar(curDir[0]) || !IsPathSepar(curDir[1])) 646 return false; 647 fixedSizeStart = 2; 648 fixedSize = GetRootPrefixSize_Of_NetworkPath(curDir.Ptr(2)); 649 if (fixedSize == 0) 650 return false; 651 superMarker = kSuperUncPrefix; 652 } 653 } 654 655 UString temp; 656 if (IS_SEPAR(c)) 657 { 658 temp = fs2us(s + 1); 659 } 660 else 661 { 662 temp += &curDir[fixedSizeStart + fixedSize]; 663 temp += fs2us(s); 664 } 665 if (!ResolveDotsFolders(temp)) 666 return false; 667 if (superMarker) 668 res += superMarker; 669 res += curDir.Mid(fixedSizeStart, fixedSize); 670 res += temp; 671 return true; 672 } 673 674 675 /* 676 In that case if GetSuperPathBase doesn't return new path, we don't need 677 to use same path that was used as main path 678 679 GetSuperPathBase superPath.IsEmpty() onlyIfNew 680 false * * GetCurDir Error 681 true false * use Super path 682 true true true don't use any path, we already used mainPath 683 true true false use main path as Super Path, we don't try mainMath 684 That case is possible now if GetCurDir returns unknow 685 type of path (not drive and not network) 686 687 We can change that code if we want to try mainPath, if GetSuperPathBase returns error, 688 and we didn't try mainPath still. 689 If we want to work that way, we don't need to use GetSuperPathBase return code. 690 */ 691 692 bool GetSuperPath(CFSTR path, UString &superPath, bool onlyIfNew) 693 { 694 if (GetSuperPathBase(path, superPath)) 695 { 696 if (superPath.IsEmpty()) 697 { 698 // actually the only possible when onlyIfNew == true and superPath is empty 699 // is case when 700 701 if (onlyIfNew) 702 return false; 703 superPath = fs2us(path); 704 } 705 return true; 706 } 707 return false; 708 } 709 710 bool GetSuperPaths(CFSTR s1, CFSTR s2, UString &d1, UString &d2, bool onlyIfNew) 711 { 712 if (!GetSuperPathBase(s1, d1) || 713 !GetSuperPathBase(s2, d2)) 714 return false; 715 if (d1.IsEmpty() && d2.IsEmpty() && onlyIfNew) 716 return false; 717 if (d1.IsEmpty()) d1 = fs2us(s1); 718 if (d2.IsEmpty()) d2 = fs2us(s2); 719 return true; 720 } 721 722 723 /* 724 // returns true, if we need additional use with New Super path. 725 bool GetSuperPath(CFSTR path, UString &superPath) 726 { 727 if (GetSuperPathBase(path, superPath)) 728 return !superPath.IsEmpty(); 729 return false; 730 } 731 */ 732 #endif // WIN_LONG_PATH 733 734 bool GetFullPath(CFSTR dirPrefix, CFSTR s, FString &res) 735 { 736 res = s; 737 738 #ifdef UNDER_CE 739 740 if (!IS_SEPAR(s[0])) 741 { 742 if (!dirPrefix) 743 return false; 744 res = dirPrefix; 745 res += s; 746 } 747 748 #else 749 750 unsigned prefixSize = GetRootPrefixSize(s); 751 if (prefixSize != 0) 752 { 753 if (!AreThereDotsFolders(s + prefixSize)) 754 return true; 755 756 UString rem = fs2us(s + prefixSize); 757 if (!ResolveDotsFolders(rem)) 758 return true; // maybe false; 759 res.DeleteFrom(prefixSize); 760 res += us2fs(rem); 761 return true; 762 } 763 764 /* 765 FChar c = s[0]; 766 if (c == 0) 767 return true; 768 if (c == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0))) 769 return true; 770 if (IS_SEPAR(c) && IS_SEPAR(s[1])) 771 return true; 772 if (IsDrivePath(s)) 773 return true; 774 */ 775 776 UString curDir; 777 if (dirPrefix) 778 curDir = fs2us(dirPrefix); 779 else 780 { 781 if (!GetCurDir(curDir)) 782 return false; 783 } 784 NormalizeDirPathPrefix(curDir); 785 786 unsigned fixedSize = 0; 787 788 #ifdef _WIN32 789 790 if (IsSuperPath(curDir)) 791 { 792 fixedSize = GetRootPrefixSize_Of_SuperPath(curDir); 793 if (fixedSize == 0) 794 return false; 795 } 796 else 797 { 798 if (IsDrivePath(curDir)) 799 fixedSize = kDrivePrefixSize; 800 else 801 { 802 if (!IsPathSepar(curDir[0]) || !IsPathSepar(curDir[1])) 803 return false; 804 fixedSize = GetRootPrefixSize_Of_NetworkPath(curDir.Ptr(2)); 805 if (fixedSize == 0) 806 return false; 807 fixedSize += 2; 808 } 809 } 810 811 #endif // _WIN32 812 813 UString temp; 814 if (IS_SEPAR(s[0])) 815 { 816 temp = fs2us(s + 1); 817 } 818 else 819 { 820 temp += curDir.Ptr(fixedSize); 821 temp += fs2us(s); 822 } 823 if (!ResolveDotsFolders(temp)) 824 return false; 825 curDir.DeleteFrom(fixedSize); 826 res = us2fs(curDir); 827 res += us2fs(temp); 828 829 #endif // UNDER_CE 830 831 return true; 832 } 833 834 bool GetFullPath(CFSTR path, FString &fullPath) 835 { 836 return GetFullPath(NULL, path, fullPath); 837 } 838 839 }}} 840