Statistics
| Branch: | Revision:

root / trunk / hammock / src / net35 / ICSharpCode.SharpZipLib.Silverlight / Core / FileSystemScanner.cs @ 0eea575a

History | View | Annotate | Download (17.6 kB)

1
// FileSystemScanner.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.IO;
39
using System.Linq;
40

    
41
namespace ICSharpCode.SharpZipLib.Silverlight.Core
42
{
43
    /// <summary>
44
    /// Event arguments for scanning.
45
    /// </summary>
46
    public class ScanEventArgs : EventArgs
47
    {
48
        #region Constructors
49

    
50
        /// <summary>
51
        /// Initialise a new instance of <see cref="ScanEventArgs"/>
52
        /// </summary>
53
        /// <param name="name">The file or directory name.</param>
54
        public ScanEventArgs(string name)
55
        {
56
            name_ = name;
57
        }
58

    
59
        #endregion
60

    
61
        /// <summary>
62
        /// The fie or directory name for this event.
63
        /// </summary>
64
        public string Name
65
        {
66
            get { return name_; }
67
        }
68

    
69
        /// <summary>
70
        /// Get set a value indicating if scanning should continue or not.
71
        /// </summary>
72
        public bool ContinueRunning
73
        {
74
            get { return continueRunning_; }
75
            set { continueRunning_ = value; }
76
        }
77

    
78
        #region Instance Fields
79

    
80
        private readonly string name_;
81
        private bool continueRunning_ = true;
82

    
83
        #endregion
84
    }
85

    
86
    /// <summary>
87
    /// Event arguments during processing of a single file or directory.
88
    /// </summary>
89
    public class ProgressEventArgs : EventArgs
90
    {
91
        #region Constructors
92

    
93
        /// <summary>
94
        /// Initialise a new instance of <see cref="ScanEventArgs"/>
95
        /// </summary>
96
        /// <param name="name">The file or directory name if known.</param>
97
        /// <param name="processed">The number of bytes processed so far</param>
98
        /// <param name="target">The total number of bytes to process, 0 if not known</param>
99
        public ProgressEventArgs(string name, long processed, long target)
100
        {
101
            name_ = name;
102
            processed_ = processed;
103
            target_ = target;
104
        }
105

    
106
        #endregion
107

    
108
        /// <summary>
109
        /// The name for this event if known.
110
        /// </summary>
111
        public string Name
112
        {
113
            get { return name_; }
114
        }
115

    
116
        /// <summary>
117
        /// Get set a value indicating wether scanning should continue or not.
118
        /// </summary>
119
        public bool ContinueRunning
120
        {
121
            get { return continueRunning_; }
122
            set { continueRunning_ = value; }
123
        }
124

    
125
        /// <summary>
126
        /// Get a percentage representing how much of the <see cref="Target"></see> has been processed
127
        /// </summary>
128
        /// <value>0.0 to 100.0 percent; 0 if target is not known.</value>
129
        public float PercentComplete
130
        {
131
            get
132
            {
133
                if (target_ <= 0)
134
                {
135
                    return 0;
136
                }
137
                return (processed_/(float) target_)*100.0f;
138
            }
139
        }
140

    
141
        /// <summary>
142
        /// The number of bytes processed so far
143
        /// </summary>
144
        public long Processed
145
        {
146
            get { return processed_; }
147
        }
148

    
149
        /// <summary>
150
        /// The number of bytes to process.
151
        /// </summary>
152
        /// <remarks>Target may be 0 or negative if the value isnt known.</remarks>
153
        public long Target
154
        {
155
            get { return target_; }
156
        }
157

    
158
        #region Instance Fields
159

    
160
        private readonly string name_;
161
        private readonly long processed_;
162
        private readonly long target_;
163
        private bool continueRunning_ = true;
164

    
165
        #endregion
166
    }
167

    
168
    /// <summary>
169
    /// Event arguments for directories.
170
    /// </summary>
171
    public class DirectoryEventArgs : ScanEventArgs
172
    {
173
        #region Constructors
174

    
175
        /// <summary>
176
        /// Initialize an instance of <see cref="DirectoryEventArgs"></see>.
177
        /// </summary>
178
        /// <param name="name">The name for this directory.</param>
179
        /// <param name="hasMatchingFiles">Flag value indicating if any matching files are contained in this directory.</param>
180
        public DirectoryEventArgs(string name, bool hasMatchingFiles)
181
            : base(name)
182
        {
183
            hasMatchingFiles_ = hasMatchingFiles;
184
        }
185

    
186
        #endregion
187

    
188
        /// <summary>
189
        /// Get a value indicating if the directory contains any matching files or not.
190
        /// </summary>
191
        public bool HasMatchingFiles
192
        {
193
            get { return hasMatchingFiles_; }
194
        }
195

    
196
        #region Instance Fields
197

    
198
        private readonly bool hasMatchingFiles_;
199

    
200
        #endregion
201
    }
202

    
203
    /// <summary>
204
    /// Arguments passed when scan failures are detected.
205
    /// </summary>
206
    public class ScanFailureEventArgs
207
    {
208
        #region Constructors
209

    
210
        /// <summary>
211
        /// Initialise a new instance of <see cref="ScanFailureEventArgs"></see>
212
        /// </summary>
213
        /// <param name="name">The name to apply.</param>
214
        /// <param name="e">The exception to use.</param>
215
        public ScanFailureEventArgs(string name, Exception e)
216
        {
217
            name_ = name;
218
            exception_ = e;
219
            ContinueRunning = true;
220
        }
221

    
222
        #endregion
223

    
224
        /// <summary>
225
        /// The applicable name.
226
        /// </summary>
227
        public string Name
228
        {
229
            get { return name_; }
230
        }
231

    
232
        /// <summary>
233
        /// The applicable exception.
234
        /// </summary>
235
        public Exception Exception
236
        {
237
            get { return exception_; }
238
        }
239

    
240
        /// <summary>
241
        /// Get / set a value indicating wether scanning should continue.
242
        /// </summary>
243
        public bool ContinueRunning { get; set; }
244

    
245
        #region Instance Fields
246

    
247
        private readonly Exception exception_;
248
        private readonly string name_;
249

    
250
        #endregion
251
    }
252

    
253
    /// <summary>
254
    /// Delegate invoked before starting to process a directory.
255
    /// </summary>
256
    public delegate void ProcessDirectoryHandler(object sender, DirectoryEventArgs e);
257

    
258
    /// <summary>
259
    /// Delegate invoked before starting to process a file.
260
    /// </summary>
261
    /// <param name="sender">The source of the event</param>
262
    /// <param name="e">The event arguments.</param>
263
    public delegate void ProcessFileHandler(object sender, ScanEventArgs e);
264

    
265
    /// <summary>
266
    /// Delegate invoked during processing of a file or directory
267
    /// </summary>
268
    /// <param name="sender">The source of the event</param>
269
    /// <param name="e">The event arguments.</param>
270
    public delegate void ProgressHandler(object sender, ProgressEventArgs e);
271

    
272
    /// <summary>
273
    /// Delegate invoked when a file has been completely processed.
274
    /// </summary>
275
    /// <param name="sender">The source of the event</param>
276
    /// <param name="e">The event arguments.</param>
277
    public delegate void CompletedFileHandler(object sender, ScanEventArgs e);
278

    
279
    /// <summary>
280
    /// Delegate invoked when a directory failure is detected.
281
    /// </summary>
282
    /// <param name="sender">The source of the event</param>
283
    /// <param name="e">The event arguments.</param>
284
    public delegate void DirectoryFailureHandler(object sender, ScanFailureEventArgs e);
285

    
286
    /// <summary>
287
    /// Delegate invoked when a file failure is detected.
288
    /// </summary>
289
    /// <param name="sender">The source of the event</param>
290
    /// <param name="e">The event arguments.</param>
291
    public delegate void FileFailureHandler(object sender, ScanFailureEventArgs e);
292

    
293
    /// <summary>
294
    /// FileSystemScanner provides facilities scanning of files and directories.
295
    /// </summary>
296
    public class FileSystemScanner
297
    {
298
        #region Constructors
299

    
300
        /// <summary>
301
        /// Initialise a new instance of <see cref="FileSystemScanner"></see>
302
        /// </summary>
303
        /// <param name="filter">The <see cref="PathFilter">file filter</see> to apply when scanning.</param>
304
        public FileSystemScanner(string filter)
305
        {
306
            fileFilter_ = new PathFilter(filter);
307
        }
308

    
309
        /// <summary>
310
        /// Initialise a new instance of <see cref="FileSystemScanner"></see>
311
        /// </summary>
312
        /// <param name="fileFilter">The <see cref="PathFilter">file filter</see> to apply.</param>
313
        /// <param name="directoryFilter">The <see cref="PathFilter"> directory filter</see> to apply.</param>
314
        public FileSystemScanner(string fileFilter, string directoryFilter)
315
        {
316
            fileFilter_ = new PathFilter(fileFilter);
317
            directoryFilter_ = new PathFilter(directoryFilter);
318
        }
319

    
320
        /// <summary>
321
        /// Initialise a new instance of <see cref="FileSystemScanner"></see>
322
        /// </summary>
323
        /// <param name="fileFilter">The file <see cref="IScanFilter">filter</see> to apply.</param>
324
        public FileSystemScanner(IScanFilter fileFilter)
325
        {
326
            fileFilter_ = fileFilter;
327
        }
328

    
329
        /// <summary>
330
        /// Initialise a new instance of <see cref="FileSystemScanner"></see>
331
        /// </summary>
332
        /// <param name="fileFilter">The file <see cref="IScanFilter">filter</see>  to apply.</param>
333
        /// <param name="directoryFilter">The directory <see cref="IScanFilter">filter</see>  to apply.</param>
334
        public FileSystemScanner(IScanFilter fileFilter, IScanFilter directoryFilter)
335
        {
336
            fileFilter_ = fileFilter;
337
            directoryFilter_ = directoryFilter;
338
        }
339

    
340
        #endregion
341

    
342
        /// <summary>
343
        /// Delegate to invoke when processing for a file has finished.
344
        /// </summary>
345
        public CompletedFileHandler CompletedFile;
346

    
347
        /// <summary>
348
        /// Delegate to invoke when a directory failure is detected.
349
        /// </summary>
350
        public DirectoryFailureHandler DirectoryFailure;
351

    
352
        /// <summary>
353
        /// Delegate to invoke when a file failure is detected.
354
        /// </summary>
355
        public FileFailureHandler FileFailure;
356

    
357
        /// <summary>
358
        /// Delegate to invoke when a directory is processed.
359
        /// </summary>
360
        public ProcessDirectoryHandler ProcessDirectory;
361

    
362
        /// <summary>
363
        /// Delegate to invoke when a file is processed.
364
        /// </summary>
365
        public ProcessFileHandler ProcessFile;
366

    
367
        /// <summary>
368
        /// Raise the DirectoryFailure event.
369
        /// </summary>
370
        /// <param name="directory">The directory name.</param>
371
        /// <param name="e">The exception detected.</param>
372
        private void OnDirectoryFailure(string directory, Exception e)
373
        {
374
            if (DirectoryFailure == null)
375
            {
376
                alive_ = false;
377
            }
378
            else
379
            {
380
                var args = new ScanFailureEventArgs(directory, e);
381
                DirectoryFailure(this, args);
382
                alive_ = args.ContinueRunning;
383
            }
384
        }
385

    
386
        /// <summary>
387
        /// Raise the FileFailure event.
388
        /// </summary>
389
        /// <param name="file">The file name.</param>
390
        /// <param name="e">The exception detected.</param>
391
        private void OnFileFailure(string file, Exception e)
392
        {
393
            if (FileFailure == null)
394
            {
395
                alive_ = false;
396
            }
397
            else
398
            {
399
                var args = new ScanFailureEventArgs(file, e);
400
                FileFailure(this, args);
401
                alive_ = args.ContinueRunning;
402
            }
403
        }
404

    
405
        /// <summary>
406
        /// Raise the ProcessFile event.
407
        /// </summary>
408
        /// <param name="file">The file name.</param>
409
        private void OnProcessFile(string file)
410
        {
411
            if (ProcessFile != null)
412
            {
413
                var args = new ScanEventArgs(file);
414
                ProcessFile(this, args);
415
                alive_ = args.ContinueRunning;
416
            }
417
        }
418

    
419
        /// <summary>
420
        /// Raise the complete file event
421
        /// </summary>
422
        /// <param name="file">The file name</param>
423
        private void OnCompleteFile(string file)
424
        {
425
            if (CompletedFile == null)
426
            {
427
                return;
428
            }
429
            var args = new ScanEventArgs(file);
430
            CompletedFile(this, args);
431
            alive_ = args.ContinueRunning;
432
        }
433

    
434
        /// <summary>
435
        /// Raise the ProcessDirectory event.
436
        /// </summary>
437
        /// <param name="directory">The directory name.</param>
438
        /// <param name="hasMatchingFiles">Flag indicating if the directory has matching files.</param>
439
        private void OnProcessDirectory(string directory, bool hasMatchingFiles)
440
        {
441
            if (ProcessDirectory != null)
442
            {
443
                var args = new DirectoryEventArgs(directory, hasMatchingFiles);
444
                ProcessDirectory(this, args);
445
                alive_ = args.ContinueRunning;
446
            }
447
        }
448

    
449
        /// <summary>
450
        /// Scan a directory.
451
        /// </summary>
452
        /// <param name="directory">The base directory to scan.</param>
453
        /// <param name="recurse">True to recurse subdirectories, false to scan a single directory.</param>
454
        public void Scan(string directory, bool recurse)
455
        {
456
            alive_ = true;
457
            ScanDir(directory, recurse);
458
        }
459

    
460
        private void ScanDir(string directory, bool recurse)
461
        {
462
            try
463
            {
464
#if !SL4
465
                var names = Directory.GetFiles(directory);
466
#else
467
                var names = Directory.EnumerateFiles(directory).ToArray(); 
468
#endif
469
                var hasMatch = false;
470
                for (var fileIndex = 0; fileIndex < names.Length; ++fileIndex)
471
                {
472
                    if (!fileFilter_.IsMatch(names[fileIndex]))
473
                    {
474
                        names[fileIndex] = null;
475
                    }
476
                    else
477
                    {
478
                        hasMatch = true;
479
                    }
480
                }
481

    
482
                OnProcessDirectory(directory, hasMatch);
483

    
484
                if (alive_ && hasMatch)
485
                {
486
                    foreach (var fileName in names)
487
                    {
488
                        try
489
                        {
490
                            if (fileName != null)
491
                            {
492
                                OnProcessFile(fileName);
493
                                if (!alive_)
494
                                {
495
                                    break;
496
                                }
497
                            }
498
                        }
499
                        catch (Exception e)
500
                        {
501
                            OnFileFailure(fileName, e);
502
                        }
503
                    }
504
                }
505
            }
506
            catch (Exception e)
507
            {
508
                OnDirectoryFailure(directory, e);
509
            }
510

    
511
            if (alive_ && recurse)
512
            {
513
                try
514
                {
515
#if !SL4
516
                    var names = Directory.GetDirectories(directory);
517
#else
518
                    var names = System.IO.Directory.EnumerateDirectories(directory); 
519
#endif
520
                    foreach (var fulldir in names)
521
                    {
522
                        if ((directoryFilter_ == null) || (directoryFilter_.IsMatch(fulldir)))
523
                        {
524
                            ScanDir(fulldir, true);
525
                            if (!alive_)
526
                            {
527
                                break;
528
                            }
529
                        }
530
                    }
531
                }
532
                catch (Exception e)
533
                {
534
                    OnDirectoryFailure(directory, e);
535
                }
536
            }
537
        }
538

    
539
        #region Instance Fields
540

    
541
        /// <summary>
542
        /// The directory filter currently in use.
543
        /// </summary>
544
        private readonly IScanFilter directoryFilter_;
545

    
546
        /// <summary>
547
        /// The file filter currently in use.
548
        /// </summary>
549
        private readonly IScanFilter fileFilter_;
550

    
551
        /// <summary>
552
        /// Flag indicating if scanning should continue running.
553
        /// </summary>
554
        private bool alive_;
555

    
556
        #endregion
557
    }
558
}