From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- other-licenses/7zstub/src/CPP/Common/Wildcard.cpp | 676 ++++++++++++++++++++++ 1 file changed, 676 insertions(+) create mode 100644 other-licenses/7zstub/src/CPP/Common/Wildcard.cpp (limited to 'other-licenses/7zstub/src/CPP/Common/Wildcard.cpp') diff --git a/other-licenses/7zstub/src/CPP/Common/Wildcard.cpp b/other-licenses/7zstub/src/CPP/Common/Wildcard.cpp new file mode 100644 index 0000000000..43e4baa179 --- /dev/null +++ b/other-licenses/7zstub/src/CPP/Common/Wildcard.cpp @@ -0,0 +1,676 @@ +// 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 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 &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; +} + +} -- cgit v1.2.3