• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ReplaceIncorrectChars(UString & s)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 
Correct_AltStream_Name(UString & s)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 
IsSupportedName(const UString & name)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 
CorrectUnsupportedName(UString & name)104 static void CorrectUnsupportedName(UString &name)
105 {
106   if (!IsSupportedName(name))
107     name.InsertAtFront(L'_');
108 }
109 
110 #endif
111 
Correct_PathPart(UString & s)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 
Get_Correct_FsFile_Name(const UString & name)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 
Correct_FsPath(bool absIsAllowed,UStringVector & parts,bool isDir)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 
MakePathFromParts(const UStringVector & parts)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