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