Home | History | Annotate | Download | only in Common
      1 // ExtractingFilePath.cpp
      2 
      3 #include "StdAfx.h"
      4 
      5 #include "../../../Common/Wildcard.h"
      6 
      7 #include "../../../Windows/FileName.h"
      8 
      9 #include "ExtractingFilePath.h"
     10 
     11 static void ReplaceIncorrectChars(UString &s)
     12 {
     13   {
     14     for (unsigned i = 0; i < s.Len(); i++)
     15     {
     16       wchar_t c = s[i];
     17       if (
     18           #ifdef _WIN32
     19           c == ':' || c == '*' || c == '?' || c < 0x20 || c == '<' || c == '>' || c == '|' || c == '"'
     20           || c == '/'
     21           // || c == 0x202E // RLO
     22           ||
     23           #endif
     24           c == WCHAR_PATH_SEPARATOR)
     25         s.ReplaceOneCharAtPos(i, '_');
     26     }
     27   }
     28 
     29   #ifdef _WIN32
     30   {
     31     for (unsigned i = s.Len(); i != 0;)
     32     {
     33       wchar_t c = s[--i];
     34       if (c != '.' && c != ' ')
     35         break;
     36       s.ReplaceOneCharAtPos(i, '_');
     37     }
     38   }
     39   #endif
     40 }
     41 
     42 #ifdef _WIN32
     43 
     44 /* WinXP-64 doesn't support ':', '\\' and '/' symbols in name of alt stream.
     45    But colon in postfix ":$DATA" is allowed.
     46    WIN32 functions don't allow empty alt stream name "name:" */
     47 
     48 void Correct_AltStream_Name(UString &s)
     49 {
     50   unsigned len = s.Len();
     51   const unsigned kPostfixSize = 6;
     52   if (s.Len() >= kPostfixSize
     53       && StringsAreEqualNoCase_Ascii(s.RightPtr(kPostfixSize), ":$DATA"))
     54     len -= kPostfixSize;
     55   for (unsigned i = 0; i < len; i++)
     56   {
     57     wchar_t c = s[i];
     58     if (c == ':' || c == '\\' || c == '/'
     59         || c == 0x202E // RLO
     60         )
     61       s.ReplaceOneCharAtPos(i, '_');
     62   }
     63   if (s.IsEmpty())
     64     s = L'_';
     65 }
     66 
     67 static const unsigned g_ReservedWithNum_Index = 4;
     68 
     69 static const char * const g_ReservedNames[] =
     70 {
     71   "CON", "PRN", "AUX", "NUL",
     72   "COM", "LPT"
     73 };
     74 
     75 static bool IsSupportedName(const UString &name)
     76 {
     77   for (unsigned i = 0; i < ARRAY_SIZE(g_ReservedNames); i++)
     78   {
     79     const char *reservedName = g_ReservedNames[i];
     80     unsigned len = MyStringLen(reservedName);
     81     if (name.Len() < len)
     82       continue;
     83     if (!name.IsPrefixedBy_Ascii_NoCase(reservedName))
     84       continue;
     85     if (i >= g_ReservedWithNum_Index)
     86     {
     87       wchar_t c = name[len];
     88       if (c < L'0' || c > L'9')
     89         continue;
     90       len++;
     91     }
     92     for (;;)
     93     {
     94       wchar_t c = name[len++];
     95       if (c == 0 || c == '.')
     96         return false;
     97       if (c != ' ')
     98         break;
     99     }
    100   }
    101   return true;
    102 }
    103 
    104 static void CorrectUnsupportedName(UString &name)
    105 {
    106   if (!IsSupportedName(name))
    107     name.InsertAtFront(L'_');
    108 }
    109 
    110 #endif
    111 
    112 static void Correct_PathPart(UString &s)
    113 {
    114   // "." and ".."
    115   if (s[0] == '.' && (s[1] == 0 || s[1] == '.' && s[2] == 0))
    116     s.Empty();
    117   #ifdef _WIN32
    118   else
    119     ReplaceIncorrectChars(s);
    120   #endif
    121 }
    122 
    123 // static const wchar_t *k_EmptyReplaceName = L"[]";
    124 static const wchar_t k_EmptyReplaceName = L'_';
    125 
    126 UString Get_Correct_FsFile_Name(const UString &name)
    127 {
    128   UString res = name;
    129   Correct_PathPart(res);
    130 
    131   #ifdef _WIN32
    132   CorrectUnsupportedName(res);
    133   #endif
    134 
    135   if (res.IsEmpty())
    136     res = k_EmptyReplaceName;
    137   return res;
    138 }
    139 
    140 
    141 void Correct_FsPath(bool absIsAllowed, UStringVector &parts, bool isDir)
    142 {
    143   unsigned i = 0;
    144 
    145   if (absIsAllowed)
    146   {
    147     #if defined(_WIN32) && !defined(UNDER_CE)
    148     bool isDrive = false;
    149     #endif
    150     if (parts[0].IsEmpty())
    151     {
    152       i = 1;
    153       #if defined(_WIN32) && !defined(UNDER_CE)
    154       if (parts.Size() > 1 && parts[1].IsEmpty())
    155       {
    156         i = 2;
    157         if (parts.Size() > 2 && parts[2] == L"?")
    158         {
    159           i = 3;
    160           if (parts.Size() > 3  && NWindows::NFile::NName::IsDrivePath2(parts[3]))
    161           {
    162             isDrive = true;
    163             i = 4;
    164           }
    165         }
    166       }
    167       #endif
    168     }
    169     #if defined(_WIN32) && !defined(UNDER_CE)
    170     else if (NWindows::NFile::NName::IsDrivePath2(parts[0]))
    171     {
    172       isDrive = true;
    173       i = 1;
    174     }
    175 
    176     if (isDrive)
    177     {
    178       // we convert "c:name" to "c:\name", if absIsAllowed path.
    179       const UString &ds = parts[i - 1];
    180       if (ds.Len() != 2)
    181       {
    182         UString s = ds.Ptr(2);
    183         parts.Insert(i, s);
    184       }
    185     }
    186     #endif
    187   }
    188 
    189   for (; i < parts.Size();)
    190   {
    191     UString &s = parts[i];
    192 
    193     Correct_PathPart(s);
    194 
    195     if (s.IsEmpty())
    196     {
    197       if (isDir || i != parts.Size() - 1)
    198       {
    199         parts.Delete(i);
    200         continue;
    201       }
    202       s = k_EmptyReplaceName;
    203     }
    204     else
    205     {
    206       #ifdef _WIN32
    207       CorrectUnsupportedName(s);
    208       #endif
    209     }
    210 
    211     i++;
    212   }
    213 
    214   if (!isDir)
    215   {
    216     if (parts.IsEmpty())
    217       parts.Add(k_EmptyReplaceName);
    218     else
    219     {
    220       UString &s = parts.Back();
    221       if (s.IsEmpty())
    222         s = k_EmptyReplaceName;
    223     }
    224   }
    225 }
    226 
    227 UString MakePathFromParts(const UStringVector &parts)
    228 {
    229   UString s;
    230   FOR_VECTOR (i, parts)
    231   {
    232     if (i != 0)
    233       s.Add_PathSepar();
    234     s += parts[i];
    235   }
    236   return s;
    237 }
    238