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
IsPath1PrefixedByPath2(const wchar_t * s1,const wchar_t * s2)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
MyStringCompare_Path(const wchar_t * s1,const wchar_t * s2)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
MyStringCompareNoCase_Path(const wchar_t * s1,const wchar_t * s2)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
CompareFileNames(const wchar_t * s1,const wchar_t * s2)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
CompareFileNames(const char * s1,const char * s2)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
EnhancedMaskTest(const wchar_t * mask,const wchar_t * name)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
SplitPathToParts(const UString & path,UStringVector & pathParts)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
SplitPathToParts_2(const UString & path,UString & dirPrefix,UString & name)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
SplitPathToParts_Smart(const UString & path,UString & dirPrefix,UString & name)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
ExtractFileNameFromPath(const UString & path)211 UString ExtractFileNameFromPath(const UString &path)
212 {
213 return UString(path.Ptr((unsigned)(path.ReverseFind_PathSepar() + 1)));
214 }
215
216
DoesWildcardMatchName(const UString & mask,const UString & name)217 bool DoesWildcardMatchName(const UString &mask, const UString &name)
218 {
219 return EnhancedMaskTest(mask, name);
220 }
221
DoesNameContainWildcard(const UString & path)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
AreAllAllowed() const256 bool CItem::AreAllAllowed() const
257 {
258 return ForFile && ForDir && WildcardMatching && PathParts.Size() == 1 && PathParts.Front() == L"*";
259 }
260
CheckPath(const UStringVector & pathParts,bool isFile) const261 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
AreAllAllowed() const326 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
FindSubNode(const UString & name) const336 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
AddItemSimple(bool include,CItem & item)344 void CCensorNode::AddItemSimple(bool include, CItem &item)
345 {
346 CObjectVector<CItem> &items = include ? IncludeItems : ExcludeItems;
347 items.Add(item);
348 }
349
AddItem(bool include,CItem & item,int ignoreWildcardIndex)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
NeedCheckSubDirs() const391 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
AreThereIncludeItems() const402 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
CheckPathCurrent(bool include,const UStringVector & pathParts,bool isFile) const412 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
CheckPathVect(const UStringVector & pathParts,bool isFile,bool & include) const421 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
CheckPathToRoot_Change(bool include,UStringVector & pathParts,bool isFile) const476 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
CheckPathToRoot(bool include,const UStringVector & pathParts,bool isFile) const486 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
ExtendExclude(const CCensorNode & fromNodes)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
FindPairForPrefix(const UString & prefix) const517 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
IsDriveColonName(const wchar_t * s)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
GetNumPrefixParts_if_DrivePath(UStringVector & pathParts)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
GetNumPrefixParts(const UStringVector & pathParts)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
AddItem(ECensorPathMode pathMode,bool include,const UString & path,const CCensorPathProps & props)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
ExtendExclude()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
AddPathsToCensor(ECensorPathMode censorPathMode)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
AddPreItem(bool include,const UString & path,const CCensorPathProps & props)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 }
791