ProjectArcade
160 строк · 6.0 Кб
1using System.Linq;
2
3namespace DokanNet
4{
5/// <summary>
6/// %Dokan functions helpers for user <see cref="IDokanOperations"/> implementation.
7/// </summary>
8public static class DokanHelper
9{
10/// <summary>
11/// Matches zero or more characters until encountering and matching the final . in the name.
12/// </summary>
13private const char DOS_STAR = '<';
14
15/// <summary>
16/// Matches any single character or, upon encountering a period or end
17/// of name string, advances the expression to the end of the set of
18/// contiguous DOS_QMs.
19/// </summary>
20private const char DOS_QM = '>';
21
22/// <summary>
23/// Matches either a period or zero characters beyond the name string.
24/// </summary>
25private const char DOS_DOT = '"';
26
27/// <summary>
28/// Matches zero or more characters.
29/// </summary>
30private const char ASTERISK = '*';
31
32/// <summary>
33/// Matches a single character.
34/// </summary>
35private const char QUESTION_MARK = '?';
36
37private readonly static char[] CharsThatMatchEmptyStringsAtEnd = { DOS_DOT, DOS_STAR, ASTERISK };
38
39/// <summary>
40/// Check whether <paramref name="name">Name</paramref> matches <paramref name="expression">Expression</paramref>.
41/// </summary>
42/// <remarks>
43/// This method is mainly used in <see cref="IDokanOperations.FindFilesWithPattern"/> to filter a list of possible files.
44/// For example "F0_<"*" match "f0_001.txt"
45/// \see <a href="http://msdn.microsoft.com/en-us/library/ff546850(v=VS.85).aspx">See FsRtlIsNameInExpression routine (MSDN)</a>
46/// </remarks>
47/// <param name="expression">The matching pattern. Can contain: ?, *, <, ", >.</param>
48/// <param name="name">The string that will be tested.</param>
49/// <param name="ignoreCase">When set to true a case insensitive match will be performed.</param>
50/// <returns>Returns true if Expression match Name, false otherwise.</returns>
51public static bool DokanIsNameInExpression(string expression, string name, bool ignoreCase)
52{
53var ei = 0;
54var ni = 0;
55
56while (ei < expression.Length && ni < name.Length)
57{
58switch (expression[ei])
59{
60case ASTERISK:
61ei++;
62if (ei > expression.Length)
63return true;
64
65while (ni < name.Length)
66{
67if (DokanIsNameInExpression(expression.Substring(ei), name.Substring(ni), ignoreCase))
68return true;
69ni++;
70}
71
72break;
73case DOS_STAR:
74var lastDotIndex = name.LastIndexOf('.');
75ei++;
76
77var endReached = false;
78while (!endReached)
79{
80endReached = (ni >= name.Length || lastDotIndex > -1 && ni > lastDotIndex);
81
82if (!endReached)
83{
84if (DokanIsNameInExpression(expression.Substring(ei), name.Substring(ni), ignoreCase))
85return true;
86ni++;
87}
88}
89
90break;
91case DOS_QM:
92ei++;
93if (name[ni] != '.')
94{
95ni++;
96}
97else
98{
99var p = ni + 1;
100while (p < name.Length)
101{
102if (name[p] == '.')
103break;
104p++;
105}
106
107if (p < name.Length && name[p] == '.')
108ni++;
109}
110
111break;
112case DOS_DOT:
113if (ei < expression.Length)
114{
115if (name[ni] != '.')
116return false;
117else
118ni++;
119}
120else
121{
122if (name[ni] == '.')
123ni++;
124}
125ei++;
126break;
127case QUESTION_MARK:
128ei++;
129ni++;
130break;
131default:
132if (ignoreCase && char.ToUpperInvariant(expression[ei]) == char.ToUpperInvariant(name[ni]))
133{
134ei++;
135ni++;
136}
137else if (!ignoreCase && expression[ei] == name[ni])
138{
139ei++;
140ni++;
141}
142else
143{
144return false;
145}
146
147break;
148}
149}
150
151var nextExpressionChars = expression.Substring(ei);
152var areNextExpressionCharsAllNullMatchers = expression.Any() && !string.IsNullOrEmpty(nextExpressionChars) && nextExpressionChars.All(x => CharsThatMatchEmptyStringsAtEnd.Contains(x));
153var isNameCurrentCharTheLast = ni == name.Length;
154if (ei == expression.Length && isNameCurrentCharTheLast || isNameCurrentCharTheLast && areNextExpressionCharsAllNullMatchers)
155return true;
156
157return false;
158}
159}
160}
161