• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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