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
FindSepar(const wchar_t * s)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
FindSepar(const FChar * s)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
NormalizeDirPathPrefix(FString & dirPath)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
NormalizeDirPathPrefix(UString & dirPath)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
IsDrivePath(const wchar_t * s)63 bool IsDrivePath(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); }
64
IsAltPathPrefix(CFSTR s)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
IsDevicePath(CFSTR s)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
IsSuperUncPath(CFSTR s)136 bool IsSuperUncPath(CFSTR s) throw() { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); }
IsNetworkPath(CFSTR s)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
GetNetworkServerPrefixSize(CFSTR s)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
IsNetworkShareRootPath(CFSTR s)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
IsDrivePath2(const wchar_t * s)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; }
IsSuperPath(const wchar_t * s)182 bool IsSuperPath(const wchar_t *s) throw() { return IS_SUPER_PREFIX(s); }
IsSuperOrDevicePath(const wchar_t * 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
IsDrivePath2(CFSTR s)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; }
IsDrivePath(CFSTR s)189 bool IsDrivePath(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); }
IsSuperPath(CFSTR s)190 bool IsSuperPath(CFSTR s) throw() { return IS_SUPER_PREFIX(s); }
IsSuperOrDevicePath(CFSTR s)191 bool IsSuperOrDevicePath(CFSTR s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); }
192 #endif // USE_UNICODE_FSTRING
193
IsDrivePath_SuperAllowed(CFSTR s)194 bool IsDrivePath_SuperAllowed(CFSTR s) throw()
195 {
196 if (IsSuperPath(s))
197 s += kSuperPathPrefixSize;
198 return IsDrivePath(s);
199 }
200
IsDriveRootPath_SuperAllowed(CFSTR s)201 bool IsDriveRootPath_SuperAllowed(CFSTR s) throw()
202 {
203 if (IsSuperPath(s))
204 s += kSuperPathPrefixSize;
205 return IsDrivePath(s) && s[kDrivePrefixSize] == 0;
206 }
207
IsAbsolutePath(const wchar_t * s)208 bool IsAbsolutePath(const wchar_t *s) throw()
209 {
210 return IS_SEPAR(s[0]) || IsDrivePath2(s);
211 }
212
FindAltStreamColon(CFSTR path)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
GetRootPrefixSize_Of_NetworkPath(CFSTR s)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
GetRootPrefixSize_Of_SimplePath(CFSTR s)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
GetRootPrefixSize_Of_SuperPath(CFSTR s)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
GetRootPrefixSize(CFSTR s)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
GetRootPrefixSize_Of_NetworkPath(const wchar_t * s)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
GetRootPrefixSize_Of_SimplePath(const wchar_t * s)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
GetRootPrefixSize_Of_SuperPath(const wchar_t * s)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
GetRootPrefixSize(const wchar_t * s)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
IsAbsolutePath(const wchar_t * s)335 bool IsAbsolutePath(const wchar_t *s) { return IS_SEPAR(s[0]); }
336
337 #ifndef USE_UNICODE_FSTRING
GetRootPrefixSize(CFSTR s)338 unsigned GetRootPrefixSize(CFSTR s) { return IS_SEPAR(s[0]) ? 1 : 0; }
339 #endif
GetRootPrefixSize(const wchar_t * s)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
GetCurDir(UString & path)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
ResolveDotsFolders(UString & s)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
AreThereDotsFolders(CFSTR s)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
GetUseSuperPathType(CFSTR s)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
GetSuperPathBase(CFSTR s,UString & res)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
GetSuperPath(CFSTR path,UString & superPath,bool onlyIfNew)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
GetSuperPaths(CFSTR s1,CFSTR s2,UString & d1,UString & d2,bool onlyIfNew)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
GetFullPath(CFSTR dirPrefix,CFSTR s,FString & res)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
GetFullPath(CFSTR path,FString & fullPath)834 bool GetFullPath(CFSTR path, FString &fullPath)
835 {
836 return GetFullPath(NULL, path, fullPath);
837 }
838
839 }}}
840