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