diff options
Diffstat (limited to '')
-rw-r--r-- | CPP/Common/Wildcard.cpp | 790 |
1 files changed, 790 insertions, 0 deletions
diff --git a/CPP/Common/Wildcard.cpp b/CPP/Common/Wildcard.cpp new file mode 100644 index 0000000..861f3f7 --- /dev/null +++ b/CPP/Common/Wildcard.cpp | |||
@@ -0,0 +1,790 @@ | |||
1 | // Common/Wildcard.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #include "Wildcard.h" | ||
6 | |||
7 | extern | ||
8 | bool g_CaseSensitive; | ||
9 | bool g_CaseSensitive = | ||
10 | #ifdef _WIN32 | ||
11 | false; | ||
12 | #elif defined (__APPLE__) | ||
13 | #ifdef TARGET_OS_IPHONE | ||
14 | true; | ||
15 | #else | ||
16 | false; | ||
17 | #endif | ||
18 | #else | ||
19 | true; | ||
20 | #endif | ||
21 | |||
22 | |||
23 | bool IsPath1PrefixedByPath2(const wchar_t *s1, const wchar_t *s2) | ||
24 | { | ||
25 | if (g_CaseSensitive) | ||
26 | return IsString1PrefixedByString2(s1, s2); | ||
27 | return IsString1PrefixedByString2_NoCase(s1, s2); | ||
28 | } | ||
29 | |||
30 | // #include <stdio.h> | ||
31 | |||
32 | /* | ||
33 | static int MyStringCompare_PathLinux(const wchar_t *s1, const wchar_t *s2) throw() | ||
34 | { | ||
35 | for (;;) | ||
36 | { | ||
37 | wchar_t c1 = *s1++; | ||
38 | wchar_t c2 = *s2++; | ||
39 | if (c1 != c2) | ||
40 | { | ||
41 | if (c1 == 0) return -1; | ||
42 | if (c2 == 0) return 1; | ||
43 | if (c1 == '/') c1 = 0; | ||
44 | if (c2 == '/') c2 = 0; | ||
45 | if (c1 < c2) return -1; | ||
46 | if (c1 > c2) return 1; | ||
47 | continue; | ||
48 | } | ||
49 | if (c1 == 0) return 0; | ||
50 | } | ||
51 | } | ||
52 | */ | ||
53 | |||
54 | static int MyStringCompare_Path(const wchar_t *s1, const wchar_t *s2) throw() | ||
55 | { | ||
56 | for (;;) | ||
57 | { | ||
58 | wchar_t c1 = *s1++; | ||
59 | wchar_t c2 = *s2++; | ||
60 | if (c1 != c2) | ||
61 | { | ||
62 | if (c1 == 0) return -1; | ||
63 | if (c2 == 0) return 1; | ||
64 | if (IS_PATH_SEPAR(c1)) c1 = 0; | ||
65 | if (IS_PATH_SEPAR(c2)) c2 = 0; | ||
66 | if (c1 < c2) return -1; | ||
67 | if (c1 > c2) return 1; | ||
68 | continue; | ||
69 | } | ||
70 | if (c1 == 0) return 0; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | static int MyStringCompareNoCase_Path(const wchar_t *s1, const wchar_t *s2) throw() | ||
75 | { | ||
76 | for (;;) | ||
77 | { | ||
78 | wchar_t c1 = *s1++; | ||
79 | wchar_t c2 = *s2++; | ||
80 | if (c1 != c2) | ||
81 | { | ||
82 | if (c1 == 0) return -1; | ||
83 | if (c2 == 0) return 1; | ||
84 | if (IS_PATH_SEPAR(c1)) c1 = 0; | ||
85 | if (IS_PATH_SEPAR(c2)) c2 = 0; | ||
86 | c1 = MyCharUpper(c1); | ||
87 | c2 = MyCharUpper(c2); | ||
88 | if (c1 < c2) return -1; | ||
89 | if (c1 > c2) return 1; | ||
90 | continue; | ||
91 | } | ||
92 | if (c1 == 0) return 0; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | int CompareFileNames(const wchar_t *s1, const wchar_t *s2) STRING_UNICODE_THROW | ||
97 | { | ||
98 | /* | ||
99 | printf("\nCompareFileNames"); | ||
100 | printf("\n S1: %ls", s1); | ||
101 | printf("\n S2: %ls", s2); | ||
102 | printf("\n"); | ||
103 | */ | ||
104 | // 21.07 : we parse PATH_SEPARATOR so: 0 < PATH_SEPARATOR < 1 | ||
105 | if (g_CaseSensitive) | ||
106 | return MyStringCompare_Path(s1, s2); | ||
107 | return MyStringCompareNoCase_Path(s1, s2); | ||
108 | } | ||
109 | |||
110 | #ifndef USE_UNICODE_FSTRING | ||
111 | int CompareFileNames(const char *s1, const char *s2) | ||
112 | { | ||
113 | const UString u1 = fs2us(s1); | ||
114 | const UString u2 = fs2us(s2); | ||
115 | return CompareFileNames(u1, u2); | ||
116 | } | ||
117 | #endif | ||
118 | |||
119 | // ----------------------------------------- | ||
120 | // this function compares name with mask | ||
121 | // ? - any char | ||
122 | // * - any char or empty | ||
123 | |||
124 | static bool EnhancedMaskTest(const wchar_t *mask, const wchar_t *name) | ||
125 | { | ||
126 | for (;;) | ||
127 | { | ||
128 | wchar_t m = *mask; | ||
129 | wchar_t c = *name; | ||
130 | if (m == 0) | ||
131 | return (c == 0); | ||
132 | if (m == '*') | ||
133 | { | ||
134 | if (EnhancedMaskTest(mask + 1, name)) | ||
135 | return true; | ||
136 | if (c == 0) | ||
137 | return false; | ||
138 | } | ||
139 | else | ||
140 | { | ||
141 | if (m == '?') | ||
142 | { | ||
143 | if (c == 0) | ||
144 | return false; | ||
145 | } | ||
146 | else if (m != c) | ||
147 | if (g_CaseSensitive || MyCharUpper(m) != MyCharUpper(c)) | ||
148 | return false; | ||
149 | mask++; | ||
150 | } | ||
151 | name++; | ||
152 | } | ||
153 | } | ||
154 | |||
155 | // -------------------------------------------------- | ||
156 | // Splits path to strings | ||
157 | |||
158 | void SplitPathToParts(const UString &path, UStringVector &pathParts) | ||
159 | { | ||
160 | pathParts.Clear(); | ||
161 | unsigned len = path.Len(); | ||
162 | if (len == 0) | ||
163 | return; | ||
164 | UString name; | ||
165 | unsigned prev = 0; | ||
166 | for (unsigned i = 0; i < len; i++) | ||
167 | if (IsPathSepar(path[i])) | ||
168 | { | ||
169 | name.SetFrom(path.Ptr(prev), i - prev); | ||
170 | pathParts.Add(name); | ||
171 | prev = i + 1; | ||
172 | } | ||
173 | name.SetFrom(path.Ptr(prev), len - prev); | ||
174 | pathParts.Add(name); | ||
175 | } | ||
176 | |||
177 | void SplitPathToParts_2(const UString &path, UString &dirPrefix, UString &name) | ||
178 | { | ||
179 | const wchar_t *start = path; | ||
180 | const wchar_t *p = start + path.Len(); | ||
181 | for (; p != start; p--) | ||
182 | if (IsPathSepar(*(p - 1))) | ||
183 | break; | ||
184 | dirPrefix.SetFrom(path, (unsigned)(p - start)); | ||
185 | name = p; | ||
186 | } | ||
187 | |||
188 | void SplitPathToParts_Smart(const UString &path, UString &dirPrefix, UString &name) | ||
189 | { | ||
190 | const wchar_t *start = path; | ||
191 | const wchar_t *p = start + path.Len(); | ||
192 | if (p != start) | ||
193 | { | ||
194 | if (IsPathSepar(*(p - 1))) | ||
195 | p--; | ||
196 | for (; p != start; p--) | ||
197 | if (IsPathSepar(*(p - 1))) | ||
198 | break; | ||
199 | } | ||
200 | dirPrefix.SetFrom(path, (unsigned)(p - start)); | ||
201 | name = p; | ||
202 | } | ||
203 | |||
204 | /* | ||
205 | UString ExtractDirPrefixFromPath(const UString &path) | ||
206 | { | ||
207 | return path.Left(path.ReverseFind_PathSepar() + 1)); | ||
208 | } | ||
209 | */ | ||
210 | |||
211 | UString ExtractFileNameFromPath(const UString &path) | ||
212 | { | ||
213 | return UString(path.Ptr((unsigned)(path.ReverseFind_PathSepar() + 1))); | ||
214 | } | ||
215 | |||
216 | |||
217 | bool DoesWildcardMatchName(const UString &mask, const UString &name) | ||
218 | { | ||
219 | return EnhancedMaskTest(mask, name); | ||
220 | } | ||
221 | |||
222 | bool DoesNameContainWildcard(const UString &path) | ||
223 | { | ||
224 | for (unsigned i = 0; i < path.Len(); i++) | ||
225 | { | ||
226 | wchar_t c = path[i]; | ||
227 | if (c == '*' || c == '?') | ||
228 | return true; | ||
229 | } | ||
230 | return false; | ||
231 | } | ||
232 | |||
233 | |||
234 | // ----------------------------------------------------------' | ||
235 | // NWildcard | ||
236 | |||
237 | namespace NWildcard { | ||
238 | |||
239 | /* | ||
240 | |||
241 | M = MaskParts.Size(); | ||
242 | N = TestNameParts.Size(); | ||
243 | |||
244 | File Dir | ||
245 | ForFile rec M<=N [N-M, N) - | ||
246 | !ForDir nonrec M=N [0, M) - | ||
247 | |||
248 | ForDir rec M<N [0, M) ... [N-M-1, N-1) same as ForBoth-File | ||
249 | !ForFile nonrec [0, M) same as ForBoth-File | ||
250 | |||
251 | ForFile rec m<=N [0, M) ... [N-M, N) same as ForBoth-File | ||
252 | ForDir nonrec [0, M) same as ForBoth-File | ||
253 | |||
254 | */ | ||
255 | |||
256 | bool CItem::AreAllAllowed() const | ||
257 | { | ||
258 | return ForFile && ForDir && WildcardMatching && PathParts.Size() == 1 && PathParts.Front() == L"*"; | ||
259 | } | ||
260 | |||
261 | bool CItem::CheckPath(const UStringVector &pathParts, bool isFile) const | ||
262 | { | ||
263 | if (!isFile && !ForDir) | ||
264 | return false; | ||
265 | |||
266 | /* | ||
267 | if (PathParts.IsEmpty()) | ||
268 | { | ||
269 | // PathParts.IsEmpty() means all items (universal wildcard) | ||
270 | if (!isFile) | ||
271 | return true; | ||
272 | if (pathParts.Size() <= 1) | ||
273 | return ForFile; | ||
274 | return (ForDir || Recursive && ForFile); | ||
275 | } | ||
276 | */ | ||
277 | |||
278 | int delta = (int)pathParts.Size() - (int)PathParts.Size(); | ||
279 | if (delta < 0) | ||
280 | return false; | ||
281 | int start = 0; | ||
282 | int finish = 0; | ||
283 | |||
284 | if (isFile) | ||
285 | { | ||
286 | if (!ForDir) | ||
287 | { | ||
288 | if (Recursive) | ||
289 | start = delta; | ||
290 | else if (delta !=0) | ||
291 | return false; | ||
292 | } | ||
293 | if (!ForFile && delta == 0) | ||
294 | return false; | ||
295 | } | ||
296 | |||
297 | if (Recursive) | ||
298 | { | ||
299 | finish = delta; | ||
300 | if (isFile && !ForFile) | ||
301 | finish = delta - 1; | ||
302 | } | ||
303 | |||
304 | for (int d = start; d <= finish; d++) | ||
305 | { | ||
306 | unsigned i; | ||
307 | for (i = 0; i < PathParts.Size(); i++) | ||
308 | { | ||
309 | if (WildcardMatching) | ||
310 | { | ||
311 | if (!DoesWildcardMatchName(PathParts[i], pathParts[i + (unsigned)d])) | ||
312 | break; | ||
313 | } | ||
314 | else | ||
315 | { | ||
316 | if (CompareFileNames(PathParts[i], pathParts[i + (unsigned)d]) != 0) | ||
317 | break; | ||
318 | } | ||
319 | } | ||
320 | if (i == PathParts.Size()) | ||
321 | return true; | ||
322 | } | ||
323 | return false; | ||
324 | } | ||
325 | |||
326 | bool CCensorNode::AreAllAllowed() const | ||
327 | { | ||
328 | if (!Name.IsEmpty() || | ||
329 | !SubNodes.IsEmpty() || | ||
330 | !ExcludeItems.IsEmpty() || | ||
331 | IncludeItems.Size() != 1) | ||
332 | return false; | ||
333 | return IncludeItems.Front().AreAllAllowed(); | ||
334 | } | ||
335 | |||
336 | int CCensorNode::FindSubNode(const UString &name) const | ||
337 | { | ||
338 | FOR_VECTOR (i, SubNodes) | ||
339 | if (CompareFileNames(SubNodes[i].Name, name) == 0) | ||
340 | return (int)i; | ||
341 | return -1; | ||
342 | } | ||
343 | |||
344 | void CCensorNode::AddItemSimple(bool include, CItem &item) | ||
345 | { | ||
346 | CObjectVector<CItem> &items = include ? IncludeItems : ExcludeItems; | ||
347 | items.Add(item); | ||
348 | } | ||
349 | |||
350 | void CCensorNode::AddItem(bool include, CItem &item, int ignoreWildcardIndex) | ||
351 | { | ||
352 | if (item.PathParts.Size() <= 1) | ||
353 | { | ||
354 | if (item.PathParts.Size() != 0 && item.WildcardMatching) | ||
355 | { | ||
356 | if (!DoesNameContainWildcard(item.PathParts.Front())) | ||
357 | item.WildcardMatching = false; | ||
358 | } | ||
359 | AddItemSimple(include, item); | ||
360 | return; | ||
361 | } | ||
362 | |||
363 | const UString &front = item.PathParts.Front(); | ||
364 | |||
365 | // WIN32 doesn't support wildcards in file names | ||
366 | if (item.WildcardMatching | ||
367 | && ignoreWildcardIndex != 0 | ||
368 | && DoesNameContainWildcard(front)) | ||
369 | { | ||
370 | AddItemSimple(include, item); | ||
371 | return; | ||
372 | } | ||
373 | CCensorNode &subNode = Find_SubNode_Or_Add_New(front); | ||
374 | item.PathParts.Delete(0); | ||
375 | subNode.AddItem(include, item, ignoreWildcardIndex - 1); | ||
376 | } | ||
377 | |||
378 | /* | ||
379 | void CCensorNode::AddItem(bool include, const UString &path, const CCensorPathProps &props) | ||
380 | { | ||
381 | CItem item; | ||
382 | SplitPathToParts(path, item.PathParts); | ||
383 | item.Recursive = props.Recursive; | ||
384 | item.ForFile = props.ForFile; | ||
385 | item.ForDir = props.ForDir; | ||
386 | item.WildcardMatching = props.WildcardMatching; | ||
387 | AddItem(include, item); | ||
388 | } | ||
389 | */ | ||
390 | |||
391 | bool CCensorNode::NeedCheckSubDirs() const | ||
392 | { | ||
393 | FOR_VECTOR (i, IncludeItems) | ||
394 | { | ||
395 | const CItem &item = IncludeItems[i]; | ||
396 | if (item.Recursive || item.PathParts.Size() > 1) | ||
397 | return true; | ||
398 | } | ||
399 | return false; | ||
400 | } | ||
401 | |||
402 | bool CCensorNode::AreThereIncludeItems() const | ||
403 | { | ||
404 | if (IncludeItems.Size() > 0) | ||
405 | return true; | ||
406 | FOR_VECTOR (i, SubNodes) | ||
407 | if (SubNodes[i].AreThereIncludeItems()) | ||
408 | return true; | ||
409 | return false; | ||
410 | } | ||
411 | |||
412 | bool CCensorNode::CheckPathCurrent(bool include, const UStringVector &pathParts, bool isFile) const | ||
413 | { | ||
414 | const CObjectVector<CItem> &items = include ? IncludeItems : ExcludeItems; | ||
415 | FOR_VECTOR (i, items) | ||
416 | if (items[i].CheckPath(pathParts, isFile)) | ||
417 | return true; | ||
418 | return false; | ||
419 | } | ||
420 | |||
421 | bool CCensorNode::CheckPathVect(const UStringVector &pathParts, bool isFile, bool &include) const | ||
422 | { | ||
423 | if (CheckPathCurrent(false, pathParts, isFile)) | ||
424 | { | ||
425 | include = false; | ||
426 | return true; | ||
427 | } | ||
428 | if (pathParts.Size() > 1) | ||
429 | { | ||
430 | int index = FindSubNode(pathParts.Front()); | ||
431 | if (index >= 0) | ||
432 | { | ||
433 | UStringVector pathParts2 = pathParts; | ||
434 | pathParts2.Delete(0); | ||
435 | if (SubNodes[(unsigned)index].CheckPathVect(pathParts2, isFile, include)) | ||
436 | return true; | ||
437 | } | ||
438 | } | ||
439 | bool finded = CheckPathCurrent(true, pathParts, isFile); | ||
440 | include = finded; // if (!finded), then (true) is allowed also | ||
441 | return finded; | ||
442 | } | ||
443 | |||
444 | /* | ||
445 | bool CCensorNode::CheckPath2(bool isAltStream, const UString &path, bool isFile, bool &include) const | ||
446 | { | ||
447 | UStringVector pathParts; | ||
448 | SplitPathToParts(path, pathParts); | ||
449 | if (CheckPathVect(pathParts, isFile, include)) | ||
450 | { | ||
451 | if (!include || !isAltStream) | ||
452 | return true; | ||
453 | } | ||
454 | if (isAltStream && !pathParts.IsEmpty()) | ||
455 | { | ||
456 | UString &back = pathParts.Back(); | ||
457 | int pos = back.Find(L':'); | ||
458 | if (pos > 0) | ||
459 | { | ||
460 | back.DeleteFrom(pos); | ||
461 | return CheckPathVect(pathParts, isFile, include); | ||
462 | } | ||
463 | } | ||
464 | return false; | ||
465 | } | ||
466 | |||
467 | bool CCensorNode::CheckPath(bool isAltStream, const UString &path, bool isFile) const | ||
468 | { | ||
469 | bool include; | ||
470 | if (CheckPath2(isAltStream, path, isFile, include)) | ||
471 | return include; | ||
472 | return false; | ||
473 | } | ||
474 | */ | ||
475 | |||
476 | bool CCensorNode::CheckPathToRoot_Change(bool include, UStringVector &pathParts, bool isFile) const | ||
477 | { | ||
478 | if (CheckPathCurrent(include, pathParts, isFile)) | ||
479 | return true; | ||
480 | if (!Parent) | ||
481 | return false; | ||
482 | pathParts.Insert(0, Name); | ||
483 | return Parent->CheckPathToRoot_Change(include, pathParts, isFile); | ||
484 | } | ||
485 | |||
486 | bool CCensorNode::CheckPathToRoot(bool include, const UStringVector &pathParts, bool isFile) const | ||
487 | { | ||
488 | if (CheckPathCurrent(include, pathParts, isFile)) | ||
489 | return true; | ||
490 | if (!Parent) | ||
491 | return false; | ||
492 | UStringVector pathParts2; | ||
493 | pathParts2.Add(Name); | ||
494 | pathParts2 += pathParts; | ||
495 | return Parent->CheckPathToRoot_Change(include, pathParts2, isFile); | ||
496 | } | ||
497 | |||
498 | /* | ||
499 | bool CCensorNode::CheckPathToRoot(bool include, const UString &path, bool isFile) const | ||
500 | { | ||
501 | UStringVector pathParts; | ||
502 | SplitPathToParts(path, pathParts); | ||
503 | return CheckPathToRoot(include, pathParts, isFile); | ||
504 | } | ||
505 | */ | ||
506 | |||
507 | void CCensorNode::ExtendExclude(const CCensorNode &fromNodes) | ||
508 | { | ||
509 | ExcludeItems += fromNodes.ExcludeItems; | ||
510 | FOR_VECTOR (i, fromNodes.SubNodes) | ||
511 | { | ||
512 | const CCensorNode &node = fromNodes.SubNodes[i]; | ||
513 | Find_SubNode_Or_Add_New(node.Name).ExtendExclude(node); | ||
514 | } | ||
515 | } | ||
516 | |||
517 | int CCensor::FindPairForPrefix(const UString &prefix) const | ||
518 | { | ||
519 | FOR_VECTOR (i, Pairs) | ||
520 | if (CompareFileNames(Pairs[i].Prefix, prefix) == 0) | ||
521 | return (int)i; | ||
522 | return -1; | ||
523 | } | ||
524 | |||
525 | #ifdef _WIN32 | ||
526 | |||
527 | bool IsDriveColonName(const wchar_t *s) | ||
528 | { | ||
529 | wchar_t c = s[0]; | ||
530 | return c != 0 | ||
531 | && s[1] == ':' | ||
532 | && s[2] == 0 | ||
533 | && ((c >= 'a' && c <= 'z') | ||
534 | || (c >= 'A' && c <= 'Z')); | ||
535 | } | ||
536 | |||
537 | unsigned GetNumPrefixParts_if_DrivePath(UStringVector &pathParts) | ||
538 | { | ||
539 | if (pathParts.IsEmpty()) | ||
540 | return 0; | ||
541 | |||
542 | unsigned testIndex = 0; | ||
543 | if (pathParts[0].IsEmpty()) | ||
544 | { | ||
545 | if (pathParts.Size() < 4 | ||
546 | || !pathParts[1].IsEmpty() | ||
547 | || pathParts[2] != L"?") | ||
548 | return 0; | ||
549 | testIndex = 3; | ||
550 | } | ||
551 | if (NWildcard::IsDriveColonName(pathParts[testIndex])) | ||
552 | return testIndex + 1; | ||
553 | return 0; | ||
554 | } | ||
555 | |||
556 | #endif | ||
557 | |||
558 | static unsigned GetNumPrefixParts(const UStringVector &pathParts) | ||
559 | { | ||
560 | if (pathParts.IsEmpty()) | ||
561 | return 0; | ||
562 | |||
563 | /* empty last part could be removed already from (pathParts), | ||
564 | if there was tail path separator (slash) in original full path string. */ | ||
565 | |||
566 | #ifdef _WIN32 | ||
567 | |||
568 | if (IsDriveColonName(pathParts[0])) | ||
569 | return 1; | ||
570 | if (!pathParts[0].IsEmpty()) | ||
571 | return 0; | ||
572 | |||
573 | if (pathParts.Size() == 1) | ||
574 | return 1; | ||
575 | if (!pathParts[1].IsEmpty()) | ||
576 | return 1; | ||
577 | if (pathParts.Size() == 2) | ||
578 | return 2; | ||
579 | if (pathParts[2] == L".") | ||
580 | return 3; | ||
581 | |||
582 | unsigned networkParts = 2; | ||
583 | if (pathParts[2] == L"?") | ||
584 | { | ||
585 | if (pathParts.Size() == 3) | ||
586 | return 3; | ||
587 | if (IsDriveColonName(pathParts[3])) | ||
588 | return 4; | ||
589 | if (!pathParts[3].IsEqualTo_Ascii_NoCase("UNC")) | ||
590 | return 3; | ||
591 | networkParts = 4; | ||
592 | } | ||
593 | |||
594 | networkParts += | ||
595 | // 2; // server/share | ||
596 | 1; // server | ||
597 | if (pathParts.Size() <= networkParts) | ||
598 | return pathParts.Size(); | ||
599 | return networkParts; | ||
600 | |||
601 | #else | ||
602 | |||
603 | return pathParts[0].IsEmpty() ? 1 : 0; | ||
604 | |||
605 | #endif | ||
606 | } | ||
607 | |||
608 | void CCensor::AddItem(ECensorPathMode pathMode, bool include, const UString &path, | ||
609 | const CCensorPathProps &props) | ||
610 | { | ||
611 | if (path.IsEmpty()) | ||
612 | throw "Empty file path"; | ||
613 | |||
614 | UStringVector pathParts; | ||
615 | SplitPathToParts(path, pathParts); | ||
616 | |||
617 | CCensorPathProps props2 = props; | ||
618 | |||
619 | bool forFile = true; | ||
620 | bool forDir = true; | ||
621 | const UString &back = pathParts.Back(); | ||
622 | if (back.IsEmpty()) | ||
623 | { | ||
624 | // we have tail path separator. So it's directory. | ||
625 | // we delete tail path separator here even for "\" and "c:\" | ||
626 | forFile = false; | ||
627 | pathParts.DeleteBack(); | ||
628 | } | ||
629 | else | ||
630 | { | ||
631 | if (props.MarkMode == kMark_StrictFile | ||
632 | || (props.MarkMode == kMark_StrictFile_IfWildcard | ||
633 | && DoesNameContainWildcard(back))) | ||
634 | forDir = false; | ||
635 | } | ||
636 | |||
637 | |||
638 | UString prefix; | ||
639 | |||
640 | int ignoreWildcardIndex = -1; | ||
641 | |||
642 | // #ifdef _WIN32 | ||
643 | // we ignore "?" wildcard in "\\?\" prefix. | ||
644 | if (pathParts.Size() >= 3 | ||
645 | && pathParts[0].IsEmpty() | ||
646 | && pathParts[1].IsEmpty() | ||
647 | && pathParts[2] == L"?") | ||
648 | ignoreWildcardIndex = 2; | ||
649 | // #endif | ||
650 | |||
651 | if (pathMode != k_AbsPath) | ||
652 | { | ||
653 | // detection of the number of Skip Parts for prefix | ||
654 | ignoreWildcardIndex = -1; | ||
655 | |||
656 | const unsigned numPrefixParts = GetNumPrefixParts(pathParts); | ||
657 | unsigned numSkipParts = numPrefixParts; | ||
658 | |||
659 | if (pathMode != k_FullPath) | ||
660 | { | ||
661 | // if absolute path, then all parts before last part will be in prefix | ||
662 | if (numPrefixParts != 0 && pathParts.Size() > numPrefixParts) | ||
663 | numSkipParts = pathParts.Size() - 1; | ||
664 | } | ||
665 | { | ||
666 | int dotsIndex = -1; | ||
667 | for (unsigned i = numPrefixParts; i < pathParts.Size(); i++) | ||
668 | { | ||
669 | const UString &part = pathParts[i]; | ||
670 | if (part == L".." || part == L".") | ||
671 | dotsIndex = (int)i; | ||
672 | } | ||
673 | |||
674 | if (dotsIndex >= 0) | ||
675 | { | ||
676 | if (dotsIndex == (int)pathParts.Size() - 1) | ||
677 | numSkipParts = pathParts.Size(); | ||
678 | else | ||
679 | numSkipParts = pathParts.Size() - 1; | ||
680 | } | ||
681 | } | ||
682 | |||
683 | // we split (pathParts) to (prefix) and (pathParts). | ||
684 | for (unsigned i = 0; i < numSkipParts; i++) | ||
685 | { | ||
686 | { | ||
687 | const UString &front = pathParts.Front(); | ||
688 | // WIN32 doesn't support wildcards in file names | ||
689 | if (props.WildcardMatching) | ||
690 | if (i >= numPrefixParts && DoesNameContainWildcard(front)) | ||
691 | break; | ||
692 | prefix += front; | ||
693 | prefix.Add_PathSepar(); | ||
694 | } | ||
695 | pathParts.Delete(0); | ||
696 | } | ||
697 | } | ||
698 | |||
699 | int index = FindPairForPrefix(prefix); | ||
700 | if (index < 0) | ||
701 | { | ||
702 | index = (int)Pairs.Size(); | ||
703 | Pairs.AddNew().Prefix = prefix; | ||
704 | } | ||
705 | |||
706 | if (pathMode != k_AbsPath) | ||
707 | { | ||
708 | if (pathParts.IsEmpty() || (pathParts.Size() == 1 && pathParts[0].IsEmpty())) | ||
709 | { | ||
710 | // we create universal item, if we skip all parts as prefix (like \ or L:\ ) | ||
711 | pathParts.Clear(); | ||
712 | pathParts.Add(UString("*")); | ||
713 | forFile = true; | ||
714 | forDir = true; | ||
715 | props2.WildcardMatching = true; | ||
716 | props2.Recursive = false; | ||
717 | } | ||
718 | } | ||
719 | |||
720 | /* | ||
721 | // not possible now | ||
722 | if (!forDir && !forFile) | ||
723 | { | ||
724 | UString s ("file path was blocked for files and directories: "); | ||
725 | s += path; | ||
726 | throw s; | ||
727 | // return; // for debug : ignore item (don't create Item) | ||
728 | } | ||
729 | */ | ||
730 | |||
731 | CItem item; | ||
732 | item.PathParts = pathParts; | ||
733 | item.ForDir = forDir; | ||
734 | item.ForFile = forFile; | ||
735 | item.Recursive = props2.Recursive; | ||
736 | item.WildcardMatching = props2.WildcardMatching; | ||
737 | Pairs[(unsigned)index].Head.AddItem(include, item, ignoreWildcardIndex); | ||
738 | } | ||
739 | |||
740 | /* | ||
741 | bool CCensor::CheckPath(bool isAltStream, const UString &path, bool isFile) const | ||
742 | { | ||
743 | bool finded = false; | ||
744 | FOR_VECTOR (i, Pairs) | ||
745 | { | ||
746 | bool include; | ||
747 | if (Pairs[i].Head.CheckPath2(isAltStream, path, isFile, include)) | ||
748 | { | ||
749 | if (!include) | ||
750 | return false; | ||
751 | finded = true; | ||
752 | } | ||
753 | } | ||
754 | return finded; | ||
755 | } | ||
756 | */ | ||
757 | |||
758 | void CCensor::ExtendExclude() | ||
759 | { | ||
760 | unsigned i; | ||
761 | for (i = 0; i < Pairs.Size(); i++) | ||
762 | if (Pairs[i].Prefix.IsEmpty()) | ||
763 | break; | ||
764 | if (i == Pairs.Size()) | ||
765 | return; | ||
766 | unsigned index = i; | ||
767 | for (i = 0; i < Pairs.Size(); i++) | ||
768 | if (index != i) | ||
769 | Pairs[i].Head.ExtendExclude(Pairs[index].Head); | ||
770 | } | ||
771 | |||
772 | void CCensor::AddPathsToCensor(ECensorPathMode censorPathMode) | ||
773 | { | ||
774 | FOR_VECTOR(i, CensorPaths) | ||
775 | { | ||
776 | const CCensorPath &cp = CensorPaths[i]; | ||
777 | AddItem(censorPathMode, cp.Include, cp.Path, cp.Props); | ||
778 | } | ||
779 | CensorPaths.Clear(); | ||
780 | } | ||
781 | |||
782 | void CCensor::AddPreItem(bool include, const UString &path, const CCensorPathProps &props) | ||
783 | { | ||
784 | CCensorPath &cp = CensorPaths.AddNew(); | ||
785 | cp.Path = path; | ||
786 | cp.Include = include; | ||
787 | cp.Props = props; | ||
788 | } | ||
789 | |||
790 | } | ||