3 // Copyright 2005 John Reilly
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.
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.
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.
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
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.
38 using System.Collections.Generic;
39 using System.Text.RegularExpressions;
41 namespace ICSharpCode.SharpZipLib.Silverlight.Core
44 /// NameFilter is a string matching class which allows for both positive and negative
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.
53 /// <example>The following expression includes all name ending in '.dat' with the exception of 'dummy.dat'
54 /// "+\.dat$;-^dummy\.dat$"
56 public class NameFilter : IScanFilter
61 /// Construct an instance based on the filter expression passed
63 /// <param name="filter">The filter expression.</param>
64 public NameFilter(string filter)
67 inclusions_ = new List<Regex>();
68 exclusions_ = new List<Regex>();
74 #region IScanFilter Members
77 /// Test a value to see if it matches the filter.
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)
83 return IsIncluded(name) && (IsExcluded(name) == false);
89 /// Test a string to see if it is a valid regular expression.
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)
98 var exp = new Regex(expression, RegexOptions.IgnoreCase | RegexOptions.Singleline);
108 /// Test an expression to see if it is valid as a filter.
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)
116 throw new ArgumentNullException("toTest");
123 var items = toTest.Split(';');
124 for (var i = 0; i < items.Length; ++i)
126 if (string.IsNullOrEmpty(items[i]))
135 toCompile = items[i].Substring(1, items[i].Length - 1);
138 toCompile = items[i].Substring(1, items[i].Length - 1);
141 toCompile = items[i];
144 var testRegex = new Regex(toCompile, RegexOptions.IgnoreCase | RegexOptions.Singleline);
156 /// Convert this filter to its string equivalent.
158 /// <returns>The string equivalent for this filter.</returns>
159 public override string ToString()
165 /// Test a value to see if it is included by the filter.
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)
172 if (inclusions_.Count == 0)
178 foreach (var r in inclusions_)
191 /// Test a value to see if it is excluded by the filter.
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)
198 foreach (var r in exclusions_)
210 /// Compile this filter.
212 private void Compile()
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.
221 // TODO: Allow for paths to include ';'
222 var items = filter_.Split(';');
223 for (var i = 0; i < items.Length; ++i)
225 if (string.IsNullOrEmpty(items[i]))
229 var include = (items[i][0] != '-');
235 toCompile = items[i].Substring(1, items[i].Length - 1);
238 toCompile = items[i].Substring(1, items[i].Length - 1);
241 toCompile = items[i];
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
250 inclusions_.Add(new Regex(toCompile, RegexOptions.IgnoreCase | RegexOptions.Singleline));
254 exclusions_.Add(new Regex(toCompile, RegexOptions.IgnoreCase | RegexOptions.Singleline));
259 #region Instance Fields
261 private readonly List<Regex> exclusions_;
262 private readonly string filter_;
263 private readonly List<Regex> inclusions_;