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.

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

mercurial