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