This commit is contained in:
Igor Pavlov
2014-11-23 00:00:00 +00:00
committed by Kornel Lesiński
parent 83f8ddcc5b
commit f08f4dcc3c
1158 changed files with 76451 additions and 35082 deletions

401
CPP/Common/Wildcard.cpp Executable file → Normal file
View File

@@ -2,8 +2,6 @@
#include "StdAfx.h"
#include "../../C/Types.h"
#include "Wildcard.h"
bool g_CaseSensitive =
@@ -13,38 +11,44 @@ bool g_CaseSensitive =
true;
#endif
static const wchar_t kAnyCharsChar = L'*';
static const wchar_t kAnyCharChar = L'?';
#ifdef _WIN32
static const wchar_t kDirDelimiter1 = L'\\';
#endif
static const wchar_t kDirDelimiter2 = L'/';
static const UString kWildCardCharSet = L"?*";
static const UString kIllegalWildCardFileNameChars=
L"\x1\x2\x3\x4\x5\x6\x7\x8\x9\xA\xB\xC\xD\xE\xF"
L"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
L"\"/:<>\\|";
static inline bool IsCharDirLimiter(wchar_t c)
{
return (
#ifdef _WIN32
c == kDirDelimiter1 ||
#endif
c == kDirDelimiter2);
}
int CompareFileNames(const UString &s1, const UString &s2)
bool IsPath1PrefixedByPath2(const wchar_t *s1, const wchar_t *s2)
{
if (g_CaseSensitive)
return s1.Compare(s2);
return s1.CompareNoCase(s2);
{
for (;;)
{
wchar_t c2 = *s2++; if (c2 == 0) return true;
wchar_t c1 = *s1++;
if (MyCharUpper(c1) !=
MyCharUpper(c2))
return false;
}
}
for (;;)
{
wchar_t c2 = *s2++; if (c2 == 0) return true;
wchar_t c1 = *s1++; if (c1 != c2) return false;
}
}
int CompareFileNames(const wchar_t *s1, const wchar_t *s2)
{
if (g_CaseSensitive)
return wcscmp(s1, s2);
return MyStringCompareNoCase(s1, s2);
}
#ifndef USE_UNICODE_FSTRING
int CompareFileNames(const char *s1, const char *s2)
{
if (g_CaseSensitive)
return wcscmp(fs2us(s1), fs2us(s2));
return MyStringCompareNoCase(fs2us(s1), fs2us(s2));
}
#endif
// -----------------------------------------
// this function compares name with mask
// ? - any char
@@ -58,7 +62,7 @@ static bool EnhancedMaskTest(const wchar_t *mask, const wchar_t *name)
wchar_t c = *name;
if (m == 0)
return (c == 0);
if (m == kAnyCharsChar)
if (m == '*')
{
if (EnhancedMaskTest(mask + 1, name))
return true;
@@ -67,7 +71,7 @@ static bool EnhancedMaskTest(const wchar_t *mask, const wchar_t *name)
}
else
{
if (m == kAnyCharChar)
if (m == '?')
{
if (c == 0)
return false;
@@ -87,61 +91,84 @@ static bool EnhancedMaskTest(const wchar_t *mask, const wchar_t *name)
void SplitPathToParts(const UString &path, UStringVector &pathParts)
{
pathParts.Clear();
UString name;
int len = path.Length();
unsigned len = path.Len();
if (len == 0)
return;
for (int i = 0; i < len; i++)
{
wchar_t c = path[i];
if (IsCharDirLimiter(c))
UString name;
unsigned prev = 0;
for (unsigned i = 0; i < len; i++)
if (IsCharDirLimiter(path[i]))
{
name.SetFrom(path.Ptr(prev), i - prev);
pathParts.Add(name);
name.Empty();
prev = i + 1;
}
else
name += c;
}
name.SetFrom(path.Ptr(prev), len - prev);
pathParts.Add(name);
}
void SplitPathToParts(const UString &path, UString &dirPrefix, UString &name)
void SplitPathToParts_2(const UString &path, UString &dirPrefix, UString &name)
{
int i;
for (i = path.Length() - 1; i >= 0; i--)
if (IsCharDirLimiter(path[i]))
const wchar_t *start = path;
const wchar_t *p = start + path.Len();
for (; p != start; p--)
if (IsCharDirLimiter(*(p - 1)))
break;
dirPrefix = path.Left(i + 1);
name = path.Mid(i + 1);
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 (IsCharDirLimiter(*(p - 1)))
p--;
for (; p != start; p--)
if (IsCharDirLimiter(*(p - 1)))
break;
}
dirPrefix.SetFrom(path, (unsigned)(p - start));
name = p;
}
UString ExtractDirPrefixFromPath(const UString &path)
{
int i;
for (i = path.Length() - 1; i >= 0; i--)
if (IsCharDirLimiter(path[i]))
const wchar_t *start = path;
const wchar_t *p = start + path.Len();
for (; p != start; p--)
if (IsCharDirLimiter(*(p - 1)))
break;
return path.Left(i + 1);
return path.Left((unsigned)(p - start));
}
UString ExtractFileNameFromPath(const UString &path)
{
int i;
for (i = path.Length() - 1; i >= 0; i--)
if (IsCharDirLimiter(path[i]))
const wchar_t *start = path;
const wchar_t *p = start + path.Len();
for (; p != start; p--)
if (IsCharDirLimiter(*(p - 1)))
break;
return path.Mid(i + 1);
return p;
}
bool CompareWildCardWithName(const UString &mask, const UString &name)
bool DoesWildcardMatchName(const UString &mask, const UString &name)
{
return EnhancedMaskTest(mask, name);
}
bool DoesNameContainWildCard(const UString &path)
bool DoesNameContainWildcard(const UString &path)
{
return (path.FindOneOf(kWildCardCharSet) >= 0);
for (unsigned i = 0; i < path.Len(); i++)
{
wchar_t c = path[i];
if (c == '*' || c == '?')
return true;
}
return false;
}
@@ -151,22 +178,36 @@ bool DoesNameContainWildCard(const UString &path)
namespace NWildcard {
#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');
}
#endif
/*
M = MaskParts.Size();
N = TestNameParts.Size();
File Dir
ForFile req M<=N [N-M, N) -
nonreq M=N [0, M) -
ForFile rec M<=N [N-M, N) -
!ForDir nonrec M=N [0, M) -
ForDir req M<N [0, M) ... [N-M-1, N-1) same as ForBoth-File
nonreq [0, M) same as ForBoth-File
ForDir rec M<N [0, M) ... [N-M-1, N-1) same as ForBoth-File
!ForFile nonrec [0, M) same as ForBoth-File
ForBoth req m<=N [0, M) ... [N-M, N) same as ForBoth-File
nonreq [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)
@@ -176,36 +217,62 @@ bool CItem::CheckPath(const UStringVector &pathParts, bool isFile) const
return false;
int start = 0;
int finish = 0;
if (isFile)
{
if (!ForDir && !Recursive && delta !=0)
return false;
if (!ForDir)
{
if (Recursive)
start = delta;
else if (delta !=0)
return false;
}
if (!ForFile && delta == 0)
return false;
if (!ForDir && Recursive)
start = delta;
}
if (Recursive)
{
finish = delta;
if (isFile && !ForFile)
finish = delta - 1;
}
for (int d = start; d <= finish; d++)
{
int i;
unsigned i;
for (i = 0; i < PathParts.Size(); i++)
if (!CompareWildCardWithName(PathParts[i], pathParts[i + d]))
break;
{
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 (int i = 0; i < SubNodes.Size(); i++)
FOR_VECTOR (i, SubNodes)
if (CompareFileNames(SubNodes[i].Name, name) == 0)
return i;
return -1;
@@ -223,11 +290,19 @@ void CCensorNode::AddItem(bool include, CItem &item)
{
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();
if (DoesNameContainWildCard(front))
// We can't ignore wildcard, since we don't allow wildcard in SubNodes[].Name
// if (item.Wildcard)
if (DoesNameContainWildcard(front))
{
AddItemSimple(include, item);
return;
@@ -239,19 +314,20 @@ void CCensorNode::AddItem(bool include, CItem &item)
SubNodes[index].AddItem(include, item);
}
void CCensorNode::AddItem(bool include, const UString &path, bool recursive, bool forFile, bool forDir)
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 (int i = 0; i < IncludeItems.Size(); i++)
FOR_VECTOR (i, IncludeItems)
{
const CItem &item = IncludeItems[i];
if (item.Recursive || item.PathParts.Size() > 1)
@@ -264,7 +340,7 @@ bool CCensorNode::AreThereIncludeItems() const
{
if (IncludeItems.Size() > 0)
return true;
for (int i = 0; i < SubNodes.Size(); i++)
FOR_VECTOR (i, SubNodes)
if (SubNodes[i].AreThereIncludeItems())
return true;
return false;
@@ -273,13 +349,13 @@ bool CCensorNode::AreThereIncludeItems() const
bool CCensorNode::CheckPathCurrent(bool include, const UStringVector &pathParts, bool isFile) const
{
const CObjectVector<CItem> &items = include ? IncludeItems : ExcludeItems;
for (int i = 0; i < items.Size(); i++)
FOR_VECTOR (i, items)
if (items[i].CheckPath(pathParts, isFile))
return true;
return false;
}
bool CCensorNode::CheckPath(UStringVector &pathParts, bool isFile, bool &include) const
bool CCensorNode::CheckPathVect(const UStringVector &pathParts, bool isFile, bool &include) const
{
if (CheckPathCurrent(false, pathParts, isFile))
{
@@ -288,30 +364,45 @@ bool CCensorNode::CheckPath(UStringVector &pathParts, bool isFile, bool &include
}
include = true;
bool finded = CheckPathCurrent(true, pathParts, isFile);
if (pathParts.Size() == 1)
if (pathParts.Size() <= 1)
return finded;
int index = FindSubNode(pathParts.Front());
if (index >= 0)
{
UStringVector pathParts2 = pathParts;
pathParts2.Delete(0);
if (SubNodes[index].CheckPath(pathParts2, isFile, include))
if (SubNodes[index].CheckPathVect(pathParts2, isFile, include))
return true;
}
return finded;
}
bool CCensorNode::CheckPath(const UString &path, bool isFile, bool &include) const
bool CCensorNode::CheckPath2(bool isAltStream, const UString &path, bool isFile, bool &include) const
{
UStringVector pathParts;
SplitPathToParts(path, pathParts);
return CheckPath(pathParts, isFile, include);
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(const UString &path, bool isFile) const
bool CCensorNode::CheckPath(bool isAltStream, const UString &path, bool isFile) const
{
bool include;
if (CheckPath(path, isFile, include))
if (CheckPath2(isAltStream, path, isFile, include))
return include;
return false;
}
@@ -335,7 +426,7 @@ bool CCensorNode::CheckPathToRoot(bool include, const UString &path, bool isFile
}
*/
void CCensorNode::AddItem2(bool include, const UString &path, bool recursive)
void CCensorNode::AddItem2(bool include, const UString &path, bool recursive, bool wildcardMatching)
{
if (path.IsEmpty())
return;
@@ -347,13 +438,13 @@ void CCensorNode::AddItem2(bool include, const UString &path, bool recursive)
path2.DeleteBack();
forFile = false;
}
AddItem(include, path2, recursive, forFile, forFolder);
AddItem(include, path2, recursive, forFile, forFolder, wildcardMatching);
}
void CCensorNode::ExtendExclude(const CCensorNode &fromNodes)
{
ExcludeItems += fromNodes.ExcludeItems;
for (int i = 0; i < fromNodes.SubNodes.Size(); i++)
FOR_VECTOR (i, fromNodes.SubNodes)
{
const CCensorNode &node = fromNodes.SubNodes[i];
int subNodeIndex = FindSubNode(node.Name);
@@ -365,13 +456,13 @@ void CCensorNode::ExtendExclude(const CCensorNode &fromNodes)
int CCensor::FindPrefix(const UString &prefix) const
{
for (int i = 0; i < Pairs.Size(); i++)
FOR_VECTOR (i, Pairs)
if (CompareFileNames(Pairs[i].Prefix, prefix) == 0)
return i;
return -1;
}
void CCensor::AddItem(bool include, const UString &path, bool recursive)
void CCensor::AddItem(ECensorPathMode pathMode, bool include, const UString &path, bool recursive, bool wildcardMatching)
{
UStringVector pathParts;
if (path.IsEmpty())
@@ -383,40 +474,82 @@ void CCensor::AddItem(bool include, const UString &path, bool recursive)
forFile = false;
pathParts.DeleteBack();
}
const UString &front = pathParts.Front();
bool isAbs = false;
if (front.IsEmpty())
isAbs = true;
else if (front.Length() == 2 && front[1] == L':')
isAbs = true;
else
{
for (int i = 0; i < pathParts.Size(); i++)
{
const UString &part = pathParts[i];
if (part == L".." || part == L".")
{
isAbs = true;
break;
}
}
}
int numAbsParts = 0;
if (isAbs)
if (pathParts.Size() > 1)
numAbsParts = pathParts.Size() - 1;
else
numAbsParts = 1;
UString prefix;
for (int i = 0; i < numAbsParts; i++)
if (pathMode != k_AbsPath)
{
const UString &front = pathParts.Front();
if (DoesNameContainWildCard(front))
break;
prefix += front;
prefix += WCHAR_PATH_SEPARATOR;
pathParts.Delete(0);
bool isAbs = false;
if (front.IsEmpty())
isAbs = true;
else
{
#ifdef _WIN32
if (IsDriveColonName(front))
isAbs = true;
else
#endif
FOR_VECTOR (i, pathParts)
{
const UString &part = pathParts[i];
if (part == L".." || part == L".")
{
isAbs = true;
break;
}
}
}
unsigned numAbsParts = 0;
if (isAbs)
if (pathParts.Size() > 1)
numAbsParts = pathParts.Size() - 1;
else
numAbsParts = 1;
#ifdef _WIN32
// \\?\ case
if (numAbsParts >= 3)
{
if (pathParts[0].IsEmpty() &&
pathParts[1].IsEmpty() &&
pathParts[2] == L"?")
{
prefix =
WSTRING_PATH_SEPARATOR
WSTRING_PATH_SEPARATOR L"?"
WSTRING_PATH_SEPARATOR;
numAbsParts -= 3;
pathParts.DeleteFrontal(3);
}
}
#endif
if (numAbsParts > 1 && pathMode == k_FullPath)
numAbsParts = 1;
// We can't ignore wildcard, since we don't allow wildcard in SubNodes[].Name
// if (wildcardMatching)
for (unsigned i = 0; i < numAbsParts; i++)
{
{
const UString &front = pathParts.Front();
if (DoesNameContainWildcard(front))
break;
prefix += front;
prefix += WCHAR_PATH_SEPARATOR;
}
pathParts.Delete(0);
}
}
int index = FindPrefix(prefix);
if (index < 0)
index = Pairs.Add(CPair(prefix));
@@ -426,16 +559,17 @@ void CCensor::AddItem(bool include, const UString &path, bool recursive)
item.ForDir = true;
item.ForFile = forFile;
item.Recursive = recursive;
item.WildcardMatching = wildcardMatching;
Pairs[index].Head.AddItem(include, item);
}
bool CCensor::CheckPath(const UString &path, bool isFile) const
bool CCensor::CheckPath(bool isAltStream, const UString &path, bool isFile) const
{
bool finded = false;
for (int i = 0; i < Pairs.Size(); i++)
FOR_VECTOR (i, Pairs)
{
bool include;
if (Pairs[i].Head.CheckPath(path, isFile, include))
if (Pairs[i].Head.CheckPath2(isAltStream, path, isFile, include))
{
if (!include)
return false;
@@ -447,16 +581,35 @@ bool CCensor::CheckPath(const UString &path, bool isFile) const
void CCensor::ExtendExclude()
{
int i;
unsigned i;
for (i = 0; i < Pairs.Size(); i++)
if (Pairs[i].Prefix.IsEmpty())
break;
if (i == Pairs.Size())
return;
int index = i;
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;
}
}