00001
00002
00003
00004
00005 #include "StdAfx.h"
00006
00007 #include "Wildcard.h"
00008
00009 static const wchar_t kPeriodChar = L'.';
00010 static const wchar_t kAnyCharsChar = L'*';
00011 static const wchar_t kAnyCharChar = L'?';
00012
00013 static const wchar_t kDirDelimiter1 = L'\\';
00014 static const wchar_t kDirDelimiter2 = L'/';
00015
00016 static const UString kWildCardCharSet = L"?*";
00017
00018 static const UString kIllegalWildCardFileNameChars=
00019 L"\x1\x2\x3\x4\x5\x6\x7\x8\x9\xA\xB\xC\xD\xE\xF"
00020 L"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
00021 L"\"/:<>\\|";
00022
00023 static const UString kIllegalFileNameChars = kIllegalWildCardFileNameChars +
00024 kWildCardCharSet;
00025
00026 static inline bool IsCharDirLimiter(wchar_t c)
00027 {
00028 return (c == kDirDelimiter1 || c == kDirDelimiter2);
00029 }
00030
00031 static bool EnhancedMaskTest(const UString &mask, int maskPos,
00032 const UString &name, int namePos)
00033 {
00034 int maskLen = mask.Length() - maskPos;
00035 int nameLen = name.Length() - namePos;
00036 if (maskLen == 0)
00037 if (nameLen == 0)
00038 return true;
00039 else
00040 return false;
00041 wchar_t maskChar = mask[maskPos];
00042 if(maskChar == kAnyCharChar)
00043 {
00044
00045 if (nameLen == 0)
00046 return false;
00047 return EnhancedMaskTest(mask, maskPos + 1, name, namePos + 1);
00048 }
00049 else if(maskChar == kAnyCharsChar)
00050 {
00051 if (EnhancedMaskTest(mask, maskPos + 1, name, namePos))
00052 return true;
00053 if (nameLen == 0)
00054 return false;
00055 return EnhancedMaskTest(mask, maskPos, name, namePos + 1);
00056 }
00057 else
00058 {
00059 wchar_t c = name[namePos];
00060 if (maskChar != c)
00061 #ifdef _WIN32
00062 if (MyCharUpper(maskChar) != MyCharUpper(c))
00063 #endif
00064 return false;
00065 return EnhancedMaskTest(mask, maskPos + 1, name, namePos + 1);
00066 }
00067 }
00068
00069 void SplitPathToParts(const UString &path, UStringVector &pathParts)
00070 {
00071 pathParts.Clear();
00072 UString name;
00073 int len = path.Length();
00074 if (len == 0)
00075 return;
00076 for (int i = 0; i < len; i++)
00077 {
00078 wchar_t c = path[i];
00079 if (IsCharDirLimiter(c))
00080 {
00081 pathParts.Add(name);
00082 name.Empty();
00083 }
00084 else
00085 name += c;
00086 }
00087 pathParts.Add(name);
00088 }
00089
00090 void SplitPathToParts(const UString &path, UString &dirPrefix, UString &name)
00091 {
00092 int i;
00093 for(i = path.Length() - 1; i >= 0; i--)
00094 if(IsCharDirLimiter(path[i]))
00095 break;
00096 dirPrefix = path.Left(i + 1);
00097 name = path.Mid(i + 1);
00098 }
00099
00100 UString ExtractDirPrefixFromPath(const UString &path)
00101 {
00102 int i;
00103 for(i = path.Length() - 1; i >= 0; i--)
00104 if(IsCharDirLimiter(path[i]))
00105 break;
00106 return path.Left(i + 1);
00107 }
00108
00109 UString ExtractFileNameFromPath(const UString &path)
00110 {
00111 int i;
00112 for(i = path.Length() - 1; i >= 0; i--)
00113 if(IsCharDirLimiter(path[i]))
00114 break;
00115 return path.Mid(i + 1);
00116 }
00117
00118 bool CompareWildCardWithName(const UString &mask, const UString &name)
00119 {
00120 return EnhancedMaskTest(mask, 0, name, 0);
00121 }
00122
00123 bool DoesNameContainWildCard(const UString &path)
00124 {
00125 return (path.FindOneOf(kWildCardCharSet) >= 0);
00126 }
00127
00128 namespace NWildcard {
00129
00130 static inline int BoolToIndex(bool value)
00131 {
00132 return value ? 1: 0;
00133 }
00134
00135 bool CItem::CheckPath(const UStringVector &pathParts, bool isFile) const
00136 {
00137 if (!isFile && !ForDir)
00138 return false;
00139 int delta = (int)pathParts.Size() - (int)PathParts.Size();
00140 if (delta < 0)
00141 return false;
00142 int start = 0;
00143 int finish = 0;
00144 if (isFile)
00145 {
00146 if (!ForDir && !Recursive && delta !=0)
00147 return false;
00148 if (!ForFile && delta == 0)
00149 return false;
00150 if (!ForDir && Recursive)
00151 start = delta;
00152 }
00153 if (Recursive)
00154 {
00155 finish = delta;
00156 if (isFile && !ForFile)
00157 finish = delta - 1;
00158 }
00159 for (int d = start; d <= finish; d++)
00160 {
00161 int i;
00162 for (i = 0; i < PathParts.Size(); i++)
00163 if (!CompareWildCardWithName(PathParts[i], pathParts[i + d]))
00164 break;
00165 if (i == PathParts.Size())
00166 return true;
00167 }
00168 return false;
00169 }
00170
00171 int CCensorNode::FindSubNode(const UString &name) const
00172 {
00173 for (int i = 0; i < SubNodes.Size(); i++)
00174 if (SubNodes[i].Name.CompareNoCase(name) == 0)
00175 return i;
00176 return -1;
00177 }
00178
00179 void CCensorNode::AddItemSimple(bool include, CItem &item)
00180 {
00181 if (include)
00182 IncludeItems.Add(item);
00183 else
00184 ExcludeItems.Add(item);
00185 }
00186
00187 void CCensorNode::AddItem(bool include, CItem &item)
00188 {
00189 if (item.PathParts.Size() <= 1)
00190 {
00191 AddItemSimple(include, item);
00192 return;
00193 }
00194 const UString &front = item.PathParts.Front();
00195 if (DoesNameContainWildCard(front))
00196 {
00197 AddItemSimple(include, item);
00198 return;
00199 }
00200 int index = FindSubNode(front);
00201 if (index < 0)
00202 index = SubNodes.Add(CCensorNode(front, this));
00203 item.PathParts.Delete(0);
00204 SubNodes[index].AddItem(include, item);
00205 }
00206
00207 void CCensorNode::AddItem(bool include, const UString &path, bool recursive, bool forFile, bool forDir)
00208 {
00209 CItem item;
00210 SplitPathToParts(path, item.PathParts);
00211 item.Recursive = recursive;
00212 item.ForFile = forFile;
00213 item.ForDir = forDir;
00214 AddItem(include, item);
00215 }
00216
00217 bool CCensorNode::NeedCheckSubDirs() const
00218 {
00219 for (int i = 0; i < IncludeItems.Size(); i++)
00220 {
00221 const CItem &item = IncludeItems[i];
00222 if (item.Recursive || item.PathParts.Size() > 1)
00223 return true;
00224 }
00225 return false;
00226 }
00227
00228 bool CCensorNode::AreThereIncludeItems() const
00229 {
00230 if (IncludeItems.Size() > 0)
00231 return true;
00232 for (int i = 0; i < SubNodes.Size(); i++)
00233 if (SubNodes[i].AreThereIncludeItems())
00234 return true;
00235 return false;
00236 }
00237
00238 bool CCensorNode::CheckPathCurrent(bool include, const UStringVector &pathParts, bool isFile) const
00239 {
00240 const CObjectVector<CItem> &items = include ? IncludeItems : ExcludeItems;
00241 for (int i = 0; i < items.Size(); i++)
00242 if (items[i].CheckPath(pathParts, isFile))
00243 return true;
00244 return false;
00245 }
00246
00247 bool CCensorNode::CheckPath(UStringVector &pathParts, bool isFile, bool &include) const
00248 {
00249 if (CheckPathCurrent(false, pathParts, isFile))
00250 {
00251 include = false;
00252 return true;
00253 }
00254 include = true;
00255 bool finded = CheckPathCurrent(true, pathParts, isFile);
00256 if (pathParts.Size() == 1)
00257 return finded;
00258 int index = FindSubNode(pathParts.Front());
00259 if (index >= 0)
00260 {
00261 UStringVector pathParts2 = pathParts;
00262 pathParts2.Delete(0);
00263 if (SubNodes[index].CheckPath(pathParts2, isFile, include))
00264 return true;
00265 }
00266 return finded;
00267 }
00268
00269 bool CCensorNode::CheckPath(const UString &path, bool isFile, bool &include) const
00270 {
00271 UStringVector pathParts;
00272 SplitPathToParts(path, pathParts);
00273 return CheckPath(pathParts, isFile, include);
00274 }
00275
00276 bool CCensorNode::CheckPath(const UString &path, bool isFile) const
00277 {
00278 bool include;
00279 if(CheckPath(path, isFile, include))
00280 return include;
00281 return false;
00282 }
00283
00284 bool CCensorNode::CheckPathToRoot(bool include, UStringVector &pathParts, bool isFile) const
00285 {
00286 if (CheckPathCurrent(include, pathParts, isFile))
00287 return true;
00288 if (Parent == 0)
00289 return false;
00290 pathParts.Insert(0, Name);
00291 return Parent->CheckPathToRoot(include, pathParts, isFile);
00292 }
00293
00294 void CCensorNode::AddItem2(bool include, const UString &path, bool recursive)
00295 {
00296 if (path.IsEmpty())
00297 return;
00298 bool forFile = true;
00299 bool forFolder = true;
00300 UString path2 = path;
00301 if (IsCharDirLimiter(path[path.Length() - 1]))
00302 {
00303 path2.Delete(path.Length() - 1);
00304 forFile = false;
00305 }
00306 AddItem(include, path2, recursive, forFile, forFolder);
00307 }
00308
00309 int CCensor::FindPrefix(const UString &prefix) const
00310 {
00311 for (int i = 0; i < Pairs.Size(); i++)
00312 if (Pairs[i].Prefix.CompareNoCase(prefix) == 0)
00313 return i;
00314 return -1;
00315 }
00316
00317 void CCensor::AddItem(bool include, const UString &path, bool recursive)
00318 {
00319 UStringVector pathParts;
00320 SplitPathToParts(path, pathParts);
00321 bool forFile = true;
00322 if (pathParts.Back().IsEmpty())
00323 {
00324 forFile = false;
00325 pathParts.DeleteBack();
00326 }
00327 const UString &front = pathParts.Front();
00328 bool isAbs = false;
00329 if (front.IsEmpty())
00330 isAbs = true;
00331 else if (front.Length() == 2 && front[1] == L':')
00332 isAbs = true;
00333 else
00334 {
00335 for (int i = 0; i < pathParts.Size(); i++)
00336 {
00337 const UString &part = pathParts[i];
00338 if (part == L".." || part == L".")
00339 {
00340 isAbs = true;
00341 break;
00342 }
00343 }
00344 }
00345 int numAbsParts = 0;
00346 if (isAbs)
00347 if (pathParts.Size() > 1)
00348 numAbsParts = pathParts.Size() - 1;
00349 else
00350 numAbsParts = 1;
00351 UString prefix;
00352 for (int i = 0; i < numAbsParts; i++)
00353 {
00354 const UString &front = pathParts.Front();
00355 if (DoesNameContainWildCard(front))
00356 break;
00357 prefix += front;
00358 prefix += L'\\';
00359 pathParts.Delete(0);
00360 }
00361 int index = FindPrefix(prefix);
00362 if (index < 0)
00363 index = Pairs.Add(CPair(prefix));
00364
00365 CItem item;
00366 item.PathParts = pathParts;
00367 item.ForDir = true;
00368 item.ForFile = forFile;
00369 item.Recursive = recursive;
00370 Pairs[index].Head.AddItem(include, item);
00371 }
00372
00373 bool CCensor::CheckPath(const UString &path, bool isFile) const
00374 {
00375 bool finded = false;
00376 for (int i = 0; i < Pairs.Size(); i++)
00377 {
00378 bool include;
00379 if (Pairs[i].Head.CheckPath(path, isFile, include))
00380 {
00381 if (!include)
00382 return false;
00383 finded = true;
00384 }
00385 }
00386 return finded;
00387 }
00388
00389 }
00390
00391 bool AreTheFileNamesDirDelimiterEqual(const UString &name1, const UString &name2)
00392 {
00393 if(name1.Length() != name2.Length())
00394 return false;
00395 for(int i = 0; i < name1.Length(); i++)
00396 {
00397 wchar_t char1 = name1[i], char2 = name2[i];
00398 if (char1 == char2)
00399 continue;
00400 if (IsCharDirLimiter(char1) && IsCharDirLimiter(char2))
00401 continue;
00402 return false;
00403 }
00404 return true;
00405 }