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