other-licenses/7zstub/src/Common/Wildcard.cpp

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

     1 // Common/Wildcard.cpp
     3 #include "StdAfx.h"
     5 #include "Wildcard.h"
     7 static const wchar_t kPeriodChar = L'.';
     8 static const wchar_t kAnyCharsChar = L'*';
     9 static const wchar_t kAnyCharChar = L'?';
    11 #ifdef _WIN32
    12 static const wchar_t kDirDelimiter1 = L'\\';
    13 #endif
    14 static const wchar_t kDirDelimiter2 = L'/';
    16 static const UString kWildCardCharSet = L"?*";
    18 static const UString kIllegalWildCardFileNameChars=
    19   L"\x1\x2\x3\x4\x5\x6\x7\x8\x9\xA\xB\xC\xD\xE\xF"
    20   L"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
    21   L"\"/:<>\\|";
    23 static const UString kIllegalFileNameChars = kIllegalWildCardFileNameChars + 
    24     kWildCardCharSet;
    26 static inline bool IsCharDirLimiter(wchar_t c)
    27 {
    28   return (
    29     #ifdef _WIN32
    30     c == kDirDelimiter1 || 
    31     #endif
    32     c == kDirDelimiter2);
    33 }
    35 // -----------------------------------------
    36 // this function tests is name matches mask
    37 // ? - any wchar_t or empty
    38 // * - any characters or empty
    40 static bool EnhancedMaskTest(const UString &mask, int maskPos, 
    41     const UString &name, int namePos)
    42 {
    43   int maskLen = mask.Length() - maskPos;
    44   int nameLen = name.Length() - namePos;
    45   if (maskLen == 0) 
    46     if (nameLen == 0)
    47       return true;
    48     else
    49       return false;
    50   wchar_t maskChar = mask[maskPos];
    51   if(maskChar == kAnyCharChar)
    52   {
    53     /*
    54     if (EnhancedMaskTest(mask, maskPos + 1, name, namePos))
    55       return true;
    56     */
    57     if (nameLen == 0) 
    58       return false;
    59     return EnhancedMaskTest(mask,  maskPos + 1, name, namePos + 1);
    60   }
    61   else if(maskChar == kAnyCharsChar)
    62   {
    63     if (EnhancedMaskTest(mask, maskPos + 1, name, namePos))
    64       return true;
    65     if (nameLen == 0) 
    66       return false;
    67     return EnhancedMaskTest(mask, maskPos, name, namePos + 1);
    68   }
    69   else
    70   {
    71     wchar_t c = name[namePos];
    72     if (maskChar != c)
    73 #ifdef _WIN32
    74       if (MyCharUpper(maskChar) != MyCharUpper(c))
    75 #endif
    76         return false;
    77     return EnhancedMaskTest(mask,  maskPos + 1, name, namePos + 1);
    78   }
    79 }
    81 // --------------------------------------------------
    82 // Splits path to strings
    84 void SplitPathToParts(const UString &path, UStringVector &pathParts)
    85 {
    86   pathParts.Clear();
    87   UString name;
    88   int len = path.Length();
    89   if (len == 0)
    90     return;
    91   for (int i = 0; i < len; i++)
    92   {
    93     wchar_t c = path[i];
    94     if (IsCharDirLimiter(c))
    95     {
    96       pathParts.Add(name);
    97       name.Empty();
    98     }
    99     else
   100       name += c;
   101   }
   102   pathParts.Add(name);
   103 }
   105 void SplitPathToParts(const UString &path, UString &dirPrefix, UString &name)
   106 {
   107   int i;
   108   for(i = path.Length() - 1; i >= 0; i--)
   109     if(IsCharDirLimiter(path[i]))
   110       break;
   111   dirPrefix = path.Left(i + 1);
   112   name = path.Mid(i + 1);
   113 }
   115 UString ExtractDirPrefixFromPath(const UString &path)
   116 {
   117   int i;
   118   for(i = path.Length() - 1; i >= 0; i--)
   119     if(IsCharDirLimiter(path[i]))
   120       break;
   121   return path.Left(i + 1);
   122 }
   124 UString ExtractFileNameFromPath(const UString &path)
   125 {
   126   int i;
   127   for(i = path.Length() - 1; i >= 0; i--)
   128     if(IsCharDirLimiter(path[i]))
   129       break;
   130   return path.Mid(i + 1);
   131 }
   134 bool CompareWildCardWithName(const UString &mask, const UString &name)
   135 {
   136   return EnhancedMaskTest(mask, 0, name, 0);
   137 }
   139 bool DoesNameContainWildCard(const UString &path)
   140 {
   141   return (path.FindOneOf(kWildCardCharSet) >= 0);
   142 }
   145 // ----------------------------------------------------------'
   146 // NWildcard
   148 namespace NWildcard {
   150 static inline int BoolToIndex(bool value)
   151 {
   152   return value ? 1: 0;
   153 }
   156 /*
   157 M = MaskParts.Size();
   158 N = TestNameParts.Size();
   160                            File                          Dir
   161 ForFile     req   M<=N  [N-M, N)                          -
   162          nonreq   M=N   [0, M)                            -  
   164 ForDir      req   M<N   [0, M) ... [N-M-1, N-1)  same as ForBoth-File
   165          nonreq         [0, M)                   same as ForBoth-File
   167 ForBoth     req   m<=N  [0, M) ... [N-M, N)      same as ForBoth-File
   168          nonreq         [0, M)                   same as ForBoth-File
   170 */
   172 bool CItem::CheckPath(const UStringVector &pathParts, bool isFile) const
   173 {
   174   if (!isFile && !ForDir)
   175     return false;
   176   int delta = (int)pathParts.Size() - (int)PathParts.Size();
   177   if (delta < 0)
   178     return false;
   179   int start = 0;
   180   int finish = 0;
   181   if (isFile)
   182   {
   183     if (!ForDir && !Recursive && delta !=0)
   184       return false;
   185     if (!ForFile && delta == 0)
   186       return false;
   187     if (!ForDir && Recursive)
   188       start = delta;
   189   }
   190   if (Recursive)
   191   {
   192     finish = delta;
   193     if (isFile && !ForFile)
   194       finish = delta - 1;
   195   }
   196   for (int d = start; d <= finish; d++)
   197   {
   198     int i;
   199     for (i = 0; i < PathParts.Size(); i++)
   200       if (!CompareWildCardWithName(PathParts[i], pathParts[i + d]))
   201         break;
   202     if (i == PathParts.Size())
   203       return true;
   204   }
   205   return false;
   206 }
   208 int CCensorNode::FindSubNode(const UString &name) const
   209 {
   210   for (int i = 0; i < SubNodes.Size(); i++)
   211     if (SubNodes[i].Name.CompareNoCase(name) == 0)
   212       return i;
   213   return -1;
   214 }
   216 void CCensorNode::AddItemSimple(bool include, CItem &item)
   217 {
   218   if (include)
   219     IncludeItems.Add(item);
   220   else
   221     ExcludeItems.Add(item);
   222 }
   224 void CCensorNode::AddItem(bool include, CItem &item)
   225 {
   226   if (item.PathParts.Size() <= 1)
   227   {
   228     AddItemSimple(include, item);
   229     return;
   230   }
   231   const UString &front = item.PathParts.Front();
   232   if (DoesNameContainWildCard(front))
   233   {
   234     AddItemSimple(include, item);
   235     return;
   236   }
   237   int index = FindSubNode(front);
   238   if (index < 0)
   239     index = SubNodes.Add(CCensorNode(front, this));
   240   item.PathParts.Delete(0);
   241   SubNodes[index].AddItem(include, item);
   242 }
   244 void CCensorNode::AddItem(bool include, const UString &path, bool recursive, bool forFile, bool forDir)
   245 {
   246   CItem item;
   247   SplitPathToParts(path, item.PathParts);
   248   item.Recursive = recursive;
   249   item.ForFile = forFile;
   250   item.ForDir = forDir;
   251   AddItem(include, item);
   252 }
   254 bool CCensorNode::NeedCheckSubDirs() const
   255 {
   256   for (int i = 0; i < IncludeItems.Size(); i++)
   257   {
   258     const CItem &item = IncludeItems[i];
   259     if (item.Recursive || item.PathParts.Size() > 1)
   260       return true;
   261   }
   262   return false;
   263 }
   265 bool CCensorNode::AreThereIncludeItems() const
   266 {
   267   if (IncludeItems.Size() > 0)
   268     return true;
   269   for (int i = 0; i < SubNodes.Size(); i++)
   270     if (SubNodes[i].AreThereIncludeItems())
   271       return true;
   272   return false;
   273 }
   275 bool CCensorNode::CheckPathCurrent(bool include, const UStringVector &pathParts, bool isFile) const
   276 {
   277   const CObjectVector<CItem> &items = include ? IncludeItems : ExcludeItems;
   278   for (int i = 0; i < items.Size(); i++)
   279     if (items[i].CheckPath(pathParts, isFile))
   280       return true;
   281   return false;
   282 }
   284 bool CCensorNode::CheckPath(UStringVector &pathParts, bool isFile, bool &include) const
   285 {
   286   if (CheckPathCurrent(false, pathParts, isFile))
   287   {
   288     include = false;
   289     return true;
   290   }
   291   include = true;
   292   bool finded = CheckPathCurrent(true, pathParts, isFile);
   293   if (pathParts.Size() == 1)
   294     return finded;
   295   int index = FindSubNode(pathParts.Front());
   296   if (index >= 0)
   297   {
   298     UStringVector pathParts2 = pathParts;
   299     pathParts2.Delete(0);
   300     if (SubNodes[index].CheckPath(pathParts2, isFile, include))
   301       return true;
   302   }
   303   return finded;
   304 }
   306 bool CCensorNode::CheckPath(const UString &path, bool isFile, bool &include) const
   307 {
   308   UStringVector pathParts; 
   309   SplitPathToParts(path, pathParts);
   310   return CheckPath(pathParts, isFile, include);
   311 }
   313 bool CCensorNode::CheckPath(const UString &path, bool isFile) const
   314 {
   315   bool include;
   316   if(CheckPath(path, isFile, include))
   317     return include;
   318   return false;
   319 }
   321 bool CCensorNode::CheckPathToRoot(bool include, UStringVector &pathParts, bool isFile) const
   322 {
   323   if (CheckPathCurrent(include, pathParts, isFile))
   324     return true;
   325   if (Parent == 0)
   326     return false;
   327   pathParts.Insert(0, Name);
   328   return Parent->CheckPathToRoot(include, pathParts, isFile);
   329 }
   331 /*
   332 bool CCensorNode::CheckPathToRoot(bool include, const UString &path, bool isFile) const
   333 {
   334   UStringVector pathParts; 
   335   SplitPathToParts(path, pathParts);
   336   return CheckPathToRoot(include, pathParts, isFile);
   337 }
   338 */
   340 void CCensorNode::AddItem2(bool include, const UString &path, bool recursive)
   341 {
   342   if (path.IsEmpty())
   343     return;
   344   bool forFile = true;
   345   bool forFolder = true;
   346   UString path2 = path;
   347   if (IsCharDirLimiter(path[path.Length() - 1]))
   348   {
   349     path2.Delete(path.Length() - 1);
   350     forFile = false;
   351   }
   352   AddItem(include, path2, recursive, forFile, forFolder);
   353 }
   355 void CCensorNode::ExtendExclude(const CCensorNode &fromNodes)
   356 {
   357   ExcludeItems += fromNodes.ExcludeItems;
   358   for (int i = 0; i < fromNodes.SubNodes.Size(); i++)
   359   {
   360     const CCensorNode &node = fromNodes.SubNodes[i];
   361     int subNodeIndex = FindSubNode(node.Name);
   362     if (subNodeIndex < 0)
   363       subNodeIndex = SubNodes.Add(CCensorNode(node.Name, this));
   364     SubNodes[subNodeIndex].ExtendExclude(node);
   365   }
   366 }
   368 int CCensor::FindPrefix(const UString &prefix) const
   369 {
   370   for (int i = 0; i < Pairs.Size(); i++)
   371     if (Pairs[i].Prefix.CompareNoCase(prefix) == 0)
   372       return i;
   373   return -1;
   374 }
   376 void CCensor::AddItem(bool include, const UString &path, bool recursive)
   377 {
   378   UStringVector pathParts;
   379   SplitPathToParts(path, pathParts);
   380   bool forFile = true;
   381   if (pathParts.Back().IsEmpty())
   382   {
   383     forFile = false;
   384     pathParts.DeleteBack();
   385   }
   386   const UString &front = pathParts.Front();
   387   bool isAbs = false;
   388   if (front.IsEmpty())
   389     isAbs = true;
   390   else if (front.Length() == 2 && front[1] == L':')
   391     isAbs = true;
   392   else
   393   {
   394     for (int i = 0; i < pathParts.Size(); i++)
   395     {
   396       const UString &part = pathParts[i];
   397       if (part == L".." || part == L".")
   398       {
   399         isAbs = true;
   400         break;
   401       }
   402     }
   403   }
   404   int numAbsParts = 0;
   405   if (isAbs)
   406     if (pathParts.Size() > 1)
   407       numAbsParts = pathParts.Size() - 1;
   408     else
   409       numAbsParts = 1;
   410   UString prefix;
   411   for (int i = 0; i < numAbsParts; i++)
   412   {
   413     const UString &front = pathParts.Front();
   414     if (DoesNameContainWildCard(front))
   415       break;
   416     prefix += front;
   417     prefix += WCHAR_PATH_SEPARATOR;
   418     pathParts.Delete(0);
   419   }
   420   int index = FindPrefix(prefix);
   421   if (index < 0)
   422     index = Pairs.Add(CPair(prefix));
   424   CItem item;
   425   item.PathParts = pathParts;
   426   item.ForDir = true;
   427   item.ForFile = forFile;
   428   item.Recursive = recursive;
   429   Pairs[index].Head.AddItem(include, item);
   430 }
   432 bool CCensor::CheckPath(const UString &path, bool isFile) const
   433 {
   434   bool finded = false;
   435   for (int i = 0; i < Pairs.Size(); i++)
   436   {
   437     bool include;
   438     if (Pairs[i].Head.CheckPath(path, isFile, include))
   439     {
   440       if (!include)
   441         return false;
   442       finded = true;
   443     }
   444   }
   445   return finded;
   446 }
   448 void CCensor::ExtendExclude()
   449 {
   450   int i;
   451   for (i = 0; i < Pairs.Size(); i++)
   452     if (Pairs[i].Prefix.IsEmpty())
   453       break;
   454   if (i == Pairs.Size())
   455     return;
   456   int index = i;
   457   for (i = 0; i < Pairs.Size(); i++)
   458     if (index != i)
   459       Pairs[i].Head.ExtendExclude(Pairs[index].Head);
   460 }
   462 }

mercurial