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(const UString & s,bool repaceColon)11 static UString ReplaceIncorrectChars(const UString &s, bool repaceColon)
12 {
13 #ifdef _WIN32
14 UString res;
15 bool beforeColon = true;
16 {
17 for (unsigned i = 0; i < s.Len(); i++)
18 {
19 wchar_t c = s[i];
20 if (beforeColon)
21 if (c == '*' || c == '?' || c < 0x20 || c == '<' || c == '>' || c == '|' || c == '"')
22 c = '_';
23 if (c == ':')
24 {
25 if (repaceColon)
26 c = '_';
27 else
28 beforeColon = false;
29 }
30 res += c;
31 }
32 }
33 if (beforeColon)
34 {
35 for (int i = res.Len() - 1; i >= 0; i--)
36 {
37 wchar_t c = res[i];
38 if (c != '.' && c != ' ')
39 break;
40 res.ReplaceOneCharAtPos(i, '_');
41 }
42 }
43 return res;
44 #else
45 return s;
46 #endif
47 }
48
49 #ifdef _WIN32
50
51 static const wchar_t *g_ReservedNames[] =
52 {
53 L"CON", L"PRN", L"AUX", L"NUL"
54 };
55
CheckTail(const UString & name,unsigned len)56 static bool CheckTail(const UString &name, unsigned len)
57 {
58 int dotPos = name.Find(L'.');
59 if (dotPos < 0)
60 dotPos = name.Len();
61 UString s = name.Left(dotPos);
62 s.TrimRight();
63 return s.Len() != len;
64 }
65
CheckNameNum(const UString & name,const wchar_t * reservedName)66 static bool CheckNameNum(const UString &name, const wchar_t *reservedName)
67 {
68 unsigned len = MyStringLen(reservedName);
69 if (name.Len() <= len)
70 return true;
71 if (MyStringCompareNoCase_N(name, reservedName, len) != 0)
72 return true;
73 wchar_t c = name[len];
74 if (c < L'0' || c > L'9')
75 return true;
76 return CheckTail(name, len + 1);
77 }
78
IsSupportedName(const UString & name)79 static bool IsSupportedName(const UString &name)
80 {
81 for (unsigned i = 0; i < ARRAY_SIZE(g_ReservedNames); i++)
82 {
83 const wchar_t *reservedName = g_ReservedNames[i];
84 unsigned len = MyStringLen(reservedName);
85 if (name.Len() < len)
86 continue;
87 if (MyStringCompareNoCase_N(name, reservedName, len) != 0)
88 continue;
89 if (!CheckTail(name, len))
90 return false;
91 }
92 if (!CheckNameNum(name, L"COM"))
93 return false;
94 return CheckNameNum(name, L"LPT");
95 }
96
97 #endif
98
GetCorrectFileName(const UString & path,bool repaceColon)99 static UString GetCorrectFileName(const UString &path, bool repaceColon)
100 {
101 if (path == L".." || path == L".")
102 return UString();
103 return ReplaceIncorrectChars(path, repaceColon);
104 }
105
MakeCorrectPath(bool isPathFromRoot,UStringVector & pathParts,bool replaceAltStreamColon)106 void MakeCorrectPath(bool isPathFromRoot, UStringVector &pathParts, bool replaceAltStreamColon)
107 {
108 for (unsigned i = 0; i < pathParts.Size();)
109 {
110 UString &s = pathParts[i];
111 #ifdef _WIN32
112 bool needReplaceColon = (replaceAltStreamColon || i != pathParts.Size() - 1);
113 if (i == 0 && isPathFromRoot && NWindows::NFile::NName::IsDrivePath(s))
114 {
115 UString s2 = s[0];
116 s2 += L'_';
117 s2 += GetCorrectFileName(s.Ptr(2), needReplaceColon);
118 s = s2;
119 }
120 else
121 s = GetCorrectFileName(s, needReplaceColon);
122 #endif
123
124 if (s.IsEmpty())
125 pathParts.Delete(i);
126 else
127 {
128 #ifdef _WIN32
129 if (!IsSupportedName(s))
130 s = (UString)L"_" + s;
131 #endif
132 i++;
133 }
134 }
135 }
136
MakePathNameFromParts(const UStringVector & parts)137 UString MakePathNameFromParts(const UStringVector &parts)
138 {
139 UString result;
140 FOR_VECTOR (i, parts)
141 {
142 if (i != 0)
143 result += WCHAR_PATH_SEPARATOR;
144 result += parts[i];
145 }
146 return result;
147 }
148
149 static const wchar_t *k_EmptyReplaceName = L"[]";
150
Correct_IfEmptyLastPart(UStringVector & parts)151 void Correct_IfEmptyLastPart(UStringVector &parts)
152 {
153 if (parts.IsEmpty())
154 parts.Add(k_EmptyReplaceName);
155 else
156 {
157 UString &s = parts.Back();
158 if (s.IsEmpty())
159 s = k_EmptyReplaceName;
160 }
161 }
162
GetCorrectFsPath(const UString & path)163 UString GetCorrectFsPath(const UString &path)
164 {
165 UString res = GetCorrectFileName(path, true);
166 #ifdef _WIN32
167 if (!IsSupportedName(res))
168 res = (UString)L"_" + res;
169 #endif
170 if (res.IsEmpty())
171 res = k_EmptyReplaceName;
172 return res;
173 }
174
GetCorrectFullFsPath(const UString & path)175 UString GetCorrectFullFsPath(const UString &path)
176 {
177 UStringVector parts;
178 SplitPathToParts(path, parts);
179 FOR_VECTOR (i, parts)
180 {
181 UString &s = parts[i];
182 #ifdef _WIN32
183 while (!s.IsEmpty() && (s.Back() == '.' || s.Back() == ' '))
184 s.DeleteBack();
185 if (!IsSupportedName(s))
186 s.InsertAtFront(L'_');
187 #endif
188 }
189 return MakePathNameFromParts(parts);
190 }
191