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