| // FileSystemScanner.cs | 
| // | 
| // Copyright 2005 John Reilly | 
| // | 
| // This program is free software; you can redistribute it and/or | 
| // modify it under the terms of the GNU General Public License | 
| // as published by the Free Software Foundation; either version 2 | 
| // of the License, or (at your option) any later version. | 
| // | 
| // This program is distributed in the hope that it will be useful, | 
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
| // GNU General Public License for more details. | 
| // | 
| // You should have received a copy of the GNU General Public License | 
| // along with this program; if not, write to the Free Software | 
| // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. | 
| // | 
| // Linking this library statically or dynamically with other modules is | 
| // making a combined work based on this library.  Thus, the terms and | 
| // conditions of the GNU General Public License cover the whole | 
| // combination. | 
| //  | 
| // As a special exception, the copyright holders of this library give you | 
| // permission to link this library with independent modules to produce an | 
| // executable, regardless of the license terms of these independent | 
| // modules, and to copy and distribute the resulting executable under | 
| // terms of your choice, provided that you also meet, for each linked | 
| // independent module, the terms and conditions of the license of that | 
| // module.  An independent module is a module which is not derived from | 
| // or based on this library.  If you modify this library, you may extend | 
| // this exception to your version of the library, but you are not | 
| // obligated to do so.  If you do not wish to do so, delete this | 
| // exception statement from your version. | 
|   | 
|   | 
| using System; | 
|   | 
| namespace ICSharpCode.SharpZipLib.Core | 
| { | 
|     #region EventArgs | 
|     /// <summary> | 
|     /// Event arguments for scanning. | 
|     /// </summary> | 
|     public class ScanEventArgs : EventArgs | 
|     { | 
|         #region Constructors | 
|         /// <summary> | 
|         /// Initialise a new instance of <see cref="ScanEventArgs"/> | 
|         /// </summary> | 
|         /// <param name="name">The file or directory name.</param> | 
|         public ScanEventArgs(string name) | 
|         { | 
|             name_ = name; | 
|         } | 
|         #endregion | 
|          | 
|         /// <summary> | 
|         /// The file or directory name for this event. | 
|         /// </summary> | 
|         public string Name | 
|         { | 
|             get { return name_; } | 
|         } | 
|          | 
|         /// <summary> | 
|         /// Get set a value indicating if scanning should continue or not. | 
|         /// </summary> | 
|         public bool ContinueRunning | 
|         { | 
|             get { return continueRunning_; } | 
|             set { continueRunning_ = value; } | 
|         } | 
|          | 
|         #region Instance Fields | 
|         string name_; | 
|         bool continueRunning_ = true; | 
|         #endregion | 
|     } | 
|   | 
|     /// <summary> | 
|     /// Event arguments during processing of a single file or directory. | 
|     /// </summary> | 
|     public class ProgressEventArgs : EventArgs | 
|     { | 
|         #region Constructors | 
|         /// <summary> | 
|         /// Initialise a new instance of <see cref="ScanEventArgs"/> | 
|         /// </summary> | 
|         /// <param name="name">The file or directory name if known.</param> | 
|         /// <param name="processed">The number of bytes processed so far</param> | 
|         /// <param name="target">The total number of bytes to process, 0 if not known</param> | 
|         public ProgressEventArgs(string name, long processed, long target) | 
|         { | 
|             name_ = name; | 
|             processed_ = processed; | 
|             target_ = target; | 
|         } | 
|         #endregion | 
|          | 
|         /// <summary> | 
|         /// The name for this event if known. | 
|         /// </summary> | 
|         public string Name | 
|         { | 
|             get { return name_; } | 
|         } | 
|          | 
|         /// <summary> | 
|         /// Get set a value indicating wether scanning should continue or not. | 
|         /// </summary> | 
|         public bool ContinueRunning | 
|         { | 
|             get { return continueRunning_; } | 
|             set { continueRunning_ = value; } | 
|         } | 
|   | 
|         /// <summary> | 
|         /// Get a percentage representing how much of the <see cref="Target"></see> has been processed | 
|         /// </summary> | 
|         /// <value>0.0 to 100.0 percent; 0 if target is not known.</value> | 
|         public float PercentComplete | 
|         { | 
|             get | 
|             { | 
|                 float result; | 
|                 if (target_ <= 0) | 
|                 { | 
|                     result = 0; | 
|                 } | 
|                 else | 
|                 { | 
|                     result = ((float)processed_ / (float)target_) * 100.0f; | 
|                 } | 
|                 return result; | 
|             } | 
|         } | 
|          | 
|         /// <summary> | 
|         /// The number of bytes processed so far | 
|         /// </summary> | 
|         public long Processed | 
|         { | 
|             get { return processed_; } | 
|         } | 
|   | 
|         /// <summary> | 
|         /// The number of bytes to process. | 
|         /// </summary> | 
|         /// <remarks>Target may be 0 or negative if the value isnt known.</remarks> | 
|         public long Target | 
|         { | 
|             get { return target_; } | 
|         } | 
|          | 
|         #region Instance Fields | 
|         string name_; | 
|         long processed_; | 
|         long target_; | 
|         bool continueRunning_ = true; | 
|         #endregion | 
|     } | 
|   | 
|     /// <summary> | 
|     /// Event arguments for directories. | 
|     /// </summary> | 
|     public class DirectoryEventArgs : ScanEventArgs | 
|     { | 
|         #region Constructors | 
|         /// <summary> | 
|         /// Initialize an instance of <see cref="DirectoryEventArgs"></see>. | 
|         /// </summary> | 
|         /// <param name="name">The name for this directory.</param> | 
|         /// <param name="hasMatchingFiles">Flag value indicating if any matching files are contained in this directory.</param> | 
|         public DirectoryEventArgs(string name, bool hasMatchingFiles) | 
|             : base (name) | 
|         { | 
|             hasMatchingFiles_ = hasMatchingFiles; | 
|         } | 
|         #endregion | 
|          | 
|         /// <summary> | 
|         /// Get a value indicating if the directory contains any matching files or not. | 
|         /// </summary> | 
|         public bool HasMatchingFiles | 
|         { | 
|             get { return hasMatchingFiles_; } | 
|         } | 
|          | 
|         #region Instance Fields | 
|         bool hasMatchingFiles_; | 
|         #endregion | 
|     } | 
|      | 
|     /// <summary> | 
|     /// Arguments passed when scan failures are detected. | 
|     /// </summary> | 
|     public class ScanFailureEventArgs : EventArgs | 
|     { | 
|         #region Constructors | 
|         /// <summary> | 
|         /// Initialise a new instance of <see cref="ScanFailureEventArgs"></see> | 
|         /// </summary> | 
|         /// <param name="name">The name to apply.</param> | 
|         /// <param name="e">The exception to use.</param> | 
|         public ScanFailureEventArgs(string name, Exception e) | 
|         { | 
|             name_ = name; | 
|             exception_ = e; | 
|             continueRunning_ = true; | 
|         } | 
|         #endregion | 
|          | 
|         /// <summary> | 
|         /// The applicable name. | 
|         /// </summary> | 
|         public string Name | 
|         { | 
|             get { return name_; } | 
|         } | 
|          | 
|         /// <summary> | 
|         /// The applicable exception. | 
|         /// </summary> | 
|         public Exception Exception | 
|         { | 
|             get { return exception_; } | 
|         } | 
|          | 
|         /// <summary> | 
|         /// Get / set a value indicating wether scanning should continue. | 
|         /// </summary> | 
|         public bool ContinueRunning | 
|         { | 
|             get { return continueRunning_; } | 
|             set { continueRunning_ = value; } | 
|         } | 
|          | 
|         #region Instance Fields | 
|         string name_; | 
|         Exception exception_; | 
|         bool continueRunning_; | 
|         #endregion | 
|     } | 
|      | 
|     #endregion | 
|      | 
|     #region Delegates | 
|     /// <summary> | 
|     /// Delegate invoked before starting to process a directory. | 
|     /// </summary> | 
|     public delegate void ProcessDirectoryHandler(object sender, DirectoryEventArgs e); | 
|      | 
|     /// <summary> | 
|     /// Delegate invoked before starting to process a file. | 
|     /// </summary> | 
|     /// <param name="sender">The source of the event</param> | 
|     /// <param name="e">The event arguments.</param> | 
|     public delegate void ProcessFileHandler(object sender, ScanEventArgs e); | 
|   | 
|     /// <summary> | 
|     /// Delegate invoked during processing of a file or directory | 
|     /// </summary> | 
|     /// <param name="sender">The source of the event</param> | 
|     /// <param name="e">The event arguments.</param> | 
|     public delegate void ProgressHandler(object sender, ProgressEventArgs e); | 
|   | 
|     /// <summary> | 
|     /// Delegate invoked when a file has been completely processed. | 
|     /// </summary> | 
|     /// <param name="sender">The source of the event</param> | 
|     /// <param name="e">The event arguments.</param> | 
|     public delegate void CompletedFileHandler(object sender, ScanEventArgs e); | 
|      | 
|     /// <summary> | 
|     /// Delegate invoked when a directory failure is detected. | 
|     /// </summary> | 
|     /// <param name="sender">The source of the event</param> | 
|     /// <param name="e">The event arguments.</param> | 
|     public delegate void DirectoryFailureHandler(object sender, ScanFailureEventArgs e); | 
|      | 
|     /// <summary> | 
|     /// Delegate invoked when a file failure is detected. | 
|     /// </summary> | 
|     /// <param name="sender">The source of the event</param> | 
|     /// <param name="e">The event arguments.</param> | 
|     public delegate void FileFailureHandler(object sender, ScanFailureEventArgs e); | 
|     #endregion | 
|   | 
|     /// <summary> | 
|     /// FileSystemScanner provides facilities scanning of files and directories. | 
|     /// </summary> | 
|     public class FileSystemScanner | 
|     { | 
|         #region Constructors | 
|         /// <summary> | 
|         /// Initialise a new instance of <see cref="FileSystemScanner"></see> | 
|         /// </summary> | 
|         /// <param name="filter">The <see cref="PathFilter">file filter</see> to apply when scanning.</param> | 
|         public FileSystemScanner(string filter) | 
|         { | 
|             fileFilter_ = new PathFilter(filter); | 
|         } | 
|          | 
|         /// <summary> | 
|         /// Initialise a new instance of <see cref="FileSystemScanner"></see> | 
|         /// </summary> | 
|         /// <param name="fileFilter">The <see cref="PathFilter">file filter</see> to apply.</param> | 
|         /// <param name="directoryFilter">The <see cref="PathFilter"> directory filter</see> to apply.</param> | 
|         public FileSystemScanner(string fileFilter, string directoryFilter) | 
|         { | 
|             fileFilter_ = new PathFilter(fileFilter); | 
|             directoryFilter_ = new PathFilter(directoryFilter); | 
|         } | 
|          | 
|         /// <summary> | 
|         /// Initialise a new instance of <see cref="FileSystemScanner"></see> | 
|         /// </summary> | 
|         /// <param name="fileFilter">The file <see cref="IScanFilter">filter</see> to apply.</param> | 
|         public FileSystemScanner(IScanFilter fileFilter) | 
|         { | 
|             fileFilter_ = fileFilter; | 
|         } | 
|          | 
|         /// <summary> | 
|         /// Initialise a new instance of <see cref="FileSystemScanner"></see> | 
|         /// </summary> | 
|         /// <param name="fileFilter">The file <see cref="IScanFilter">filter</see>  to apply.</param> | 
|         /// <param name="directoryFilter">The directory <see cref="IScanFilter">filter</see>  to apply.</param> | 
|         public FileSystemScanner(IScanFilter fileFilter, IScanFilter directoryFilter) | 
|         { | 
|             fileFilter_ = fileFilter; | 
|             directoryFilter_ = directoryFilter; | 
|         } | 
|         #endregion | 
|   | 
|         #region Delegates | 
|         /// <summary> | 
|         /// Delegate to invoke when a directory is processed. | 
|         /// </summary> | 
|         public ProcessDirectoryHandler ProcessDirectory; | 
|          | 
|         /// <summary> | 
|         /// Delegate to invoke when a file is processed. | 
|         /// </summary> | 
|         public ProcessFileHandler ProcessFile; | 
|   | 
|         /// <summary> | 
|         /// Delegate to invoke when processing for a file has finished. | 
|         /// </summary> | 
|         public CompletedFileHandler CompletedFile; | 
|   | 
|         /// <summary> | 
|         /// Delegate to invoke when a directory failure is detected. | 
|         /// </summary> | 
|         public DirectoryFailureHandler DirectoryFailure; | 
|          | 
|         /// <summary> | 
|         /// Delegate to invoke when a file failure is detected. | 
|         /// </summary> | 
|         public FileFailureHandler FileFailure; | 
|         #endregion | 
|   | 
|         /// <summary> | 
|         /// Raise the DirectoryFailure event. | 
|         /// </summary> | 
|         /// <param name="directory">The directory name.</param> | 
|         /// <param name="e">The exception detected.</param> | 
|         bool OnDirectoryFailure(string directory, Exception e) | 
|         { | 
|             DirectoryFailureHandler handler = DirectoryFailure; | 
|             bool result = (handler != null); | 
|             if ( result ) { | 
|                 ScanFailureEventArgs args = new ScanFailureEventArgs(directory, e); | 
|                 handler(this, args); | 
|                 alive_ = args.ContinueRunning; | 
|             } | 
|             return result; | 
|         } | 
|          | 
|         /// <summary> | 
|         /// Raise the FileFailure event. | 
|         /// </summary> | 
|         /// <param name="file">The file name.</param> | 
|         /// <param name="e">The exception detected.</param> | 
|         bool OnFileFailure(string file, Exception e) | 
|         { | 
|             FileFailureHandler handler = FileFailure; | 
|   | 
|             bool result = (handler != null); | 
|   | 
|             if ( result ){ | 
|                 ScanFailureEventArgs args = new ScanFailureEventArgs(file, e); | 
|                 FileFailure(this, args); | 
|                 alive_ = args.ContinueRunning; | 
|             } | 
|             return result; | 
|         } | 
|   | 
|         /// <summary> | 
|         /// Raise the ProcessFile event. | 
|         /// </summary> | 
|         /// <param name="file">The file name.</param> | 
|         void OnProcessFile(string file) | 
|         { | 
|             ProcessFileHandler handler = ProcessFile; | 
|   | 
|             if ( handler!= null ) { | 
|                 ScanEventArgs args = new ScanEventArgs(file); | 
|                 handler(this, args); | 
|                 alive_ = args.ContinueRunning; | 
|             } | 
|         } | 
|   | 
|         /// <summary> | 
|         /// Raise the complete file event | 
|         /// </summary> | 
|         /// <param name="file">The file name</param> | 
|         void OnCompleteFile(string file) | 
|         { | 
|             CompletedFileHandler handler = CompletedFile; | 
|   | 
|             if (handler != null) | 
|             { | 
|                 ScanEventArgs args = new ScanEventArgs(file); | 
|                 handler(this, args); | 
|                 alive_ = args.ContinueRunning; | 
|             } | 
|         } | 
|   | 
|         /// <summary> | 
|         /// Raise the ProcessDirectory event. | 
|         /// </summary> | 
|         /// <param name="directory">The directory name.</param> | 
|         /// <param name="hasMatchingFiles">Flag indicating if the directory has matching files.</param> | 
|         void OnProcessDirectory(string directory, bool hasMatchingFiles) | 
|         { | 
|             ProcessDirectoryHandler handler = ProcessDirectory; | 
|   | 
|             if ( handler != null ) { | 
|                 DirectoryEventArgs args = new DirectoryEventArgs(directory, hasMatchingFiles); | 
|                 handler(this, args); | 
|                 alive_ = args.ContinueRunning; | 
|             } | 
|         } | 
|   | 
|         /// <summary> | 
|         /// Scan a directory. | 
|         /// </summary> | 
|         /// <param name="directory">The base directory to scan.</param> | 
|         /// <param name="recurse">True to recurse subdirectories, false to scan a single directory.</param> | 
|         public void Scan(string directory, bool recurse) | 
|         { | 
|             alive_ = true; | 
|             ScanDir(directory, recurse); | 
|         } | 
|          | 
|         void ScanDir(string directory, bool recurse) | 
|         { | 
|   | 
|             try { | 
|                 string[] names = System.IO.Directory.GetFiles(directory); | 
|                 bool hasMatch = false; | 
|                 for (int fileIndex = 0; fileIndex < names.Length; ++fileIndex) { | 
|                     if ( !fileFilter_.IsMatch(names[fileIndex]) ) { | 
|                         names[fileIndex] = null; | 
|                     } else { | 
|                         hasMatch = true; | 
|                     } | 
|                 } | 
|                  | 
|                 OnProcessDirectory(directory, hasMatch); | 
|                  | 
|                 if ( alive_ && hasMatch ) { | 
|                     foreach (string fileName in names) { | 
|                         try { | 
|                             if ( fileName != null ) { | 
|                                 OnProcessFile(fileName); | 
|                                 if ( !alive_ ) { | 
|                                     break; | 
|                                 } | 
|                             } | 
|                         } | 
|                         catch (Exception e) { | 
|                             if (!OnFileFailure(fileName, e)) { | 
|                                 throw; | 
|                             } | 
|                         } | 
|                     } | 
|                 } | 
|             } | 
|             catch (Exception e) { | 
|                 if (!OnDirectoryFailure(directory, e)) { | 
|                     throw; | 
|                 } | 
|             } | 
|   | 
|             if ( alive_ && recurse ) { | 
|                 try { | 
|                     string[] names = System.IO.Directory.GetDirectories(directory); | 
|                     foreach (string fulldir in names) { | 
|                         if ((directoryFilter_ == null) || (directoryFilter_.IsMatch(fulldir))) { | 
|                             ScanDir(fulldir, true); | 
|                             if ( !alive_ ) { | 
|                                 break; | 
|                             } | 
|                         } | 
|                     } | 
|                 } | 
|                 catch (Exception e) { | 
|                     if (!OnDirectoryFailure(directory, e)) { | 
|                         throw; | 
|                     } | 
|                 } | 
|             } | 
|         } | 
|          | 
|         #region Instance Fields | 
|         /// <summary> | 
|         /// The file filter currently in use. | 
|         /// </summary> | 
|         IScanFilter fileFilter_; | 
|         /// <summary> | 
|         /// The directory filter currently in use. | 
|         /// </summary> | 
|         IScanFilter directoryFilter_; | 
|         /// <summary> | 
|         /// Flag indicating if scanning should continue running. | 
|         /// </summary> | 
|         bool alive_; | 
|         #endregion | 
|     } | 
| } |