root / trunk / hammock / src / net35 / ICSharpCode.SharpZipLib.Silverlight / Core / NameFilter.cs @ 0eea575a
History | View | Annotate | Download (9.4 kB)
1 |
// NameFilter.cs |
---|---|
2 |
// |
3 |
// Copyright 2005 John Reilly |
4 |
// |
5 |
// This program is free software; you can redistribute it and/or |
6 |
// modify it under the terms of the GNU General Public License |
7 |
// as published by the Free Software Foundation; either version 2 |
8 |
// of the License, or (at your option) any later version. |
9 |
// |
10 |
// This program is distributed in the hope that it will be useful, |
11 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 |
// GNU General Public License for more details. |
14 |
// |
15 |
// You should have received a copy of the GNU General Public License |
16 |
// along with this program; if not, write to the Free Software |
17 |
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
18 |
// |
19 |
// Linking this library statically or dynamically with other modules is |
20 |
// making a combined work based on this library. Thus, the terms and |
21 |
// conditions of the GNU General Public License cover the whole |
22 |
// combination. |
23 |
// |
24 |
// As a special exception, the copyright holders of this library give you |
25 |
// permission to link this library with independent modules to produce an |
26 |
// executable, regardless of the license terms of these independent |
27 |
// modules, and to copy and distribute the resulting executable under |
28 |
// terms of your choice, provided that you also meet, for each linked |
29 |
// independent module, the terms and conditions of the license of that |
30 |
// module. An independent module is a module which is not derived from |
31 |
// or based on this library. If you modify this library, you may extend |
32 |
// this exception to your version of the library, but you are not |
33 |
// obligated to do so. If you do not wish to do so, delete this |
34 |
// exception statement from your version. |
35 |
|
36 |
|
37 |
using System; |
38 |
using System.Collections.Generic; |
39 |
using System.Text.RegularExpressions; |
40 |
|
41 |
namespace ICSharpCode.SharpZipLib.Silverlight.Core |
42 |
{ |
43 |
/// <summary> |
44 |
/// NameFilter is a string matching class which allows for both positive and negative |
45 |
/// matching. |
46 |
/// A filter is a sequence of independant <see cref="Regex">regular expressions</see> separated by semi-colons ';' |
47 |
/// Each expression can be prefixed by a plus '+' sign or a minus '-' sign to denote the expression |
48 |
/// is intended to include or exclude names. If neither a plus or minus sign is found include is the default |
49 |
/// A given name is tested for inclusion before checking exclusions. Only names matching an include spec |
50 |
/// and not matching an exclude spec are deemed to match the filter. |
51 |
/// An empty filter matches any name. |
52 |
/// </summary> |
53 |
/// <example>The following expression includes all name ending in '.dat' with the exception of 'dummy.dat' |
54 |
/// "+\.dat$;-^dummy\.dat$" |
55 |
/// </example> |
56 |
public class NameFilter : IScanFilter |
57 |
{ |
58 |
#region Constructors |
59 |
|
60 |
/// <summary> |
61 |
/// Construct an instance based on the filter expression passed |
62 |
/// </summary> |
63 |
/// <param name="filter">The filter expression.</param> |
64 |
public NameFilter(string filter) |
65 |
{ |
66 |
filter_ = filter; |
67 |
inclusions_ = new List<Regex>(); |
68 |
exclusions_ = new List<Regex>(); |
69 |
Compile(); |
70 |
} |
71 |
|
72 |
#endregion |
73 |
|
74 |
#region IScanFilter Members |
75 |
|
76 |
/// <summary> |
77 |
/// Test a value to see if it matches the filter. |
78 |
/// </summary> |
79 |
/// <param name="name">The value to test.</param> |
80 |
/// <returns>True if the value matches, false otherwise.</returns> |
81 |
public bool IsMatch(string name) |
82 |
{ |
83 |
return IsIncluded(name) && (IsExcluded(name) == false); |
84 |
} |
85 |
|
86 |
#endregion |
87 |
|
88 |
/// <summary> |
89 |
/// Test a string to see if it is a valid regular expression. |
90 |
/// </summary> |
91 |
/// <param name="expression">The expression to test.</param> |
92 |
/// <returns>True if expression is a valid <see cref="System.Text.RegularExpressions.Regex"/> false otherwise.</returns> |
93 |
public static bool IsValidExpression(string expression) |
94 |
{ |
95 |
var result = true; |
96 |
try |
97 |
{ |
98 |
var exp = new Regex(expression, RegexOptions.IgnoreCase | RegexOptions.Singleline); |
99 |
} |
100 |
catch |
101 |
{ |
102 |
result = false; |
103 |
} |
104 |
return result; |
105 |
} |
106 |
|
107 |
/// <summary> |
108 |
/// Test an expression to see if it is valid as a filter. |
109 |
/// </summary> |
110 |
/// <param name="toTest">The filter expression to test.</param> |
111 |
/// <returns>True if the expression is valid, false otherwise.</returns> |
112 |
public static bool IsValidFilterExpression(string toTest) |
113 |
{ |
114 |
if (toTest == null) |
115 |
{ |
116 |
throw new ArgumentNullException("toTest"); |
117 |
} |
118 |
|
119 |
var result = true; |
120 |
|
121 |
try |
122 |
{ |
123 |
var items = toTest.Split(';'); |
124 |
for (var i = 0; i < items.Length; ++i) |
125 |
{ |
126 |
if (string.IsNullOrEmpty(items[i])) |
127 |
{ |
128 |
continue; |
129 |
} |
130 |
string toCompile; |
131 |
|
132 |
switch (items[i][0]) |
133 |
{ |
134 |
case '+': |
135 |
toCompile = items[i].Substring(1, items[i].Length - 1); |
136 |
break; |
137 |
case '-': |
138 |
toCompile = items[i].Substring(1, items[i].Length - 1); |
139 |
break; |
140 |
default: |
141 |
toCompile = items[i]; |
142 |
break; |
143 |
} |
144 |
var testRegex = new Regex(toCompile, RegexOptions.IgnoreCase | RegexOptions.Singleline); |
145 |
} |
146 |
} |
147 |
catch (Exception) |
148 |
{ |
149 |
result = false; |
150 |
} |
151 |
|
152 |
return result; |
153 |
} |
154 |
|
155 |
/// <summary> |
156 |
/// Convert this filter to its string equivalent. |
157 |
/// </summary> |
158 |
/// <returns>The string equivalent for this filter.</returns> |
159 |
public override string ToString() |
160 |
{ |
161 |
return filter_; |
162 |
} |
163 |
|
164 |
/// <summary> |
165 |
/// Test a value to see if it is included by the filter. |
166 |
/// </summary> |
167 |
/// <param name="name">The value to test.</param> |
168 |
/// <returns>True if the value is included, false otherwise.</returns> |
169 |
public bool IsIncluded(string name) |
170 |
{ |
171 |
var result = false; |
172 |
if (inclusions_.Count == 0) |
173 |
{ |
174 |
result = true; |
175 |
} |
176 |
else |
177 |
{ |
178 |
foreach (var r in inclusions_) |
179 |
{ |
180 |
if (r.IsMatch(name)) |
181 |
{ |
182 |
result = true; |
183 |
break; |
184 |
} |
185 |
} |
186 |
} |
187 |
return result; |
188 |
} |
189 |
|
190 |
/// <summary> |
191 |
/// Test a value to see if it is excluded by the filter. |
192 |
/// </summary> |
193 |
/// <param name="name">The value to test.</param> |
194 |
/// <returns>True if the value is excluded, false otherwise.</returns> |
195 |
public bool IsExcluded(string name) |
196 |
{ |
197 |
var result = false; |
198 |
foreach (var r in exclusions_) |
199 |
{ |
200 |
if (r.IsMatch(name)) |
201 |
{ |
202 |
result = true; |
203 |
break; |
204 |
} |
205 |
} |
206 |
return result; |
207 |
} |
208 |
|
209 |
/// <summary> |
210 |
/// Compile this filter. |
211 |
/// </summary> |
212 |
private void Compile() |
213 |
{ |
214 |
// TODO: Check to see if combining RE's makes it faster/smaller. |
215 |
// simple scheme would be to have one RE for inclusion and one for exclusion. |
216 |
if (filter_ == null) |
217 |
{ |
218 |
return; |
219 |
} |
220 |
|
221 |
// TODO: Allow for paths to include ';' |
222 |
var items = filter_.Split(';'); |
223 |
for (var i = 0; i < items.Length; ++i) |
224 |
{ |
225 |
if (string.IsNullOrEmpty(items[i])) |
226 |
{ |
227 |
continue; |
228 |
} |
229 |
var include = (items[i][0] != '-'); |
230 |
string toCompile; |
231 |
|
232 |
switch (items[i][0]) |
233 |
{ |
234 |
case '+': |
235 |
toCompile = items[i].Substring(1, items[i].Length - 1); |
236 |
break; |
237 |
case '-': |
238 |
toCompile = items[i].Substring(1, items[i].Length - 1); |
239 |
break; |
240 |
default: |
241 |
toCompile = items[i]; |
242 |
break; |
243 |
} |
244 |
|
245 |
// NOTE: Regular expressions can fail to compile here for a number of reasons that cause an exception |
246 |
// these are left unhandled here as the caller is responsible for ensuring all is valid. |
247 |
// several functions IsValidFilterExpression and IsValidExpression are provided for such checking |
248 |
if (include) |
249 |
{ |
250 |
inclusions_.Add(new Regex(toCompile, RegexOptions.IgnoreCase | RegexOptions.Singleline)); |
251 |
} |
252 |
else |
253 |
{ |
254 |
exclusions_.Add(new Regex(toCompile, RegexOptions.IgnoreCase | RegexOptions.Singleline)); |
255 |
} |
256 |
} |
257 |
} |
258 |
|
259 |
#region Instance Fields |
260 |
|
261 |
private readonly List<Regex> exclusions_; |
262 |
private readonly string filter_; |
263 |
private readonly List<Regex> inclusions_; |
264 |
|
265 |
#endregion |
266 |
} |
267 |
} |