Source code
Revision control
Copy as Markdown
Other Tools
// Common/Wildcard.cpp↩
↩
#include "StdAfx.h"↩
↩
#include "Wildcard.h"↩
↩
bool g_CaseSensitive =↩
#ifdef _WIN32↩
false;↩
#else↩
true;↩
#endif↩
↩
↩
bool IsPath1PrefixedByPath2(const wchar_t *s1, const wchar_t *s2)↩
{↩
if (g_CaseSensitive)↩
return IsString1PrefixedByString2(s1, s2);↩
return IsString1PrefixedByString2_NoCase(s1, s2);↩
}↩
↩
int CompareFileNames(const wchar_t *s1, const wchar_t *s2) STRING_UNICODE_THROW↩
{↩
if (g_CaseSensitive)↩
return MyStringCompare(s1, s2);↩
return MyStringCompareNoCase(s1, s2);↩
}↩
↩
#ifndef USE_UNICODE_FSTRING↩
int CompareFileNames(const char *s1, const char *s2)↩
{↩
const UString u1 = fs2us(s1);↩
const UString u2 = fs2us(s2);↩
if (g_CaseSensitive)↩
return MyStringCompare(u1, u2);↩
return MyStringCompareNoCase(u1, u2);↩
}↩
#endif↩
↩
// -----------------------------------------↩
// this function compares name with mask↩
// ? - any char↩
// * - any char or empty↩
↩
static bool EnhancedMaskTest(const wchar_t *mask, const wchar_t *name)↩
{↩
for (;;)↩
{↩
wchar_t m = *mask;↩
wchar_t c = *name;↩
if (m == 0)↩
return (c == 0);↩
if (m == '*')↩
{↩
if (EnhancedMaskTest(mask + 1, name))↩
return true;↩
if (c == 0)↩
return false;↩
}↩
else↩
{↩
if (m == '?')↩
{↩
if (c == 0)↩
return false;↩
}↩
else if (m != c)↩
if (g_CaseSensitive || MyCharUpper(m) != MyCharUpper(c))↩
return false;↩
mask++;↩
}↩
name++;↩
}↩
}↩
↩
// --------------------------------------------------↩
// Splits path to strings↩
↩
void SplitPathToParts(const UString &path, UStringVector &pathParts)↩
{↩
pathParts.Clear();↩
unsigned len = path.Len();↩
if (len == 0)↩
return;↩
UString name;↩
unsigned prev = 0;↩
for (unsigned i = 0; i < len; i++)↩
if (IsPathSepar(path[i]))↩
{↩
name.SetFrom(path.Ptr(prev), i - prev);↩
pathParts.Add(name);↩
prev = i + 1;↩
}↩
name.SetFrom(path.Ptr(prev), len - prev);↩
pathParts.Add(name);↩
}↩
↩
void SplitPathToParts_2(const UString &path, UString &dirPrefix, UString &name)↩
{↩
const wchar_t *start = path;↩
const wchar_t *p = start + path.Len();↩
for (; p != start; p--)↩
if (IsPathSepar(*(p - 1)))↩
break;↩
dirPrefix.SetFrom(path, (unsigned)(p - start));↩
name = p;↩
}↩
↩
void SplitPathToParts_Smart(const UString &path, UString &dirPrefix, UString &name)↩
{↩
const wchar_t *start = path;↩
const wchar_t *p = start + path.Len();↩
if (p != start)↩
{↩
if (IsPathSepar(*(p - 1)))↩
p--;↩
for (; p != start; p--)↩
if (IsPathSepar(*(p - 1)))↩
break;↩
}↩
dirPrefix.SetFrom(path, (unsigned)(p - start));↩
name = p;↩
}↩
↩
/*↩
UString ExtractDirPrefixFromPath(const UString &path)↩
{↩
return path.Left(path.ReverseFind_PathSepar() + 1));↩
}↩
*/↩
↩
UString ExtractFileNameFromPath(const UString &path)↩
{↩
return UString(path.Ptr(path.ReverseFind_PathSepar() + 1));↩
}↩
↩
↩
bool DoesWildcardMatchName(const UString &mask, const UString &name)↩
{↩
return EnhancedMaskTest(mask, name);↩
}↩
↩
bool DoesNameContainWildcard(const UString &path)↩
{↩
for (unsigned i = 0; i < path.Len(); i++)↩
{↩
wchar_t c = path[i];↩
if (c == '*' || c == '?')↩
return true;↩
}↩
return false;↩
}↩
↩
↩
// ----------------------------------------------------------'↩
// NWildcard↩
↩
namespace NWildcard {↩
↩
/*↩
↩
M = MaskParts.Size();↩
N = TestNameParts.Size();↩
↩
File Dir↩
ForFile rec M<=N [N-M, N) -↩
!ForDir nonrec M=N [0, M) -↩
↩
ForDir rec M<N [0, M) ... [N-M-1, N-1) same as ForBoth-File↩
!ForFile nonrec [0, M) same as ForBoth-File↩
↩
ForFile rec m<=N [0, M) ... [N-M, N) same as ForBoth-File↩
ForDir nonrec [0, M) same as ForBoth-File↩
↩
*/↩
↩
bool CItem::AreAllAllowed() const↩
{↩
return ForFile && ForDir && WildcardMatching && PathParts.Size() == 1 && PathParts.Front() == L"*";↩
}↩
↩
bool CItem::CheckPath(const UStringVector &pathParts, bool isFile) const↩
{↩
if (!isFile && !ForDir)↩
return false;↩
↩
/*↩
if (PathParts.IsEmpty())↩
{↩
// PathParts.IsEmpty() means all items (universal wildcard)↩
if (!isFile)↩
return true;↩
if (pathParts.Size() <= 1)↩
return ForFile;↩
return (ForDir || Recursive && ForFile);↩
}↩
*/↩
↩
int delta = (int)pathParts.Size() - (int)PathParts.Size();↩
if (delta < 0)↩
return false;↩
int start = 0;↩
int finish = 0;↩
↩
if (isFile)↩
{↩
if (!ForDir)↩
{↩
if (Recursive)↩
start = delta;↩
else if (delta !=0)↩
return false;↩
}↩
if (!ForFile && delta == 0)↩
return false;↩
}↩
↩
if (Recursive)↩
{↩
finish = delta;↩
if (isFile && !ForFile)↩
finish = delta - 1;↩
}↩
↩
for (int d = start; d <= finish; d++)↩
{↩
unsigned i;↩
for (i = 0; i < PathParts.Size(); i++)↩
{↩
if (WildcardMatching)↩
{↩
if (!DoesWildcardMatchName(PathParts[i], pathParts[i + d]))↩
break;↩
}↩
else↩
{↩
if (CompareFileNames(PathParts[i], pathParts[i + d]) != 0)↩
break;↩
}↩
}↩
if (i == PathParts.Size())↩
return true;↩
}↩
return false;↩
}↩
↩
bool CCensorNode::AreAllAllowed() const↩
{↩
if (!Name.IsEmpty() ||↩
!SubNodes.IsEmpty() ||↩
!ExcludeItems.IsEmpty() ||↩
IncludeItems.Size() != 1)↩
return false;↩
return IncludeItems.Front().AreAllAllowed();↩
}↩
↩
int CCensorNode::FindSubNode(const UString &name) const↩
{↩
FOR_VECTOR (i, SubNodes)↩
if (CompareFileNames(SubNodes[i].Name, name) == 0)↩
return i;↩
return -1;↩
}↩
↩
void CCensorNode::AddItemSimple(bool include, CItem &item)↩
{↩
if (include)↩
IncludeItems.Add(item);↩
else↩
ExcludeItems.Add(item);↩
}↩
↩
void CCensorNode::AddItem(bool include, CItem &item, int ignoreWildcardIndex)↩
{↩
if (item.PathParts.Size() <= 1)↩
{↩
if (item.PathParts.Size() != 0 && item.WildcardMatching)↩
{↩
if (!DoesNameContainWildcard(item.PathParts.Front()))↩
item.WildcardMatching = false;↩
}↩
AddItemSimple(include, item);↩
return;↩
}↩
const UString &front = item.PathParts.Front();↩
↩
// WIN32 doesn't support wildcards in file names↩
if (item.WildcardMatching↩
&& ignoreWildcardIndex != 0↩
&& DoesNameContainWildcard(front))↩
{↩
AddItemSimple(include, item);↩
return;↩
}↩
int index = FindSubNode(front);↩
if (index < 0)↩
index = SubNodes.Add(CCensorNode(front, this));↩
item.PathParts.Delete(0);↩
SubNodes[index].AddItem(include, item, ignoreWildcardIndex - 1);↩
}↩
↩
void CCensorNode::AddItem(bool include, const UString &path, bool recursive, bool forFile, bool forDir, bool wildcardMatching)↩
{↩
CItem item;↩
SplitPathToParts(path, item.PathParts);↩
item.Recursive = recursive;↩
item.ForFile = forFile;↩
item.ForDir = forDir;↩
item.WildcardMatching = wildcardMatching;↩
AddItem(include, item);↩
}↩
↩
bool CCensorNode::NeedCheckSubDirs() const↩
{↩
FOR_VECTOR (i, IncludeItems)↩
{↩
const CItem &item = IncludeItems[i];↩
if (item.Recursive || item.PathParts.Size() > 1)↩
return true;↩
}↩
return false;↩
}↩
↩
bool CCensorNode::AreThereIncludeItems() const↩
{↩
if (IncludeItems.Size() > 0)↩
return true;↩
FOR_VECTOR (i, SubNodes)↩
if (SubNodes[i].AreThereIncludeItems())↩
return true;↩
return false;↩
}↩
↩
bool CCensorNode::CheckPathCurrent(bool include, const UStringVector &pathParts, bool isFile) const↩
{↩
const CObjectVector<CItem> &items = include ? IncludeItems : ExcludeItems;↩
FOR_VECTOR (i, items)↩
if (items[i].CheckPath(pathParts, isFile))↩
return true;↩
return false;↩
}↩
↩
bool CCensorNode::CheckPathVect(const UStringVector &pathParts, bool isFile, bool &include) const↩
{↩
if (CheckPathCurrent(false, pathParts, isFile))↩
{↩
include = false;↩
return true;↩
}↩
include = true;↩
bool finded = CheckPathCurrent(true, pathParts, isFile);↩
if (pathParts.Size() <= 1)↩
return finded;↩
int index = FindSubNode(pathParts.Front());↩
if (index >= 0)↩
{↩
UStringVector pathParts2 = pathParts;↩
pathParts2.Delete(0);↩
if (SubNodes[index].CheckPathVect(pathParts2, isFile, include))↩
return true;↩
}↩
return finded;↩
}↩
↩
/*↩
bool CCensorNode::CheckPath2(bool isAltStream, const UString &path, bool isFile, bool &include) const↩
{↩
UStringVector pathParts;↩
SplitPathToParts(path, pathParts);↩
if (CheckPathVect(pathParts, isFile, include))↩
{↩
if (!include || !isAltStream)↩
return true;↩
}↩
if (isAltStream && !pathParts.IsEmpty())↩
{↩
UString &back = pathParts.Back();↩
int pos = back.Find(L':');↩
if (pos > 0)↩
{↩
back.DeleteFrom(pos);↩
return CheckPathVect(pathParts, isFile, include);↩
}↩
}↩
return false;↩
}↩
↩
bool CCensorNode::CheckPath(bool isAltStream, const UString &path, bool isFile) const↩
{↩
bool include;↩
if (CheckPath2(isAltStream, path, isFile, include))↩
return include;↩
return false;↩
}↩
*/↩
↩
bool CCensorNode::CheckPathToRoot(bool include, UStringVector &pathParts, bool isFile) const↩
{↩
if (CheckPathCurrent(include, pathParts, isFile))↩
return true;↩
if (Parent == 0)↩
return false;↩
pathParts.Insert(0, Name);↩
return Parent->CheckPathToRoot(include, pathParts, isFile);↩
}↩
↩
/*↩
bool CCensorNode::CheckPathToRoot(bool include, const UString &path, bool isFile) const↩
{↩
UStringVector pathParts;↩
SplitPathToParts(path, pathParts);↩
return CheckPathToRoot(include, pathParts, isFile);↩
}↩
*/↩
↩
void CCensorNode::AddItem2(bool include, const UString &path, bool recursive, bool wildcardMatching)↩
{↩
if (path.IsEmpty())↩
return;↩
bool forFile = true;↩
bool forFolder = true;↩
UString path2 (path);↩
if (IsPathSepar(path.Back()))↩
{↩
path2.DeleteBack();↩
forFile = false;↩
}↩
AddItem(include, path2, recursive, forFile, forFolder, wildcardMatching);↩
}↩
↩
void CCensorNode::ExtendExclude(const CCensorNode &fromNodes)↩
{↩
ExcludeItems += fromNodes.ExcludeItems;↩
FOR_VECTOR (i, fromNodes.SubNodes)↩
{↩
const CCensorNode &node = fromNodes.SubNodes[i];↩
int subNodeIndex = FindSubNode(node.Name);↩
if (subNodeIndex < 0)↩
subNodeIndex = SubNodes.Add(CCensorNode(node.Name, this));↩
SubNodes[subNodeIndex].ExtendExclude(node);↩
}↩
}↩
↩
int CCensor::FindPrefix(const UString &prefix) const↩
{↩
FOR_VECTOR (i, Pairs)↩
if (CompareFileNames(Pairs[i].Prefix, prefix) == 0)↩
return i;↩
return -1;↩
}↩
↩
#ifdef _WIN32↩
↩
bool IsDriveColonName(const wchar_t *s)↩
{↩
wchar_t c = s[0];↩
return c != 0 && s[1] == ':' && s[2] == 0 && (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z');↩
}↩
↩
unsigned GetNumPrefixParts_if_DrivePath(UStringVector &pathParts)↩
{↩
if (pathParts.IsEmpty())↩
return 0;↩
↩
unsigned testIndex = 0;↩
if (pathParts[0].IsEmpty())↩
{↩
if (pathParts.Size() < 4↩
|| !pathParts[1].IsEmpty()↩
|| pathParts[2] != L"?")↩
return 0;↩
testIndex = 3;↩
}↩
if (NWildcard::IsDriveColonName(pathParts[testIndex]))↩
return testIndex + 1;↩
return 0;↩
}↩
↩
#endif↩
↩
static unsigned GetNumPrefixParts(const UStringVector &pathParts)↩
{↩
if (pathParts.IsEmpty())↩
return 0;↩
↩
#ifdef _WIN32↩
↩
if (IsDriveColonName(pathParts[0]))↩
return 1;↩
if (!pathParts[0].IsEmpty())↩
return 0;↩
↩
if (pathParts.Size() == 1)↩
return 1;↩
if (!pathParts[1].IsEmpty())↩
return 1;↩
if (pathParts.Size() == 2)↩
return 2;↩
if (pathParts[2] == L".")↩
return 3;↩
↩
unsigned networkParts = 2;↩
if (pathParts[2] == L"?")↩
{↩
if (pathParts.Size() == 3)↩
return 3;↩
if (IsDriveColonName(pathParts[3]))↩
return 4;↩
if (!pathParts[3].IsEqualTo_Ascii_NoCase("UNC"))↩
return 3;↩
networkParts = 4;↩
}↩
↩
networkParts +=↩
// 2; // server/share↩
1; // server↩
if (pathParts.Size() <= networkParts)↩
return pathParts.Size();↩
return networkParts;↩
↩
#else↩
↩
return pathParts[0].IsEmpty() ? 1 : 0;↩
↩
#endif↩
}↩
↩
void CCensor::AddItem(ECensorPathMode pathMode, bool include, const UString &path, bool recursive, bool wildcardMatching)↩
{↩
if (path.IsEmpty())↩
throw "Empty file path";↩
↩
UStringVector pathParts;↩
SplitPathToParts(path, pathParts);↩
↩
bool forFile = true;↩
if (pathParts.Back().IsEmpty())↩
{↩
forFile = false;↩
pathParts.DeleteBack();↩
}↩
↩
UString prefix;↩
↩
int ignoreWildcardIndex = -1;↩
↩
// #ifdef _WIN32↩
// we ignore "?" wildcard in "\\?\" prefix.↩
if (pathParts.Size() >= 3↩
&& pathParts[0].IsEmpty()↩
&& pathParts[1].IsEmpty()↩
&& pathParts[2] == L"?")↩
ignoreWildcardIndex = 2;↩
// #endif↩
↩
if (pathMode != k_AbsPath)↩
{↩
ignoreWildcardIndex = -1;↩
↩
const unsigned numPrefixParts = GetNumPrefixParts(pathParts);↩
unsigned numSkipParts = numPrefixParts;↩
↩
if (pathMode != k_FullPath)↩
{↩
if (numPrefixParts != 0 && pathParts.Size() > numPrefixParts)↩
numSkipParts = pathParts.Size() - 1;↩
}↩
{↩
int dotsIndex = -1;↩
for (unsigned i = numPrefixParts; i < pathParts.Size(); i++)↩
{↩
const UString &part = pathParts[i];↩
if (part == L".." || part == L".")↩
dotsIndex = i;↩
}↩
↩
if (dotsIndex >= 0)↩
if (dotsIndex == (int)pathParts.Size() - 1)↩
numSkipParts = pathParts.Size();↩
else↩
numSkipParts = pathParts.Size() - 1;↩
}↩
↩
for (unsigned i = 0; i < numSkipParts; i++)↩
{↩
{↩
const UString &front = pathParts.Front();↩
// WIN32 doesn't support wildcards in file names↩
if (wildcardMatching)↩
if (i >= numPrefixParts && DoesNameContainWildcard(front))↩
break;↩
prefix += front;↩
prefix.Add_PathSepar();↩
}↩
pathParts.Delete(0);↩
}↩
}↩
↩
int index = FindPrefix(prefix);↩
if (index < 0)↩
index = Pairs.Add(CPair(prefix));↩
↩
if (pathMode != k_AbsPath)↩
{↩
if (pathParts.IsEmpty() || pathParts.Size() == 1 && pathParts[0].IsEmpty())↩
{↩
// we create universal item, if we skip all parts as prefix (like \ or L:\ )↩
pathParts.Clear();↩
pathParts.Add(UString("*"));↩
forFile = true;↩
wildcardMatching = true;↩
recursive = false;↩
}↩
}↩
↩
CItem item;↩
item.PathParts = pathParts;↩
item.ForDir = true;↩
item.ForFile = forFile;↩
item.Recursive = recursive;↩
item.WildcardMatching = wildcardMatching;↩
Pairs[index].Head.AddItem(include, item, ignoreWildcardIndex);↩
}↩
↩
/*↩
bool CCensor::CheckPath(bool isAltStream, const UString &path, bool isFile) const↩
{↩
bool finded = false;↩
FOR_VECTOR (i, Pairs)↩
{↩
bool include;↩
if (Pairs[i].Head.CheckPath2(isAltStream, path, isFile, include))↩
{↩
if (!include)↩
return false;↩
finded = true;↩
}↩
}↩
return finded;↩
}↩
*/↩
↩
void CCensor::ExtendExclude()↩
{↩
unsigned i;↩
for (i = 0; i < Pairs.Size(); i++)↩
if (Pairs[i].Prefix.IsEmpty())↩
break;↩
if (i == Pairs.Size())↩
return;↩
unsigned index = i;↩
for (i = 0; i < Pairs.Size(); i++)↩
if (index != i)↩
Pairs[i].Head.ExtendExclude(Pairs[index].Head);↩
}↩
↩
void CCensor::AddPathsToCensor(ECensorPathMode censorPathMode)↩
{↩
FOR_VECTOR(i, CensorPaths)↩
{↩
const CCensorPath &cp = CensorPaths[i];↩
AddItem(censorPathMode, cp.Include, cp.Path, cp.Recursive, cp.WildcardMatching);↩
}↩
CensorPaths.Clear();↩
}↩
↩
void CCensor::AddPreItem(bool include, const UString &path, bool recursive, bool wildcardMatching)↩
{↩
CCensorPath &cp = CensorPaths.AddNew();↩
cp.Path = path;↩
cp.Include = include;↩
cp.Recursive = recursive;↩
cp.WildcardMatching = wildcardMatching;↩
}↩
↩
}↩