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