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