diff options
Diffstat (limited to 'CPP/Common/Wildcard.cpp')
-rw-r--r--[-rwxr-xr-x] | CPP/Common/Wildcard.cpp | 385 |
1 files changed, 269 insertions, 116 deletions
diff --git a/CPP/Common/Wildcard.cpp b/CPP/Common/Wildcard.cpp index 87d44971..182256ab 100755..100644 --- a/CPP/Common/Wildcard.cpp +++ b/CPP/Common/Wildcard.cpp @@ -2,8 +2,6 @@ #include "StdAfx.h" -#include "../../C/Types.h" - #include "Wildcard.h" bool g_CaseSensitive = @@ -13,37 +11,43 @@ 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"\"/:<>\\|"; +bool IsPath1PrefixedByPath2(const wchar_t *s1, const wchar_t *s2) +{ + if (g_CaseSensitive) + { + 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; + } +} -static inline bool IsCharDirLimiter(wchar_t c) +int CompareFileNames(const wchar_t *s1, const wchar_t *s2) { - return ( - #ifdef _WIN32 - c == kDirDelimiter1 || - #endif - c == kDirDelimiter2); + if (g_CaseSensitive) + return wcscmp(s1, s2); + return MyStringCompareNoCase(s1, s2); } -int CompareFileNames(const UString &s1, const UString &s2) +#ifndef USE_UNICODE_FSTRING +int CompareFileNames(const char *s1, const char *s2) { if (g_CaseSensitive) - return s1.Compare(s2); - return s1.CompareNoCase(s2); + return wcscmp(fs2us(s1), fs2us(s2)); + return MyStringCompareNoCase(fs2us(s1), fs2us(s2)); } +#endif // ----------------------------------------- // this function compares name with mask @@ -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 + + UString prefix; + + if (pathMode != k_AbsPath) { - for (int i = 0; i < pathParts.Size(); i++) + const UString &front = pathParts.Front(); + bool isAbs = false; + + if (front.IsEmpty()) + isAbs = true; + else { - const UString &part = pathParts[i]; - if (part == L".." || part == L".") - { + #ifdef _WIN32 + + if (IsDriveColonName(front)) isAbs = true; - break; + 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); } } - } - int numAbsParts = 0; - if (isAbs) - if (pathParts.Size() > 1) - numAbsParts = pathParts.Size() - 1; - else + + #endif + + if (numAbsParts > 1 && pathMode == k_FullPath) numAbsParts = 1; - UString prefix; - for (int i = 0; i < numAbsParts; i++) - { - const UString &front = pathParts.Front(); - if (DoesNameContainWildCard(front)) - break; - prefix += front; - prefix += WCHAR_PATH_SEPARATOR; - pathParts.Delete(0); + + // 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; +} + } |