Wildcard.cpp 10 KB

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