rlm@1
|
1 // Common/Wildcard.cpp
|
rlm@1
|
2
|
rlm@1
|
3 #include "StdAfx.h"
|
rlm@1
|
4
|
rlm@1
|
5 #include "Wildcard.h"
|
rlm@1
|
6
|
rlm@1
|
7 bool g_CaseSensitive =
|
rlm@1
|
8 #ifdef _WIN32
|
rlm@1
|
9 false;
|
rlm@1
|
10 #else
|
rlm@1
|
11 true;
|
rlm@1
|
12 #endif
|
rlm@1
|
13
|
rlm@1
|
14 static const wchar_t kAnyCharsChar = L'*';
|
rlm@1
|
15 static const wchar_t kAnyCharChar = L'?';
|
rlm@1
|
16
|
rlm@1
|
17 #ifdef _WIN32
|
rlm@1
|
18 static const wchar_t kDirDelimiter1 = L'\\';
|
rlm@1
|
19 #endif
|
rlm@1
|
20 static const wchar_t kDirDelimiter2 = L'/';
|
rlm@1
|
21
|
rlm@1
|
22 static const UString kWildCardCharSet = L"?*";
|
rlm@1
|
23
|
rlm@1
|
24 static const UString kIllegalWildCardFileNameChars=
|
rlm@1
|
25 L"\x1\x2\x3\x4\x5\x6\x7\x8\x9\xA\xB\xC\xD\xE\xF"
|
rlm@1
|
26 L"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
|
rlm@1
|
27 L"\"/:<>\\|";
|
rlm@1
|
28
|
rlm@1
|
29
|
rlm@1
|
30 static inline bool IsCharDirLimiter(wchar_t c)
|
rlm@1
|
31 {
|
rlm@1
|
32 return (
|
rlm@1
|
33 #ifdef _WIN32
|
rlm@1
|
34 c == kDirDelimiter1 ||
|
rlm@1
|
35 #endif
|
rlm@1
|
36 c == kDirDelimiter2);
|
rlm@1
|
37 }
|
rlm@1
|
38
|
rlm@1
|
39 int CompareFileNames(const UString &s1, const UString &s2)
|
rlm@1
|
40 {
|
rlm@1
|
41 if (g_CaseSensitive)
|
rlm@1
|
42 return s1.Compare(s2);
|
rlm@1
|
43 return s1.CompareNoCase(s2);
|
rlm@1
|
44 }
|
rlm@1
|
45
|
rlm@1
|
46 // -----------------------------------------
|
rlm@1
|
47 // this function compares name with mask
|
rlm@1
|
48 // ? - any char
|
rlm@1
|
49 // * - any char or empty
|
rlm@1
|
50
|
rlm@1
|
51 static bool EnhancedMaskTest(const wchar_t *mask, const wchar_t *name)
|
rlm@1
|
52 {
|
rlm@1
|
53 for (;;)
|
rlm@1
|
54 {
|
rlm@1
|
55 wchar_t m = *mask;
|
rlm@1
|
56 wchar_t c = *name;
|
rlm@1
|
57 if (m == 0)
|
rlm@1
|
58 return (c == 0);
|
rlm@1
|
59 if (m == kAnyCharsChar)
|
rlm@1
|
60 {
|
rlm@1
|
61 if (EnhancedMaskTest(mask + 1, name))
|
rlm@1
|
62 return true;
|
rlm@1
|
63 if (c == 0)
|
rlm@1
|
64 return false;
|
rlm@1
|
65 }
|
rlm@1
|
66 else
|
rlm@1
|
67 {
|
rlm@1
|
68 if (m == kAnyCharChar)
|
rlm@1
|
69 {
|
rlm@1
|
70 if (c == 0)
|
rlm@1
|
71 return false;
|
rlm@1
|
72 }
|
rlm@1
|
73 else if (m != c)
|
rlm@1
|
74 if (g_CaseSensitive || MyCharUpper(m) != MyCharUpper(c))
|
rlm@1
|
75 return false;
|
rlm@1
|
76 mask++;
|
rlm@1
|
77 }
|
rlm@1
|
78 name++;
|
rlm@1
|
79 }
|
rlm@1
|
80 }
|
rlm@1
|
81
|
rlm@1
|
82 // --------------------------------------------------
|
rlm@1
|
83 // Splits path to strings
|
rlm@1
|
84
|
rlm@1
|
85 void SplitPathToParts(const UString &path, UStringVector &pathParts)
|
rlm@1
|
86 {
|
rlm@1
|
87 pathParts.Clear();
|
rlm@1
|
88 UString name;
|
rlm@1
|
89 int len = path.Length();
|
rlm@1
|
90 if (len == 0)
|
rlm@1
|
91 return;
|
rlm@1
|
92 for (int i = 0; i < len; i++)
|
rlm@1
|
93 {
|
rlm@1
|
94 wchar_t c = path[i];
|
rlm@1
|
95 if (IsCharDirLimiter(c))
|
rlm@1
|
96 {
|
rlm@1
|
97 pathParts.Add(name);
|
rlm@1
|
98 name.Empty();
|
rlm@1
|
99 }
|
rlm@1
|
100 else
|
rlm@1
|
101 name += c;
|
rlm@1
|
102 }
|
rlm@1
|
103 pathParts.Add(name);
|
rlm@1
|
104 }
|
rlm@1
|
105
|
rlm@1
|
106 void SplitPathToParts(const UString &path, UString &dirPrefix, UString &name)
|
rlm@1
|
107 {
|
rlm@1
|
108 int i;
|
rlm@1
|
109 for (i = path.Length() - 1; i >= 0; i--)
|
rlm@1
|
110 if (IsCharDirLimiter(path[i]))
|
rlm@1
|
111 break;
|
rlm@1
|
112 dirPrefix = path.Left(i + 1);
|
rlm@1
|
113 name = path.Mid(i + 1);
|
rlm@1
|
114 }
|
rlm@1
|
115
|
rlm@1
|
116 UString ExtractDirPrefixFromPath(const UString &path)
|
rlm@1
|
117 {
|
rlm@1
|
118 int i;
|
rlm@1
|
119 for (i = path.Length() - 1; i >= 0; i--)
|
rlm@1
|
120 if (IsCharDirLimiter(path[i]))
|
rlm@1
|
121 break;
|
rlm@1
|
122 return path.Left(i + 1);
|
rlm@1
|
123 }
|
rlm@1
|
124
|
rlm@1
|
125 UString ExtractFileNameFromPath(const UString &path)
|
rlm@1
|
126 {
|
rlm@1
|
127 int i;
|
rlm@1
|
128 for (i = path.Length() - 1; i >= 0; i--)
|
rlm@1
|
129 if (IsCharDirLimiter(path[i]))
|
rlm@1
|
130 break;
|
rlm@1
|
131 return path.Mid(i + 1);
|
rlm@1
|
132 }
|
rlm@1
|
133
|
rlm@1
|
134
|
rlm@1
|
135 bool CompareWildCardWithName(const UString &mask, const UString &name)
|
rlm@1
|
136 {
|
rlm@1
|
137 return EnhancedMaskTest(mask, name);
|
rlm@1
|
138 }
|
rlm@1
|
139
|
rlm@1
|
140 bool DoesNameContainWildCard(const UString &path)
|
rlm@1
|
141 {
|
rlm@1
|
142 return (path.FindOneOf(kWildCardCharSet) >= 0);
|
rlm@1
|
143 }
|
rlm@1
|
144
|
rlm@1
|
145
|
rlm@1
|
146 // ----------------------------------------------------------'
|
rlm@1
|
147 // NWildcard
|
rlm@1
|
148
|
rlm@1
|
149 namespace NWildcard {
|
rlm@1
|
150
|
rlm@1
|
151
|
rlm@1
|
152 /*
|
rlm@1
|
153 M = MaskParts.Size();
|
rlm@1
|
154 N = TestNameParts.Size();
|
rlm@1
|
155
|
rlm@1
|
156 File Dir
|
rlm@1
|
157 ForFile req M<=N [N-M, N) -
|
rlm@1
|
158 nonreq M=N [0, M) -
|
rlm@1
|
159
|
rlm@1
|
160 ForDir req M<N [0, M) ... [N-M-1, N-1) same as ForBoth-File
|
rlm@1
|
161 nonreq [0, M) same as ForBoth-File
|
rlm@1
|
162
|
rlm@1
|
163 ForBoth req m<=N [0, M) ... [N-M, N) same as ForBoth-File
|
rlm@1
|
164 nonreq [0, M) same as ForBoth-File
|
rlm@1
|
165
|
rlm@1
|
166 */
|
rlm@1
|
167
|
rlm@1
|
168 bool CItem::CheckPath(const UStringVector &pathParts, bool isFile) const
|
rlm@1
|
169 {
|
rlm@1
|
170 if (!isFile && !ForDir)
|
rlm@1
|
171 return false;
|
rlm@1
|
172 int delta = (int)pathParts.Size() - (int)PathParts.Size();
|
rlm@1
|
173 if (delta < 0)
|
rlm@1
|
174 return false;
|
rlm@1
|
175 int start = 0;
|
rlm@1
|
176 int finish = 0;
|
rlm@1
|
177 if (isFile)
|
rlm@1
|
178 {
|
rlm@1
|
179 if (!ForDir && !Recursive && delta !=0)
|
rlm@1
|
180 return false;
|
rlm@1
|
181 if (!ForFile && delta == 0)
|
rlm@1
|
182 return false;
|
rlm@1
|
183 if (!ForDir && Recursive)
|
rlm@1
|
184 start = delta;
|
rlm@1
|
185 }
|
rlm@1
|
186 if (Recursive)
|
rlm@1
|
187 {
|
rlm@1
|
188 finish = delta;
|
rlm@1
|
189 if (isFile && !ForFile)
|
rlm@1
|
190 finish = delta - 1;
|
rlm@1
|
191 }
|
rlm@1
|
192 for (int d = start; d <= finish; d++)
|
rlm@1
|
193 {
|
rlm@1
|
194 int i;
|
rlm@1
|
195 for (i = 0; i < PathParts.Size(); i++)
|
rlm@1
|
196 if (!CompareWildCardWithName(PathParts[i], pathParts[i + d]))
|
rlm@1
|
197 break;
|
rlm@1
|
198 if (i == PathParts.Size())
|
rlm@1
|
199 return true;
|
rlm@1
|
200 }
|
rlm@1
|
201 return false;
|
rlm@1
|
202 }
|
rlm@1
|
203
|
rlm@1
|
204 int CCensorNode::FindSubNode(const UString &name) const
|
rlm@1
|
205 {
|
rlm@1
|
206 for (int i = 0; i < SubNodes.Size(); i++)
|
rlm@1
|
207 if (CompareFileNames(SubNodes[i].Name, name) == 0)
|
rlm@1
|
208 return i;
|
rlm@1
|
209 return -1;
|
rlm@1
|
210 }
|
rlm@1
|
211
|
rlm@1
|
212 void CCensorNode::AddItemSimple(bool include, CItem &item)
|
rlm@1
|
213 {
|
rlm@1
|
214 if (include)
|
rlm@1
|
215 IncludeItems.Add(item);
|
rlm@1
|
216 else
|
rlm@1
|
217 ExcludeItems.Add(item);
|
rlm@1
|
218 }
|
rlm@1
|
219
|
rlm@1
|
220 void CCensorNode::AddItem(bool include, CItem &item)
|
rlm@1
|
221 {
|
rlm@1
|
222 if (item.PathParts.Size() <= 1)
|
rlm@1
|
223 {
|
rlm@1
|
224 AddItemSimple(include, item);
|
rlm@1
|
225 return;
|
rlm@1
|
226 }
|
rlm@1
|
227 const UString &front = item.PathParts.Front();
|
rlm@1
|
228 if (DoesNameContainWildCard(front))
|
rlm@1
|
229 {
|
rlm@1
|
230 AddItemSimple(include, item);
|
rlm@1
|
231 return;
|
rlm@1
|
232 }
|
rlm@1
|
233 int index = FindSubNode(front);
|
rlm@1
|
234 if (index < 0)
|
rlm@1
|
235 index = SubNodes.Add(CCensorNode(front, this));
|
rlm@1
|
236 item.PathParts.Delete(0);
|
rlm@1
|
237 SubNodes[index].AddItem(include, item);
|
rlm@1
|
238 }
|
rlm@1
|
239
|
rlm@1
|
240 void CCensorNode::AddItem(bool include, const UString &path, bool recursive, bool forFile, bool forDir)
|
rlm@1
|
241 {
|
rlm@1
|
242 CItem item;
|
rlm@1
|
243 SplitPathToParts(path, item.PathParts);
|
rlm@1
|
244 item.Recursive = recursive;
|
rlm@1
|
245 item.ForFile = forFile;
|
rlm@1
|
246 item.ForDir = forDir;
|
rlm@1
|
247 AddItem(include, item);
|
rlm@1
|
248 }
|
rlm@1
|
249
|
rlm@1
|
250 bool CCensorNode::NeedCheckSubDirs() const
|
rlm@1
|
251 {
|
rlm@1
|
252 for (int i = 0; i < IncludeItems.Size(); i++)
|
rlm@1
|
253 {
|
rlm@1
|
254 const CItem &item = IncludeItems[i];
|
rlm@1
|
255 if (item.Recursive || item.PathParts.Size() > 1)
|
rlm@1
|
256 return true;
|
rlm@1
|
257 }
|
rlm@1
|
258 return false;
|
rlm@1
|
259 }
|
rlm@1
|
260
|
rlm@1
|
261 bool CCensorNode::AreThereIncludeItems() const
|
rlm@1
|
262 {
|
rlm@1
|
263 if (IncludeItems.Size() > 0)
|
rlm@1
|
264 return true;
|
rlm@1
|
265 for (int i = 0; i < SubNodes.Size(); i++)
|
rlm@1
|
266 if (SubNodes[i].AreThereIncludeItems())
|
rlm@1
|
267 return true;
|
rlm@1
|
268 return false;
|
rlm@1
|
269 }
|
rlm@1
|
270
|
rlm@1
|
271 bool CCensorNode::CheckPathCurrent(bool include, const UStringVector &pathParts, bool isFile) const
|
rlm@1
|
272 {
|
rlm@1
|
273 const CObjectVector<CItem> &items = include ? IncludeItems : ExcludeItems;
|
rlm@1
|
274 for (int i = 0; i < items.Size(); i++)
|
rlm@1
|
275 if (items[i].CheckPath(pathParts, isFile))
|
rlm@1
|
276 return true;
|
rlm@1
|
277 return false;
|
rlm@1
|
278 }
|
rlm@1
|
279
|
rlm@1
|
280 bool CCensorNode::CheckPath(UStringVector &pathParts, bool isFile, bool &include) const
|
rlm@1
|
281 {
|
rlm@1
|
282 if (CheckPathCurrent(false, pathParts, isFile))
|
rlm@1
|
283 {
|
rlm@1
|
284 include = false;
|
rlm@1
|
285 return true;
|
rlm@1
|
286 }
|
rlm@1
|
287 include = true;
|
rlm@1
|
288 bool finded = CheckPathCurrent(true, pathParts, isFile);
|
rlm@1
|
289 if (pathParts.Size() == 1)
|
rlm@1
|
290 return finded;
|
rlm@1
|
291 int index = FindSubNode(pathParts.Front());
|
rlm@1
|
292 if (index >= 0)
|
rlm@1
|
293 {
|
rlm@1
|
294 UStringVector pathParts2 = pathParts;
|
rlm@1
|
295 pathParts2.Delete(0);
|
rlm@1
|
296 if (SubNodes[index].CheckPath(pathParts2, isFile, include))
|
rlm@1
|
297 return true;
|
rlm@1
|
298 }
|
rlm@1
|
299 return finded;
|
rlm@1
|
300 }
|
rlm@1
|
301
|
rlm@1
|
302 bool CCensorNode::CheckPath(const UString &path, bool isFile, bool &include) const
|
rlm@1
|
303 {
|
rlm@1
|
304 UStringVector pathParts;
|
rlm@1
|
305 SplitPathToParts(path, pathParts);
|
rlm@1
|
306 return CheckPath(pathParts, isFile, include);
|
rlm@1
|
307 }
|
rlm@1
|
308
|
rlm@1
|
309 bool CCensorNode::CheckPath(const UString &path, bool isFile) const
|
rlm@1
|
310 {
|
rlm@1
|
311 bool include;
|
rlm@1
|
312 if (CheckPath(path, isFile, include))
|
rlm@1
|
313 return include;
|
rlm@1
|
314 return false;
|
rlm@1
|
315 }
|
rlm@1
|
316
|
rlm@1
|
317 bool CCensorNode::CheckPathToRoot(bool include, UStringVector &pathParts, bool isFile) const
|
rlm@1
|
318 {
|
rlm@1
|
319 if (CheckPathCurrent(include, pathParts, isFile))
|
rlm@1
|
320 return true;
|
rlm@1
|
321 if (Parent == 0)
|
rlm@1
|
322 return false;
|
rlm@1
|
323 pathParts.Insert(0, Name);
|
rlm@1
|
324 return Parent->CheckPathToRoot(include, pathParts, isFile);
|
rlm@1
|
325 }
|
rlm@1
|
326
|
rlm@1
|
327 /*
|
rlm@1
|
328 bool CCensorNode::CheckPathToRoot(bool include, const UString &path, bool isFile) const
|
rlm@1
|
329 {
|
rlm@1
|
330 UStringVector pathParts;
|
rlm@1
|
331 SplitPathToParts(path, pathParts);
|
rlm@1
|
332 return CheckPathToRoot(include, pathParts, isFile);
|
rlm@1
|
333 }
|
rlm@1
|
334 */
|
rlm@1
|
335
|
rlm@1
|
336 void CCensorNode::AddItem2(bool include, const UString &path, bool recursive)
|
rlm@1
|
337 {
|
rlm@1
|
338 if (path.IsEmpty())
|
rlm@1
|
339 return;
|
rlm@1
|
340 bool forFile = true;
|
rlm@1
|
341 bool forFolder = true;
|
rlm@1
|
342 UString path2 = path;
|
rlm@1
|
343 if (IsCharDirLimiter(path[path.Length() - 1]))
|
rlm@1
|
344 {
|
rlm@1
|
345 path2.Delete(path.Length() - 1);
|
rlm@1
|
346 forFile = false;
|
rlm@1
|
347 }
|
rlm@1
|
348 AddItem(include, path2, recursive, forFile, forFolder);
|
rlm@1
|
349 }
|
rlm@1
|
350
|
rlm@1
|
351 void CCensorNode::ExtendExclude(const CCensorNode &fromNodes)
|
rlm@1
|
352 {
|
rlm@1
|
353 ExcludeItems += fromNodes.ExcludeItems;
|
rlm@1
|
354 for (int i = 0; i < fromNodes.SubNodes.Size(); i++)
|
rlm@1
|
355 {
|
rlm@1
|
356 const CCensorNode &node = fromNodes.SubNodes[i];
|
rlm@1
|
357 int subNodeIndex = FindSubNode(node.Name);
|
rlm@1
|
358 if (subNodeIndex < 0)
|
rlm@1
|
359 subNodeIndex = SubNodes.Add(CCensorNode(node.Name, this));
|
rlm@1
|
360 SubNodes[subNodeIndex].ExtendExclude(node);
|
rlm@1
|
361 }
|
rlm@1
|
362 }
|
rlm@1
|
363
|
rlm@1
|
364 int CCensor::FindPrefix(const UString &prefix) const
|
rlm@1
|
365 {
|
rlm@1
|
366 for (int i = 0; i < Pairs.Size(); i++)
|
rlm@1
|
367 if (CompareFileNames(Pairs[i].Prefix, prefix) == 0)
|
rlm@1
|
368 return i;
|
rlm@1
|
369 return -1;
|
rlm@1
|
370 }
|
rlm@1
|
371
|
rlm@1
|
372 void CCensor::AddItem(bool include, const UString &path, bool recursive)
|
rlm@1
|
373 {
|
rlm@1
|
374 UStringVector pathParts;
|
rlm@1
|
375 SplitPathToParts(path, pathParts);
|
rlm@1
|
376 bool forFile = true;
|
rlm@1
|
377 if (pathParts.Back().IsEmpty())
|
rlm@1
|
378 {
|
rlm@1
|
379 forFile = false;
|
rlm@1
|
380 pathParts.DeleteBack();
|
rlm@1
|
381 }
|
rlm@1
|
382 const UString &front = pathParts.Front();
|
rlm@1
|
383 bool isAbs = false;
|
rlm@1
|
384 if (front.IsEmpty())
|
rlm@1
|
385 isAbs = true;
|
rlm@1
|
386 else if (front.Length() == 2 && front[1] == L':')
|
rlm@1
|
387 isAbs = true;
|
rlm@1
|
388 else
|
rlm@1
|
389 {
|
rlm@1
|
390 for (int i = 0; i < pathParts.Size(); i++)
|
rlm@1
|
391 {
|
rlm@1
|
392 const UString &part = pathParts[i];
|
rlm@1
|
393 if (part == L".." || part == L".")
|
rlm@1
|
394 {
|
rlm@1
|
395 isAbs = true;
|
rlm@1
|
396 break;
|
rlm@1
|
397 }
|
rlm@1
|
398 }
|
rlm@1
|
399 }
|
rlm@1
|
400 int numAbsParts = 0;
|
rlm@1
|
401 if (isAbs)
|
rlm@1
|
402 if (pathParts.Size() > 1)
|
rlm@1
|
403 numAbsParts = pathParts.Size() - 1;
|
rlm@1
|
404 else
|
rlm@1
|
405 numAbsParts = 1;
|
rlm@1
|
406 UString prefix;
|
rlm@1
|
407 for (int i = 0; i < numAbsParts; i++)
|
rlm@1
|
408 {
|
rlm@1
|
409 const UString &front = pathParts.Front();
|
rlm@1
|
410 if (DoesNameContainWildCard(front))
|
rlm@1
|
411 break;
|
rlm@1
|
412 prefix += front;
|
rlm@1
|
413 prefix += WCHAR_PATH_SEPARATOR;
|
rlm@1
|
414 pathParts.Delete(0);
|
rlm@1
|
415 }
|
rlm@1
|
416 int index = FindPrefix(prefix);
|
rlm@1
|
417 if (index < 0)
|
rlm@1
|
418 index = Pairs.Add(CPair(prefix));
|
rlm@1
|
419
|
rlm@1
|
420 CItem item;
|
rlm@1
|
421 item.PathParts = pathParts;
|
rlm@1
|
422 item.ForDir = true;
|
rlm@1
|
423 item.ForFile = forFile;
|
rlm@1
|
424 item.Recursive = recursive;
|
rlm@1
|
425 Pairs[index].Head.AddItem(include, item);
|
rlm@1
|
426 }
|
rlm@1
|
427
|
rlm@1
|
428 bool CCensor::CheckPath(const UString &path, bool isFile) const
|
rlm@1
|
429 {
|
rlm@1
|
430 bool finded = false;
|
rlm@1
|
431 for (int i = 0; i < Pairs.Size(); i++)
|
rlm@1
|
432 {
|
rlm@1
|
433 bool include;
|
rlm@1
|
434 if (Pairs[i].Head.CheckPath(path, isFile, include))
|
rlm@1
|
435 {
|
rlm@1
|
436 if (!include)
|
rlm@1
|
437 return false;
|
rlm@1
|
438 finded = true;
|
rlm@1
|
439 }
|
rlm@1
|
440 }
|
rlm@1
|
441 return finded;
|
rlm@1
|
442 }
|
rlm@1
|
443
|
rlm@1
|
444 void CCensor::ExtendExclude()
|
rlm@1
|
445 {
|
rlm@1
|
446 int i;
|
rlm@1
|
447 for (i = 0; i < Pairs.Size(); i++)
|
rlm@1
|
448 if (Pairs[i].Prefix.IsEmpty())
|
rlm@1
|
449 break;
|
rlm@1
|
450 if (i == Pairs.Size())
|
rlm@1
|
451 return;
|
rlm@1
|
452 int index = i;
|
rlm@1
|
453 for (i = 0; i < Pairs.Size(); i++)
|
rlm@1
|
454 if (index != i)
|
rlm@1
|
455 Pairs[i].Head.ExtendExclude(Pairs[index].Head);
|
rlm@1
|
456 }
|
rlm@1
|
457
|
rlm@1
|
458 }
|