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 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 
    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 
    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 /*
    195 bool IsDrivePath_SuperAllowed(CFSTR s)
    196 {
    197   if (IsSuperPath(s))
    198     s += kSuperPathPrefixSize;
    199   return IsDrivePath(s);
    200 }
    201 */
    202 
    203 bool IsDriveRootPath_SuperAllowed(CFSTR s) throw()
    204 {
    205   if (IsSuperPath(s))
    206     s += kSuperPathPrefixSize;
    207   return IsDrivePath(s) && s[kDrivePrefixSize] == 0;
    208 }
    209 
    210 bool IsAbsolutePath(const wchar_t *s) throw()
    211 {
    212   return IS_SEPAR(s[0]) || IsDrivePath2(s);
    213 }
    214 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    337 bool IsAbsolutePath(const wchar_t *s) { return IS_SEPAR(s[0]); }
    338 
    339 #ifndef USE_UNICODE_FSTRING
    340 unsigned GetRootPrefixSize(CFSTR s) { return IS_SEPAR(s[0]) ? 1 : 0; }
    341 #endif
    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 
    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 
    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
    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 
    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 
    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 
    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 
    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 
    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 
    836 bool GetFullPath(CFSTR path, FString &fullPath)
    837 {
    838   return GetFullPath(NULL, path, fullPath);
    839 }
    840 
    841 }}}
    842