Home | History | Annotate | Download | only in Windows
      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 
     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
     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
     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 
     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 
     63 bool IsDrivePath(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); }
     64 
     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 
    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 
    136 bool IsSuperUncPath(CFSTR s) throw() { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); }
    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 
    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 
    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 
    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; }
    182 bool IsSuperPath(const wchar_t *s) throw() { return IS_SUPER_PREFIX(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
    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; }
    189 bool IsDrivePath(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); }
    190 bool IsSuperPath(CFSTR s) throw() { return IS_SUPER_PREFIX(s); }
    191 bool IsSuperOrDevicePath(CFSTR s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); }
    192 #endif // USE_UNICODE_FSTRING
    193 
    194 bool IsDrivePath_SuperAllowed(CFSTR s) throw()
    195 {
    196   if (IsSuperPath(s))
    197     s += kSuperPathPrefixSize;
    198   return IsDrivePath(s);
    199 }
    200 
    201 bool IsDriveRootPath_SuperAllowed(CFSTR s) throw()
    202 {
    203   if (IsSuperPath(s))
    204     s += kSuperPathPrefixSize;
    205   return IsDrivePath(s) && s[kDrivePrefixSize] == 0;
    206 }
    207 
    208 bool IsAbsolutePath(const wchar_t *s) throw()
    209 {
    210   return IS_SEPAR(s[0]) || IsDrivePath2(s);
    211 }
    212 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    335 bool IsAbsolutePath(const wchar_t *s) { return IS_SEPAR(s[0]); }
    336 
    337 #ifndef USE_UNICODE_FSTRING
    338 unsigned GetRootPrefixSize(CFSTR s) { return IS_SEPAR(s[0]) ? 1 : 0; }
    339 #endif
    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 
    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 
    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
    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 
    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 
    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 
    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 
    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 
    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 
    834 bool GetFullPath(CFSTR path, FString &fullPath)
    835 {
    836   return GetFullPath(NULL, path, fullPath);
    837 }
    838 
    839 }}}
    840