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