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