misc/libphysfs/lzma/CPP/Common/Wildcard.cpp
changeset 12218 bb5522e88ab2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libphysfs/lzma/CPP/Common/Wildcard.cpp	Mon Apr 10 12:06:43 2017 -0400
@@ -0,0 +1,458 @@
+// Common/Wildcard.cpp
+
+#include "StdAfx.h"
+
+#include "Wildcard.h"
+
+bool g_CaseSensitive = 
+  #ifdef _WIN32
+    false;
+  #else
+    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)
+{
+  if (g_CaseSensitive)
+    return s1.Compare(s2);
+  return s1.CompareNoCase(s2);
+}
+
+// -----------------------------------------
+// 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 == kAnyCharsChar)
+    {
+      if (EnhancedMaskTest(mask + 1, name))
+        return true;
+      if (c == 0) 
+        return false;
+    }
+    else
+    {
+      if (m == kAnyCharChar)
+      {
+        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();
+  UString name;
+  int len = path.Length();
+  if (len == 0)
+    return;
+  for (int i = 0; i < len; i++)
+  {
+    wchar_t c = path[i];
+    if (IsCharDirLimiter(c))
+    {
+      pathParts.Add(name);
+      name.Empty();
+    }
+    else
+      name += c;
+  }
+  pathParts.Add(name);
+}
+
+void SplitPathToParts(const UString &path, UString &dirPrefix, UString &name)
+{
+  int i;
+  for(i = path.Length() - 1; i >= 0; i--)
+    if(IsCharDirLimiter(path[i]))
+      break;
+  dirPrefix = path.Left(i + 1);
+  name = path.Mid(i + 1);
+}
+
+UString ExtractDirPrefixFromPath(const UString &path)
+{
+  int i;
+  for(i = path.Length() - 1; i >= 0; i--)
+    if(IsCharDirLimiter(path[i]))
+      break;
+  return path.Left(i + 1);
+}
+
+UString ExtractFileNameFromPath(const UString &path)
+{
+  int i;
+  for(i = path.Length() - 1; i >= 0; i--)
+    if(IsCharDirLimiter(path[i]))
+      break;
+  return path.Mid(i + 1);
+}
+
+
+bool CompareWildCardWithName(const UString &mask, const UString &name)
+{
+  return EnhancedMaskTest(mask, name);
+}
+
+bool DoesNameContainWildCard(const UString &path)
+{
+  return (path.FindOneOf(kWildCardCharSet) >= 0);
+}
+
+
+// ----------------------------------------------------------'
+// NWildcard
+
+namespace NWildcard {
+
+
+/*
+M = MaskParts.Size();
+N = TestNameParts.Size();
+
+                           File                          Dir
+ForFile     req   M<=N  [N-M, N)                          -
+         nonreq   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
+
+ForBoth     req   m<=N  [0, M) ... [N-M, N)      same as ForBoth-File
+         nonreq         [0, M)                   same as ForBoth-File
+
+*/
+
+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 && !Recursive && 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;
+    for (i = 0; i < PathParts.Size(); i++)
+      if (!CompareWildCardWithName(PathParts[i], pathParts[i + d]))
+        break;
+    if (i == PathParts.Size())
+      return true;
+  }
+  return false;
+}
+
+int CCensorNode::FindSubNode(const UString &name) const
+{
+  for (int i = 0; i < SubNodes.Size(); i++)
+    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)
+  {
+    AddItemSimple(include, item);
+    return;
+  }
+  const UString &front = item.PathParts.Front();
+  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)
+{
+  CItem item;
+  SplitPathToParts(path, item.PathParts);
+  item.Recursive = recursive;
+  item.ForFile = forFile;
+  item.ForDir = forDir;
+  AddItem(include, item);
+}
+
+bool CCensorNode::NeedCheckSubDirs() const
+{
+  for (int i = 0; i < IncludeItems.Size(); i++)
+  {
+    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 (int i = 0; i < SubNodes.Size(); i++)
+    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 (int i = 0; i < items.Size(); i++)
+    if (items[i].CheckPath(pathParts, isFile))
+      return true;
+  return false;
+}
+
+bool CCensorNode::CheckPath(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].CheckPath(pathParts2, isFile, include))
+      return true;
+  }
+  return finded;
+}
+
+bool CCensorNode::CheckPath(const UString &path, bool isFile, bool &include) const
+{
+  UStringVector pathParts; 
+  SplitPathToParts(path, pathParts);
+  return CheckPath(pathParts, isFile, include);
+}
+
+bool CCensorNode::CheckPath(const UString &path, bool isFile) const
+{
+  bool include;
+  if(CheckPath(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)
+{
+  if (path.IsEmpty())
+    return;
+  bool forFile = true;
+  bool forFolder = true;
+  UString path2 = path;
+  if (IsCharDirLimiter(path[path.Length() - 1]))
+  {
+    path2.Delete(path.Length() - 1);
+    forFile = false;
+  }
+  AddItem(include, path2, recursive, forFile, forFolder);
+}
+
+void CCensorNode::ExtendExclude(const CCensorNode &fromNodes)
+{
+  ExcludeItems += fromNodes.ExcludeItems;
+  for (int i = 0; i < fromNodes.SubNodes.Size(); i++)
+  {
+    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 (int i = 0; i < Pairs.Size(); i++)
+    if (CompareFileNames(Pairs[i].Prefix, prefix) == 0)
+      return i;
+  return -1;
+}
+
+void CCensor::AddItem(bool include, const UString &path, bool recursive)
+{
+  UStringVector pathParts;
+  SplitPathToParts(path, pathParts);
+  bool forFile = true;
+  if (pathParts.Back().IsEmpty())
+  {
+    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++)
+  {
+    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;
+  Pairs[index].Head.AddItem(include, item);
+}
+
+bool CCensor::CheckPath(const UString &path, bool isFile) const
+{
+  bool finded = false;
+  for (int i = 0; i < Pairs.Size(); i++)
+  {
+    bool include;
+    if (Pairs[i].Head.CheckPath(path, isFile, include))
+    {
+      if (!include)
+        return false;
+      finded = true;
+    }
+  }
+  return finded;
+}
+
+void CCensor::ExtendExclude()
+{
+  int i;
+  for (i = 0; i < Pairs.Size(); i++)
+    if (Pairs[i].Prefix.IsEmpty())
+      break;
+  if (i == Pairs.Size())
+    return;
+  int index = i;
+  for (i = 0; i < Pairs.Size(); i++)
+    if (index != i)
+      Pairs[i].Head.ExtendExclude(Pairs[index].Head);
+}
+
+}