xref: /aosp_15_r20/external/lzma/CPP/Windows/FileName.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
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