diff options
Diffstat (limited to 'src/libs/3rdparty/7zip/win/CPP/Common/Wildcard.cpp')
-rw-r--r-- | src/libs/3rdparty/7zip/win/CPP/Common/Wildcard.cpp | 615 |
1 files changed, 615 insertions, 0 deletions
diff --git a/src/libs/3rdparty/7zip/win/CPP/Common/Wildcard.cpp b/src/libs/3rdparty/7zip/win/CPP/Common/Wildcard.cpp new file mode 100644 index 000000000..e88a1cf1c --- /dev/null +++ b/src/libs/3rdparty/7zip/win/CPP/Common/Wildcard.cpp @@ -0,0 +1,615 @@ +// 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) + { + 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) STRING_UNICODE_THROW +{ + 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 +// * - 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 (IsCharDirLimiter(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 (IsCharDirLimiter(*(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 (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) +{ + const wchar_t *start = path; + const wchar_t *p = start + path.Len(); + for (; p != start; p--) + if (IsCharDirLimiter(*(p - 1))) + break; + return path.Left((unsigned)(p - start)); +} + +UString ExtractFileNameFromPath(const UString &path) +{ + const wchar_t *start = path; + const wchar_t *p = start + path.Len(); + for (; p != start; p--) + if (IsCharDirLimiter(*(p - 1))) + break; + return p; +} + + +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 { + + +#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 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; + 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) +{ + 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(); + + // We can't ignore wildcard, since we don't allow wildcard in SubNodes[].Name + // if (item.Wildcard) + if (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); +} + +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 (IsCharDirLimiter(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; +} + +void CCensor::AddItem(ECensorPathMode pathMode, bool include, const UString &path, bool recursive, bool wildcardMatching) +{ + UStringVector pathParts; + if (path.IsEmpty()) + throw "Empty file path"; + SplitPathToParts(path, pathParts); + bool forFile = true; + if (pathParts.Back().IsEmpty()) + { + forFile = false; + pathParts.DeleteBack(); + } + + UString prefix; + + if (pathMode != k_AbsPath) + { + const UString &front = pathParts.Front(); + 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)); + + CItem item; + item.PathParts = pathParts; + item.ForDir = true; + item.ForFile = forFile; + item.Recursive = recursive; + item.WildcardMatching = wildcardMatching; + Pairs[index].Head.AddItem(include, item); +} + +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; +} + +} |