1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612 |
- //#define SelectorTrace
- // FileSelector.cs
- // ------------------------------------------------------------------
- //
- // Copyright (c) 2008-2011 Dino Chiesa.
- // All rights reserved.
- //
- // This code module is part of DotNetZip, a zipfile class library.
- //
- // ------------------------------------------------------------------
- //
- // This code is licensed under the Microsoft Public License.
- // See the file License.txt for the license details.
- // More info on: http://dotnetzip.codeplex.com
- //
- // ------------------------------------------------------------------
- //
- // last saved: <2011-August-05 11:03:11>
- //
- // ------------------------------------------------------------------
- //
- // This module implements a "file selector" that finds files based on a
- // set of inclusion criteria, including filename, size, file time, and
- // potentially file attributes. The criteria are given in a string with
- // a simple expression language. Examples:
- //
- // find all .txt files:
- // name = *.txt
- //
- // shorthand for the above
- // *.txt
- //
- // all files modified after January 1st, 2009
- // mtime > 2009-01-01
- //
- // All .txt files modified after the first of the year
- // name = *.txt AND mtime > 2009-01-01
- //
- // All .txt files modified after the first of the year, or any file with the archive bit set
- // (name = *.txt AND mtime > 2009-01-01) or (attribtues = A)
- //
- // All .txt files or any file greater than 1mb in size
- // (name = *.txt or size > 1mb)
- //
- // and so on.
- // ------------------------------------------------------------------
- using System;
- using System.IO;
- using System.Text;
- using System.Reflection;
- using System.ComponentModel;
- using System.Text.RegularExpressions;
- using System.Collections.Generic;
- #if SILVERLIGHT
- using System.Linq;
- #endif
- namespace Ionic
- {
- /// <summary>
- /// Enumerates the options for a logical conjunction. This enum is intended for use
- /// internally by the FileSelector class.
- /// </summary>
- internal enum LogicalConjunction
- {
- NONE,
- AND,
- OR,
- XOR,
- }
- internal enum WhichTime
- {
- atime,
- mtime,
- ctime,
- }
- internal enum ComparisonOperator
- {
- [Description(">")]
- GreaterThan,
- [Description(">=")]
- GreaterThanOrEqualTo,
- [Description("<")]
- LesserThan,
- [Description("<=")]
- LesserThanOrEqualTo,
- [Description("=")]
- EqualTo,
- [Description("!=")]
- NotEqualTo
- }
- internal abstract partial class SelectionCriterion
- {
- internal virtual bool Verbose
- {
- get;set;
- }
- internal abstract bool Evaluate(string filename);
- [System.Diagnostics.Conditional("SelectorTrace")]
- protected static void CriterionTrace(string format, params object[] args)
- {
- //System.Console.WriteLine(" " + format, args);
- }
- }
- internal partial class SizeCriterion : SelectionCriterion
- {
- internal ComparisonOperator Operator;
- internal Int64 Size;
- public override String ToString()
- {
- StringBuilder sb = new StringBuilder();
- sb.Append("size ").Append(EnumUtil.GetDescription(Operator)).Append(" ").Append(Size.ToString());
- return sb.ToString();
- }
- internal override bool Evaluate(string filename)
- {
- System.IO.FileInfo fi = new System.IO.FileInfo(filename);
- CriterionTrace("SizeCriterion::Evaluate('{0}' [{1}])",
- filename, this.ToString());
- return _Evaluate(fi.Length);
- }
- private bool _Evaluate(Int64 Length)
- {
- bool result = false;
- switch (Operator)
- {
- case ComparisonOperator.GreaterThanOrEqualTo:
- result = Length >= Size;
- break;
- case ComparisonOperator.GreaterThan:
- result = Length > Size;
- break;
- case ComparisonOperator.LesserThanOrEqualTo:
- result = Length <= Size;
- break;
- case ComparisonOperator.LesserThan:
- result = Length < Size;
- break;
- case ComparisonOperator.EqualTo:
- result = Length == Size;
- break;
- case ComparisonOperator.NotEqualTo:
- result = Length != Size;
- break;
- default:
- throw new ArgumentException("Operator");
- }
- return result;
- }
- }
- internal partial class TimeCriterion : SelectionCriterion
- {
- internal ComparisonOperator Operator;
- internal WhichTime Which;
- internal DateTime Time;
- public override String ToString()
- {
- StringBuilder sb = new StringBuilder();
- sb.Append(Which.ToString()).Append(" ").Append(EnumUtil.GetDescription(Operator)).Append(" ").Append(Time.ToString("yyyy-MM-dd-HH:mm:ss"));
- return sb.ToString();
- }
- internal override bool Evaluate(string filename)
- {
- DateTime x;
- switch (Which)
- {
- case WhichTime.atime:
- x = System.IO.File.GetLastAccessTime(filename).ToUniversalTime();
- break;
- case WhichTime.mtime:
- x = System.IO.File.GetLastWriteTime(filename).ToUniversalTime();
- break;
- case WhichTime.ctime:
- x = System.IO.File.GetCreationTime(filename).ToUniversalTime();
- break;
- default:
- throw new ArgumentException("Operator");
- }
- CriterionTrace("TimeCriterion({0},{1})= {2}", filename, Which.ToString(), x);
- return _Evaluate(x);
- }
- private bool _Evaluate(DateTime x)
- {
- bool result = false;
- switch (Operator)
- {
- case ComparisonOperator.GreaterThanOrEqualTo:
- result = (x >= Time);
- break;
- case ComparisonOperator.GreaterThan:
- result = (x > Time);
- break;
- case ComparisonOperator.LesserThanOrEqualTo:
- result = (x <= Time);
- break;
- case ComparisonOperator.LesserThan:
- result = (x < Time);
- break;
- case ComparisonOperator.EqualTo:
- result = (x == Time);
- break;
- case ComparisonOperator.NotEqualTo:
- result = (x != Time);
- break;
- default:
- throw new ArgumentException("Operator");
- }
- CriterionTrace("TimeCriterion: {0}", result);
- return result;
- }
- }
- internal partial class NameCriterion : SelectionCriterion
- {
- private Regex _re;
- private String _regexString;
- internal ComparisonOperator Operator;
- private string _MatchingFileSpec;
- internal virtual string MatchingFileSpec
- {
- set
- {
- // workitem 8245
- if (Directory.Exists(value))
- {
- _MatchingFileSpec = "." + Path.DirectorySeparatorChar + value + Path.DirectorySeparatorChar + "*.*";
- }
- else
- {
- _MatchingFileSpec = value;
- }
- _regexString = "^" +
- Regex.Escape(_MatchingFileSpec)
- .Replace(@"\\\*\.\*", @"\\([^\.]+|.*\.[^\\\.]*)")
- .Replace(@"\.\*", @"\.[^\\\.]*")
- .Replace(@"\*", @".*")
- //.Replace(@"\*", @"[^\\\.]*") // ill-conceived
- .Replace(@"\?", @"[^\\\.]")
- + "$";
- CriterionTrace("NameCriterion regexString({0})", _regexString);
- _re = new Regex(_regexString, RegexOptions.IgnoreCase);
- }
- }
- public override String ToString()
- {
- StringBuilder sb = new StringBuilder();
- sb.Append("name ").Append(EnumUtil.GetDescription(Operator))
- .Append(" '")
- .Append(_MatchingFileSpec)
- .Append("'");
- return sb.ToString();
- }
- internal override bool Evaluate(string filename)
- {
- CriterionTrace("NameCriterion::Evaluate('{0}' pattern[{1}])",
- filename, _MatchingFileSpec);
- return _Evaluate(filename);
- }
- private bool _Evaluate(string fullpath)
- {
- CriterionTrace("NameCriterion::Evaluate({0})", fullpath);
- // No slash in the pattern implicitly means recurse, which means compare to
- // filename only, not full path.
- String f = (_MatchingFileSpec.IndexOf(Path.DirectorySeparatorChar) == -1)
- ? System.IO.Path.GetFileName(fullpath)
- : fullpath; // compare to fullpath
- bool result = _re.IsMatch(f);
- if (Operator != ComparisonOperator.EqualTo)
- result = !result;
- return result;
- }
- }
- internal partial class TypeCriterion : SelectionCriterion
- {
- private char ObjectType; // 'D' = Directory, 'F' = File
- internal ComparisonOperator Operator;
- internal string AttributeString
- {
- get
- {
- return ObjectType.ToString();
- }
- set
- {
- if (value.Length != 1 ||
- (value[0]!='D' && value[0]!='F'))
- throw new ArgumentException("Specify a single character: either D or F");
- ObjectType = value[0];
- }
- }
- public override String ToString()
- {
- StringBuilder sb = new StringBuilder();
- sb.Append("type ").Append(EnumUtil.GetDescription(Operator)).Append(" ").Append(AttributeString);
- return sb.ToString();
- }
- internal override bool Evaluate(string filename)
- {
- CriterionTrace("TypeCriterion::Evaluate({0})", filename);
- bool result = (ObjectType == 'D')
- ? Directory.Exists(filename)
- : File.Exists(filename);
- if (Operator != ComparisonOperator.EqualTo)
- result = !result;
- return result;
- }
- }
- #if !SILVERLIGHT
- internal partial class AttributesCriterion : SelectionCriterion
- {
- private FileAttributes _Attributes;
- internal ComparisonOperator Operator;
- internal string AttributeString
- {
- get
- {
- string result = "";
- if ((_Attributes & FileAttributes.Hidden) != 0)
- result += "H";
- if ((_Attributes & FileAttributes.System) != 0)
- result += "S";
- if ((_Attributes & FileAttributes.ReadOnly) != 0)
- result += "R";
- if ((_Attributes & FileAttributes.Archive) != 0)
- result += "A";
- if ((_Attributes & FileAttributes.ReparsePoint) != 0)
- result += "L";
- if ((_Attributes & FileAttributes.NotContentIndexed) != 0)
- result += "I";
- return result;
- }
- set
- {
- _Attributes = FileAttributes.Normal;
- foreach (char c in value.ToUpper())
- {
- switch (c)
- {
- case 'H':
- if ((_Attributes & FileAttributes.Hidden) != 0)
- throw new ArgumentException(String.Format("Repeated flag. ({0})", c), "value");
- _Attributes |= FileAttributes.Hidden;
- break;
- case 'R':
- if ((_Attributes & FileAttributes.ReadOnly) != 0)
- throw new ArgumentException(String.Format("Repeated flag. ({0})", c), "value");
- _Attributes |= FileAttributes.ReadOnly;
- break;
- case 'S':
- if ((_Attributes & FileAttributes.System) != 0)
- throw new ArgumentException(String.Format("Repeated flag. ({0})", c), "value");
- _Attributes |= FileAttributes.System;
- break;
- case 'A':
- if ((_Attributes & FileAttributes.Archive) != 0)
- throw new ArgumentException(String.Format("Repeated flag. ({0})", c), "value");
- _Attributes |= FileAttributes.Archive;
- break;
- case 'I':
- if ((_Attributes & FileAttributes.NotContentIndexed) != 0)
- throw new ArgumentException(String.Format("Repeated flag. ({0})", c), "value");
- _Attributes |= FileAttributes.NotContentIndexed;
- break;
- case 'L':
- if ((_Attributes & FileAttributes.ReparsePoint) != 0)
- throw new ArgumentException(String.Format("Repeated flag. ({0})", c), "value");
- _Attributes |= FileAttributes.ReparsePoint;
- break;
- default:
- throw new ArgumentException(value);
- }
- }
- }
- }
- public override String ToString()
- {
- StringBuilder sb = new StringBuilder();
- sb.Append("attributes ").Append(EnumUtil.GetDescription(Operator)).Append(" ").Append(AttributeString);
- return sb.ToString();
- }
- private bool _EvaluateOne(FileAttributes fileAttrs, FileAttributes criterionAttrs)
- {
- bool result = false;
- if ((_Attributes & criterionAttrs) == criterionAttrs)
- result = ((fileAttrs & criterionAttrs) == criterionAttrs);
- else
- result = true;
- return result;
- }
- internal override bool Evaluate(string filename)
- {
- // workitem 10191
- if (Directory.Exists(filename))
- {
- // Directories don't have file attributes, so the result
- // of an evaluation is always NO. This gets negated if
- // the operator is NotEqualTo.
- return (Operator != ComparisonOperator.EqualTo);
- }
- #if NETCF && !ANDROID
- FileAttributes fileAttrs = NetCfFile.GetAttributes(filename);
- #else
- FileAttributes fileAttrs = System.IO.File.GetAttributes(filename);
- #endif
- return _Evaluate(fileAttrs);
- }
- private bool _Evaluate(FileAttributes fileAttrs)
- {
- bool result = _EvaluateOne(fileAttrs, FileAttributes.Hidden);
- if (result)
- result = _EvaluateOne(fileAttrs, FileAttributes.System);
- if (result)
- result = _EvaluateOne(fileAttrs, FileAttributes.ReadOnly);
- if (result)
- result = _EvaluateOne(fileAttrs, FileAttributes.Archive);
- if (result)
- result = _EvaluateOne(fileAttrs, FileAttributes.NotContentIndexed);
- if (result)
- result = _EvaluateOne(fileAttrs, FileAttributes.ReparsePoint);
- if (Operator != ComparisonOperator.EqualTo)
- result = !result;
- return result;
- }
- }
- #endif
- internal partial class CompoundCriterion : SelectionCriterion
- {
- internal LogicalConjunction Conjunction;
- internal SelectionCriterion Left;
- private SelectionCriterion _Right;
- internal SelectionCriterion Right
- {
- get { return _Right; }
- set
- {
- _Right = value;
- if (value == null)
- Conjunction = LogicalConjunction.NONE;
- else if (Conjunction == LogicalConjunction.NONE)
- Conjunction = LogicalConjunction.AND;
- }
- }
- internal override bool Evaluate(string filename)
- {
- bool result = Left.Evaluate(filename);
- switch (Conjunction)
- {
- case LogicalConjunction.AND:
- if (result)
- result = Right.Evaluate(filename);
- break;
- case LogicalConjunction.OR:
- if (!result)
- result = Right.Evaluate(filename);
- break;
- case LogicalConjunction.XOR:
- result ^= Right.Evaluate(filename);
- break;
- default:
- throw new ArgumentException("Conjunction");
- }
- return result;
- }
- public override String ToString()
- {
- StringBuilder sb = new StringBuilder();
- sb.Append("(")
- .Append((Left != null) ? Left.ToString() : "null")
- .Append(" ")
- .Append(Conjunction.ToString())
- .Append(" ")
- .Append((Right != null) ? Right.ToString() : "null")
- .Append(")");
- return sb.ToString();
- }
- }
- /// <summary>
- /// FileSelector encapsulates logic that selects files from a source - a zip file
- /// or the filesystem - based on a set of criteria. This class is used internally
- /// by the DotNetZip library, in particular for the AddSelectedFiles() methods.
- /// This class can also be used independently of the zip capability in DotNetZip.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// The FileSelector class is used internally by the ZipFile class for selecting
- /// files for inclusion into the ZipFile, when the <see
- /// cref="Ionic.Zip.ZipFile.AddSelectedFiles(String,String)"/> method, or one of
- /// its overloads, is called. It's also used for the <see
- /// cref="Ionic.Zip.ZipFile.ExtractSelectedEntries(String)"/> methods. Typically, an
- /// application that creates or manipulates Zip archives will not directly
- /// interact with the FileSelector class.
- /// </para>
- ///
- /// <para>
- /// Some applications may wish to use the FileSelector class directly, to
- /// select files from disk volumes based on a set of criteria, without creating or
- /// querying Zip archives. The file selection criteria include: a pattern to
- /// match the filename; the last modified, created, or last accessed time of the
- /// file; the size of the file; and the attributes of the file.
- /// </para>
- ///
- /// <para>
- /// Consult the documentation for <see cref="SelectionCriteria"/>
- /// for more information on specifying the selection criteria.
- /// </para>
- ///
- /// </remarks>
- public partial class FileSelector
- {
- internal SelectionCriterion _Criterion;
- #if NOTUSED
- /// <summary>
- /// The default constructor.
- /// </summary>
- /// <remarks>
- /// Typically, applications won't use this constructor. Instead they'll
- /// call the constructor that accepts a selectionCriteria string. If you
- /// use this constructor, you'll want to set the SelectionCriteria
- /// property on the instance before calling SelectFiles().
- /// </remarks>
- protected FileSelector() { }
- #endif
- /// <summary>
- /// Constructor that allows the caller to specify file selection criteria.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This constructor allows the caller to specify a set of criteria for
- /// selection of files.
- /// </para>
- ///
- /// <para>
- /// See <see cref="FileSelector.SelectionCriteria"/> for a description of
- /// the syntax of the selectionCriteria string.
- /// </para>
- ///
- /// <para>
- /// By default the FileSelector will traverse NTFS Reparse Points. To
- /// change this, use <see cref="FileSelector(String,
- /// bool)">FileSelector(String, bool)</see>.
- /// </para>
- /// </remarks>
- ///
- /// <param name="selectionCriteria">The criteria for file selection.</param>
- public FileSelector(String selectionCriteria)
- : this(selectionCriteria, true)
- {
- }
- /// <summary>
- /// Constructor that allows the caller to specify file selection criteria.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This constructor allows the caller to specify a set of criteria for
- /// selection of files.
- /// </para>
- ///
- /// <para>
- /// See <see cref="FileSelector.SelectionCriteria"/> for a description of
- /// the syntax of the selectionCriteria string.
- /// </para>
- /// </remarks>
- ///
- /// <param name="selectionCriteria">The criteria for file selection.</param>
- /// <param name="traverseDirectoryReparsePoints">
- /// whether to traverse NTFS reparse points (junctions).
- /// </param>
- public FileSelector(String selectionCriteria, bool traverseDirectoryReparsePoints)
- {
- if (!String.IsNullOrEmpty(selectionCriteria))
- _Criterion = _ParseCriterion(selectionCriteria);
- TraverseReparsePoints = traverseDirectoryReparsePoints;
- }
- /// <summary>
- /// The string specifying which files to include when retrieving.
- /// </summary>
- /// <remarks>
- ///
- /// <para>
- /// Specify the criteria in statements of 3 elements: a noun, an operator,
- /// and a value. Consider the string "name != *.doc" . The noun is
- /// "name". The operator is "!=", implying "Not Equal". The value is
- /// "*.doc". That criterion, in English, says "all files with a name that
- /// does not end in the .doc extension."
- /// </para>
- ///
- /// <para>
- /// Supported nouns include "name" (or "filename") for the filename;
- /// "atime", "mtime", and "ctime" for last access time, last modfied time,
- /// and created time of the file, respectively; "attributes" (or "attrs")
- /// for the file attributes; "size" (or "length") for the file length
- /// (uncompressed); and "type" for the type of object, either a file or a
- /// directory. The "attributes", "type", and "name" nouns all support =
- /// and != as operators. The "size", "atime", "mtime", and "ctime" nouns
- /// support = and !=, and >, >=, <, <= as well. The times are
- /// taken to be expressed in local time.
- /// </para>
- ///
- /// <para>
- /// Specify values for the file attributes as a string with one or more of
- /// the characters H,R,S,A,I,L in any order, implying file attributes of
- /// Hidden, ReadOnly, System, Archive, NotContextIndexed, and ReparsePoint
- /// (symbolic link) respectively.
- /// </para>
- ///
- /// <para>
- /// To specify a time, use YYYY-MM-DD-HH:mm:ss or YYYY/MM/DD-HH:mm:ss as
- /// the format. If you omit the HH:mm:ss portion, it is assumed to be
- /// 00:00:00 (midnight).
- /// </para>
- ///
- /// <para>
- /// The value for a size criterion is expressed in integer quantities of
- /// bytes, kilobytes (use k or kb after the number), megabytes (m or mb),
- /// or gigabytes (g or gb).
- /// </para>
- ///
- /// <para>
- /// The value for a name is a pattern to match against the filename,
- /// potentially including wildcards. The pattern follows CMD.exe glob
- /// rules: * implies one or more of any character, while ? implies one
- /// character. If the name pattern contains any slashes, it is matched to
- /// the entire filename, including the path; otherwise, it is matched
- /// against only the filename without the path. This means a pattern of
- /// "*\*.*" matches all files one directory level deep, while a pattern of
- /// "*.*" matches all files in all directories.
- /// </para>
- ///
- /// <para>
- /// To specify a name pattern that includes spaces, use single quotes
- /// around the pattern. A pattern of "'* *.*'" will match all files that
- /// have spaces in the filename. The full criteria string for that would
- /// be "name = '* *.*'" .
- /// </para>
- ///
- /// <para>
- /// The value for a type criterion is either F (implying a file) or D
- /// (implying a directory).
- /// </para>
- ///
- /// <para>
- /// Some examples:
- /// </para>
- ///
- /// <list type="table">
- /// <listheader>
- /// <term>criteria</term>
- /// <description>Files retrieved</description>
- /// </listheader>
- ///
- /// <item>
- /// <term>name != *.xls </term>
- /// <description>any file with an extension that is not .xls
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>name = *.mp3 </term>
- /// <description>any file with a .mp3 extension.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>*.mp3</term>
- /// <description>(same as above) any file with a .mp3 extension.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>attributes = A </term>
- /// <description>all files whose attributes include the Archive bit.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>attributes != H </term>
- /// <description>all files whose attributes do not include the Hidden bit.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>mtime > 2009-01-01</term>
- /// <description>all files with a last modified time after January 1st, 2009.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>ctime > 2009/01/01-03:00:00</term>
- /// <description>all files with a created time after 3am (local time),
- /// on January 1st, 2009.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>size > 2gb</term>
- /// <description>all files whose uncompressed size is greater than 2gb.
- /// </description>
- /// </item>
- ///
- /// <item>
- /// <term>type = D</term>
- /// <description>all directories in the filesystem. </description>
- /// </item>
- ///
- /// </list>
- ///
- /// <para>
- /// You can combine criteria with the conjunctions AND, OR, and XOR. Using
- /// a string like "name = *.txt AND size >= 100k" for the
- /// selectionCriteria retrieves entries whose names end in .txt, and whose
- /// uncompressed size is greater than or equal to 100 kilobytes.
- /// </para>
- ///
- /// <para>
- /// For more complex combinations of criteria, you can use parenthesis to
- /// group clauses in the boolean logic. Absent parenthesis, the
- /// precedence of the criterion atoms is determined by order of
- /// appearance. Unlike the C# language, the AND conjunction does not take
- /// precendence over the logical OR. This is important only in strings
- /// that contain 3 or more criterion atoms. In other words, "name = *.txt
- /// and size > 1000 or attributes = H" implies "((name = *.txt AND size
- /// > 1000) OR attributes = H)" while "attributes = H OR name = *.txt
- /// and size > 1000" evaluates to "((attributes = H OR name = *.txt)
- /// AND size > 1000)". When in doubt, use parenthesis.
- /// </para>
- ///
- /// <para>
- /// Using time properties requires some extra care. If you want to
- /// retrieve all entries that were last updated on 2009 February 14,
- /// specify "mtime >= 2009-02-14 AND mtime < 2009-02-15". Read this
- /// to say: all files updated after 12:00am on February 14th, until
- /// 12:00am on February 15th. You can use the same bracketing approach to
- /// specify any time period - a year, a month, a week, and so on.
- /// </para>
- ///
- /// <para>
- /// The syntax allows one special case: if you provide a string with no
- /// spaces, it is treated as a pattern to match for the filename.
- /// Therefore a string like "*.xls" will be equivalent to specifying "name
- /// = *.xls". This "shorthand" notation does not work with compound
- /// criteria.
- /// </para>
- ///
- /// <para>
- /// There is no logic in this class that insures that the inclusion
- /// criteria are internally consistent. For example, it's possible to
- /// specify criteria that says the file must have a size of less than 100
- /// bytes, as well as a size that is greater than 1000 bytes. Obviously
- /// no file will ever satisfy such criteria, but this class does not check
- /// for or detect such inconsistencies.
- /// </para>
- ///
- /// </remarks>
- ///
- /// <exception cref="System.Exception">
- /// Thrown in the setter if the value has an invalid syntax.
- /// </exception>
- public String SelectionCriteria
- {
- get
- {
- if (_Criterion == null) return null;
- return _Criterion.ToString();
- }
- set
- {
- if (value == null) _Criterion = null;
- else if (value.Trim() == "") _Criterion = null;
- else
- _Criterion = _ParseCriterion(value);
- }
- }
- /// <summary>
- /// Indicates whether searches will traverse NTFS reparse points, like Junctions.
- /// </summary>
- public bool TraverseReparsePoints
- {
- get; set;
- }
- private enum ParseState
- {
- Start,
- OpenParen,
- CriterionDone,
- ConjunctionPending,
- Whitespace,
- }
- private static class RegexAssertions
- {
- public static readonly String PrecededByOddNumberOfSingleQuotes = "(?<=(?:[^']*'[^']*')*'[^']*)";
- public static readonly String FollowedByOddNumberOfSingleQuotesAndLineEnd = "(?=[^']*'(?:[^']*'[^']*')*[^']*$)";
- public static readonly String PrecededByEvenNumberOfSingleQuotes = "(?<=(?:[^']*'[^']*')*[^']*)";
- public static readonly String FollowedByEvenNumberOfSingleQuotesAndLineEnd = "(?=(?:[^']*'[^']*')*[^']*$)";
- }
- private static string NormalizeCriteriaExpression(string source)
- {
- // The goal here is to normalize the criterion expression. At output, in
- // the transformed criterion string, every significant syntactic element
- // - a property element, grouping paren for the boolean logic, operator
- // ( = < > != ), conjunction, or property value - will be separated from
- // its neighbors by at least one space. Thus,
- //
- // before after
- // -------------------------------------------------------------------
- // name=*.txt name = *.txt
- // (size>100)AND(name=*.txt) ( size > 100 ) AND ( name = *.txt )
- //
- // This is relatively straightforward using regular expression
- // replacement. This method applies a distinct regex pattern and
- // corresponding replacement string for each one of a number of cases:
- // an open paren followed by a word; a word followed by a close-paren; a
- // pair of open parens; a close paren followed by a word (which should
- // then be followed by an open paren). And so on. These patterns and
- // replacements are all stored in prPairs. By applying each of these
- // regex replacements in turn, we get the transformed string. Easy.
- //
- // The resulting "normalized" criterion string, is then used as the
- // subject that gets parsed, by splitting the string into tokens that
- // are separated by spaces. Here, there's a twist. The spaces within
- // single-quote delimiters do not delimit distinct tokens. So, this
- // normalization method temporarily replaces those spaces with
- // ASCII 6 (0x06), a control character which is not a legal
- // character in a filename. The parsing logic that happens later will
- // revert that change, restoring the original value of the filename
- // specification.
- //
- // To illustrate, for a "before" string of [(size>100)AND(name='Name
- // (with Parens).txt')] , the "after" string is [( size > 100 ) AND
- // ( name = 'Name\u0006(with\u0006Parens).txt' )].
- //
- string[][] prPairs =
- {
- // A. opening double parens - insert a space between them
- new string[] { @"([^']*)\(\(([^']+)", "$1( ($2" },
- // B. closing double parens - insert a space between
- new string[] { @"(.)\)\)", "$1) )" },
- // C. single open paren with a following word - insert a space between
- new string[] { @"\(([^'\f\n\r\t\v\x85\p{Z}])", "( $1" },
- // D. single close paren with a preceding word - insert a space between the two
- new string[] { @"(\S)\)", "$1 )" },
- // E. close paren at line start?, insert a space before the close paren
- // this seems like a degenerate case. I don't recall why it's here.
- new string[] { @"^\)", " )" },
- // F. a word (likely a conjunction) followed by an open paren - insert a space between
- new string[] { @"(\S)\(", "$1 (" },
- // G. single close paren followed by word - insert a paren after close paren
- new string[] { @"\)([^'\f\n\r\t\v\x85\p{Z}])", ") $1" },
- // H. insert space between = and a following single quote
- //new string[] { @"(=|!=)('[^']*')", "$1 $2" },
- new string[] { @"(=)('[^']*')", "$1 $2" },
- // I. insert space between property names and the following operator
- //new string[] { @"([^ ])([><(?:!=)=])", "$1 $2" },
- new string[] { @"([^ !><])(>|<|!=|=)", "$1 $2" },
- // J. insert spaces between operators and the following values
- //new string[] { @"([><(?:!=)=])([^ ])", "$1 $2" },
- new string[] { @"(>|<|!=|=)([^ =])", "$1 $2" },
- // K. replace fwd slash with backslash
- new string[] { @"/", "\\" },
- };
- string interim = source;
- for (int i=0; i < prPairs.Length; i++)
- {
- //char caseIdx = (char)('A' + i);
- string pattern = RegexAssertions.PrecededByEvenNumberOfSingleQuotes +
- prPairs[i][0] +
- RegexAssertions.FollowedByEvenNumberOfSingleQuotesAndLineEnd;
- interim = Regex.Replace(interim, pattern, prPairs[i][1]);
- }
- // match a fwd slash, followed by an odd number of single quotes.
- // This matches fwd slashes only inside a pair of single quote delimiters,
- // eg, a filename. This must be done as well as the case above, to handle
- // filenames specified inside quotes as well as filenames without quotes.
- var regexPattern = @"/" +
- RegexAssertions.FollowedByOddNumberOfSingleQuotesAndLineEnd;
- // replace with backslash
- interim = Regex.Replace(interim, regexPattern, "\\");
- // match a space, followed by an odd number of single quotes.
- // This matches spaces only inside a pair of single quote delimiters.
- regexPattern = " " +
- RegexAssertions.FollowedByOddNumberOfSingleQuotesAndLineEnd;
- // Replace all spaces that appear inside single quotes, with
- // ascii 6. This allows a split on spaces to get tokens in
- // the expression. The split will not split any filename or
- // wildcard that appears within single quotes. After tokenizing, we
- // need to replace ascii 6 with ascii 32 to revert the
- // spaces within quotes.
- return Regex.Replace(interim, regexPattern, "\u0006");
- }
- private static SelectionCriterion _ParseCriterion(String s)
- {
- if (s == null) return null;
- // inject spaces after open paren and before close paren, etc
- s = NormalizeCriteriaExpression(s);
- // no spaces in the criteria is shorthand for filename glob
- if (s.IndexOf(" ") == -1)
- s = "name = " + s;
- // split the expression into tokens
- string[] tokens = s.Trim().Split(' ', '\t');
- if (tokens.Length < 3) throw new ArgumentException(s);
- SelectionCriterion current = null;
- LogicalConjunction pendingConjunction = LogicalConjunction.NONE;
- ParseState state;
- var stateStack = new System.Collections.Generic.Stack<ParseState>();
- var critStack = new System.Collections.Generic.Stack<SelectionCriterion>();
- stateStack.Push(ParseState.Start);
- for (int i = 0; i < tokens.Length; i++)
- {
- string tok1 = tokens[i].ToLower();
- switch (tok1)
- {
- case "and":
- case "xor":
- case "or":
- state = stateStack.Peek();
- if (state != ParseState.CriterionDone)
- throw new ArgumentException(String.Join(" ", tokens, i, tokens.Length - i));
- if (tokens.Length <= i + 3)
- throw new ArgumentException(String.Join(" ", tokens, i, tokens.Length - i));
- pendingConjunction = (LogicalConjunction)Enum.Parse(typeof(LogicalConjunction), tokens[i].ToUpper(), true);
- current = new CompoundCriterion { Left = current, Right = null, Conjunction = pendingConjunction };
- stateStack.Push(state);
- stateStack.Push(ParseState.ConjunctionPending);
- critStack.Push(current);
- break;
- case "(":
- state = stateStack.Peek();
- if (state != ParseState.Start && state != ParseState.ConjunctionPending && state != ParseState.OpenParen)
- throw new ArgumentException(String.Join(" ", tokens, i, tokens.Length - i));
- if (tokens.Length <= i + 4)
- throw new ArgumentException(String.Join(" ", tokens, i, tokens.Length - i));
- stateStack.Push(ParseState.OpenParen);
- break;
- case ")":
- state = stateStack.Pop();
- if (stateStack.Peek() != ParseState.OpenParen)
- throw new ArgumentException(String.Join(" ", tokens, i, tokens.Length - i));
- stateStack.Pop();
- stateStack.Push(ParseState.CriterionDone);
- break;
- case "atime":
- case "ctime":
- case "mtime":
- if (tokens.Length <= i + 2)
- throw new ArgumentException(String.Join(" ", tokens, i, tokens.Length - i));
- DateTime t;
- try
- {
- t = DateTime.ParseExact(tokens[i + 2], "yyyy-MM-dd-HH:mm:ss", null);
- }
- catch (FormatException)
- {
- try
- {
- t = DateTime.ParseExact(tokens[i + 2], "yyyy/MM/dd-HH:mm:ss", null);
- }
- catch (FormatException)
- {
- try
- {
- t = DateTime.ParseExact(tokens[i + 2], "yyyy/MM/dd", null);
- }
- catch (FormatException)
- {
- try
- {
- t = DateTime.ParseExact(tokens[i + 2], "MM/dd/yyyy", null);
- }
- catch (FormatException)
- {
- t = DateTime.ParseExact(tokens[i + 2], "yyyy-MM-dd", null);
- }
- }
- }
- }
- t= DateTime.SpecifyKind(t, DateTimeKind.Local).ToUniversalTime();
- current = new TimeCriterion
- {
- Which = (WhichTime)Enum.Parse(typeof(WhichTime), tokens[i], true),
- Operator = (ComparisonOperator)EnumUtil.Parse(typeof(ComparisonOperator), tokens[i + 1]),
- Time = t
- };
- i += 2;
- stateStack.Push(ParseState.CriterionDone);
- break;
- case "length":
- case "size":
- if (tokens.Length <= i + 2)
- throw new ArgumentException(String.Join(" ", tokens, i, tokens.Length - i));
- Int64 sz = 0;
- string v = tokens[i + 2];
- if (v.ToUpper().EndsWith("K"))
- sz = Int64.Parse(v.Substring(0, v.Length - 1)) * 1024;
- else if (v.ToUpper().EndsWith("KB"))
- sz = Int64.Parse(v.Substring(0, v.Length - 2)) * 1024;
- else if (v.ToUpper().EndsWith("M"))
- sz = Int64.Parse(v.Substring(0, v.Length - 1)) * 1024 * 1024;
- else if (v.ToUpper().EndsWith("MB"))
- sz = Int64.Parse(v.Substring(0, v.Length - 2)) * 1024 * 1024;
- else if (v.ToUpper().EndsWith("G"))
- sz = Int64.Parse(v.Substring(0, v.Length - 1)) * 1024 * 1024 * 1024;
- else if (v.ToUpper().EndsWith("GB"))
- sz = Int64.Parse(v.Substring(0, v.Length - 2)) * 1024 * 1024 * 1024;
- else sz = Int64.Parse(tokens[i + 2]);
- current = new SizeCriterion
- {
- Size = sz,
- Operator = (ComparisonOperator)EnumUtil.Parse(typeof(ComparisonOperator), tokens[i + 1])
- };
- i += 2;
- stateStack.Push(ParseState.CriterionDone);
- break;
- case "filename":
- case "name":
- {
- if (tokens.Length <= i + 2)
- throw new ArgumentException(String.Join(" ", tokens, i, tokens.Length - i));
- ComparisonOperator c =
- (ComparisonOperator)EnumUtil.Parse(typeof(ComparisonOperator), tokens[i + 1]);
- if (c != ComparisonOperator.NotEqualTo && c != ComparisonOperator.EqualTo)
- throw new ArgumentException(String.Join(" ", tokens, i, tokens.Length - i));
- string m = tokens[i + 2];
- // handle single-quoted filespecs (used to include
- // spaces in filename patterns)
- if (m.StartsWith("'") && m.EndsWith("'"))
- {
- // trim off leading and trailing single quotes and
- // revert the control characters to spaces.
- m = m.Substring(1, m.Length - 2)
- .Replace("\u0006", " ");
- }
- // if (m.StartsWith("'"))
- // m = m.Replace("\u0006", " ");
- //Fix for Unix -> NormalizeCriteriaExpression replaces all slashes with backslashes
- if (Path.DirectorySeparatorChar == '/')
- m = m.Replace('\\', Path.DirectorySeparatorChar);
- current = new NameCriterion
- {
- MatchingFileSpec = m,
- Operator = c
- };
- i += 2;
- stateStack.Push(ParseState.CriterionDone);
- }
- break;
- #if !SILVERLIGHT
- case "attrs":
- case "attributes":
- #endif
- case "type":
- {
- if (tokens.Length <= i + 2)
- throw new ArgumentException(String.Join(" ", tokens, i, tokens.Length - i));
- ComparisonOperator c =
- (ComparisonOperator)EnumUtil.Parse(typeof(ComparisonOperator), tokens[i + 1]);
- if (c != ComparisonOperator.NotEqualTo && c != ComparisonOperator.EqualTo)
- throw new ArgumentException(String.Join(" ", tokens, i, tokens.Length - i));
- #if SILVERLIGHT
- current = (SelectionCriterion) new TypeCriterion
- {
- AttributeString = tokens[i + 2],
- Operator = c
- };
- #else
- current = (tok1 == "type")
- ? (SelectionCriterion) new TypeCriterion
- {
- AttributeString = tokens[i + 2],
- Operator = c
- }
- : (SelectionCriterion) new AttributesCriterion
- {
- AttributeString = tokens[i + 2],
- Operator = c
- };
- #endif
- i += 2;
- stateStack.Push(ParseState.CriterionDone);
- }
- break;
- case "":
- // NOP
- stateStack.Push(ParseState.Whitespace);
- break;
- default:
- throw new ArgumentException("'" + tokens[i] + "'");
- }
- state = stateStack.Peek();
- if (state == ParseState.CriterionDone)
- {
- stateStack.Pop();
- if (stateStack.Peek() == ParseState.ConjunctionPending)
- {
- while (stateStack.Peek() == ParseState.ConjunctionPending)
- {
- var cc = critStack.Pop() as CompoundCriterion;
- cc.Right = current;
- current = cc; // mark the parent as current (walk up the tree)
- stateStack.Pop(); // the conjunction is no longer pending
- state = stateStack.Pop();
- if (state != ParseState.CriterionDone)
- throw new ArgumentException("??");
- }
- }
- else stateStack.Push(ParseState.CriterionDone); // not sure?
- }
- if (state == ParseState.Whitespace)
- stateStack.Pop();
- }
- return current;
- }
- /// <summary>
- /// Returns a string representation of the FileSelector object.
- /// </summary>
- /// <returns>The string representation of the boolean logic statement of the file
- /// selection criteria for this instance. </returns>
- public override String ToString()
- {
- return "FileSelector("+_Criterion.ToString()+")";
- }
- private bool Evaluate(string filename)
- {
- // dinoch - Thu, 11 Feb 2010 18:34
- SelectorTrace("Evaluate({0})", filename);
- bool result = _Criterion.Evaluate(filename);
- return result;
- }
- [System.Diagnostics.Conditional("SelectorTrace")]
- private void SelectorTrace(string format, params object[] args)
- {
- if (_Criterion != null && _Criterion.Verbose)
- System.Console.WriteLine(format, args);
- }
- /// <summary>
- /// Returns the names of the files in the specified directory
- /// that fit the selection criteria specified in the FileSelector.
- /// </summary>
- ///
- /// <remarks>
- /// This is equivalent to calling <see cref="SelectFiles(String, bool)"/>
- /// with recurseDirectories = false.
- /// </remarks>
- ///
- /// <param name="directory">
- /// The name of the directory over which to apply the FileSelector
- /// criteria.
- /// </param>
- ///
- /// <returns>
- /// A collection of strings containing fully-qualified pathnames of files
- /// that match the criteria specified in the FileSelector instance.
- /// </returns>
- public System.Collections.Generic.ICollection<String> SelectFiles(String directory)
- {
- return SelectFiles(directory, false);
- }
- /// <summary>
- /// Returns the names of the files in the specified directory that fit the
- /// selection criteria specified in the FileSelector, optionally recursing
- /// through subdirectories.
- /// </summary>
- ///
- /// <remarks>
- /// This method applies the file selection criteria contained in the
- /// FileSelector to the files contained in the given directory, and
- /// returns the names of files that conform to the criteria.
- /// </remarks>
- ///
- /// <param name="directory">
- /// The name of the directory over which to apply the FileSelector
- /// criteria.
- /// </param>
- ///
- /// <param name="recurseDirectories">
- /// Whether to recurse through subdirectories when applying the file
- /// selection criteria.
- /// </param>
- ///
- /// <returns>
- /// A collection of strings containing fully-qualified pathnames of files
- /// that match the criteria specified in the FileSelector instance.
- /// </returns>
- public System.Collections.ObjectModel.ReadOnlyCollection<String>
- SelectFiles(String directory,
- bool recurseDirectories)
- {
- if (_Criterion == null)
- throw new ArgumentException("SelectionCriteria has not been set");
- var list = new List<String>();
- try
- {
- if (Directory.Exists(directory))
- {
- String[] filenames = Directory.GetFiles(directory);
- // add the files:
- foreach (String filename in filenames)
- {
- if (Evaluate(filename))
- list.Add(filename);
- }
- if (recurseDirectories)
- {
- // add the subdirectories:
- String[] dirnames = Directory.GetDirectories(directory);
- foreach (String dir in dirnames)
- {
- if (this.TraverseReparsePoints
- #if !SILVERLIGHT
- || ((File.GetAttributes(dir) & FileAttributes.ReparsePoint) == 0)
- #endif
- )
- {
- // workitem 10191
- if (Evaluate(dir)) list.Add(dir);
- list.AddRange(this.SelectFiles(dir, recurseDirectories));
- }
- }
- }
- }
- }
- // can get System.UnauthorizedAccessException here
- catch (System.UnauthorizedAccessException)
- {
- }
- catch (System.IO.IOException)
- {
- }
- return list.AsReadOnly();
- }
- }
- /// <summary>
- /// Summary description for EnumUtil.
- /// </summary>
- internal sealed class EnumUtil
- {
- private EnumUtil() { }
- /// <summary>
- /// Returns the value of the DescriptionAttribute if the specified Enum
- /// value has one. If not, returns the ToString() representation of the
- /// Enum value.
- /// </summary>
- /// <param name="value">The Enum to get the description for</param>
- /// <returns></returns>
- internal static string GetDescription(System.Enum value)
- {
- FieldInfo fi = value.GetType().GetField(value.ToString());
- var attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
- if (attributes.Length > 0)
- return attributes[0].Description;
- else
- return value.ToString();
- }
- /// <summary>
- /// Converts the string representation of the name or numeric value of one
- /// or more enumerated constants to an equivalent enumerated object.
- /// Note: use the DescriptionAttribute on enum values to enable this.
- /// </summary>
- /// <param name="enumType">The System.Type of the enumeration.</param>
- /// <param name="stringRepresentation">
- /// A string containing the name or value to convert.
- /// </param>
- /// <returns></returns>
- internal static object Parse(Type enumType, string stringRepresentation)
- {
- return Parse(enumType, stringRepresentation, false);
- }
- #if SILVERLIGHT
- public static System.Enum[] GetEnumValues(Type type)
- {
- if (!type.IsEnum)
- throw new ArgumentException("not an enum");
- return (
- from field in type.GetFields(BindingFlags.Public | BindingFlags.Static)
- where field.IsLiteral
- select (System.Enum)field.GetValue(null)
- ).ToArray();
- }
- public static string[] GetEnumStrings<T>()
- {
- var type = typeof(T);
- if (!type.IsEnum)
- throw new ArgumentException("not an enum");
- return (
- from field in type.GetFields(BindingFlags.Public | BindingFlags.Static)
- where field.IsLiteral
- select field.Name
- ).ToArray();
- }
- #endif
- /// <summary>
- /// Converts the string representation of the name or numeric value of one
- /// or more enumerated constants to an equivalent enumerated object. A
- /// parameter specified whether the operation is case-sensitive. Note:
- /// use the DescriptionAttribute on enum values to enable this.
- /// </summary>
- /// <param name="enumType">The System.Type of the enumeration.</param>
- /// <param name="stringRepresentation">
- /// A string containing the name or value to convert.
- /// </param>
- /// <param name="ignoreCase">
- /// Whether the operation is case-sensitive or not.</param>
- /// <returns></returns>
- internal static object Parse(Type enumType, string stringRepresentation, bool ignoreCase)
- {
- if (ignoreCase)
- stringRepresentation = stringRepresentation.ToLower();
- #if SILVERLIGHT
- foreach (System.Enum enumVal in GetEnumValues(enumType))
- #else
- foreach (System.Enum enumVal in System.Enum.GetValues(enumType))
- #endif
- {
- string description = GetDescription(enumVal);
- if (ignoreCase)
- description = description.ToLower();
- if (description == stringRepresentation)
- return enumVal;
- }
- return System.Enum.Parse(enumType, stringRepresentation, ignoreCase);
- }
- }
- #if DEMO
- public class DemonstrateFileSelector
- {
- private string _directory;
- private bool _recurse;
- private bool _traverse;
- private bool _verbose;
- private string _selectionCriteria;
- private FileSelector f;
- public DemonstrateFileSelector()
- {
- this._directory = ".";
- this._recurse = true;
- }
- public DemonstrateFileSelector(string[] args) : this()
- {
- for (int i = 0; i < args.Length; i++)
- {
- switch(args[i])
- {
- case"-?":
- Usage();
- Environment.Exit(0);
- break;
- case "-d":
- i++;
- if (args.Length <= i)
- throw new ArgumentException("-directory");
- this._directory = args[i];
- break;
- case "-norecurse":
- this._recurse = false;
- break;
- case "-j-":
- this._traverse = false;
- break;
- case "-j+":
- this._traverse = true;
- break;
- case "-v":
- this._verbose = true;
- break;
- default:
- if (this._selectionCriteria != null)
- throw new ArgumentException(args[i]);
- this._selectionCriteria = args[i];
- break;
- }
- if (this._selectionCriteria != null)
- this.f = new FileSelector(this._selectionCriteria);
- }
- }
- public static void Main(string[] args)
- {
- try
- {
- Console.WriteLine();
- new DemonstrateFileSelector(args).Run();
- }
- catch (Exception exc1)
- {
- Console.WriteLine("Exception: {0}", exc1.ToString());
- Usage();
- }
- }
- public void Run()
- {
- if (this.f == null)
- this.f = new FileSelector("name = *.jpg AND (size > 1000 OR atime < 2009-02-14-01:00:00)");
- this.f.TraverseReparsePoints = _traverse;
- this.f.Verbose = this._verbose;
- Console.WriteLine();
- Console.WriteLine(new String(':', 88));
- Console.WriteLine("Selecting files:\n" + this.f.ToString());
- var files = this.f.SelectFiles(this._directory, this._recurse);
- if (files.Count == 0)
- {
- Console.WriteLine("no files.");
- }
- else
- {
- Console.WriteLine("files: {0}", files.Count);
- foreach (string file in files)
- {
- Console.WriteLine(" " + file);
- }
- }
- }
- public static void Usage()
- {
- Console.WriteLine("FileSelector: select files based on selection criteria.\n");
- Console.WriteLine("Usage:\n FileSelector <selectionCriteria> [options]\n" +
- "\n" +
- " -d <dir> directory to select from (Default .)\n" +
- " -norecurse don't recurse into subdirs\n" +
- " -j- don't traverse junctions\n" +
- " -v verbose output\n");
- }
- }
- #endif
- }
|