annotate src/win32/7zip/7z/CPP/Common/Wildcard.cpp @ 1:f9f4f1b99eed

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