Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.EPPlus/4.0.3/EPPlus-4.0.3/Packaging/DotNetZip/ZipFile.Selector.cs @ 12074

Last change on this file since 12074 was 12074, checked in by sraggl, 9 years ago

#2341: Added EPPlus-4.0.3 to ExtLibs

File size: 61.7 KB
Line 
1// ZipFile.Selector.cs
2// ------------------------------------------------------------------
3//
4// Copyright (c) 2009-2010 Dino Chiesa.
5// All rights reserved.
6//
7// This code module is part of DotNetZip, a zipfile class library.
8//
9// ------------------------------------------------------------------
10//
11// This code is licensed under the Microsoft Public License.
12// See the file License.txt for the license details.
13// More info on: http://dotnetzip.codeplex.com
14//
15// ------------------------------------------------------------------
16//
17// last saved (in emacs):
18// Time-stamp: <2011-August-06 09:35:58>
19//
20// ------------------------------------------------------------------
21//
22// This module defines methods in the ZipFile class associated to the FileFilter
23// capability - selecting files to add into the archive, or selecting entries to
24// retrieve from the archive based on criteria including the filename, size, date, or
25// attributes.  It is something like a "poor man's LINQ".  I included it into DotNetZip
26// because not everyone has .NET 3.5 yet.  When using DotNetZip on .NET 3.5, the LINQ
27// query/selection will be superior.
28//
29// These methods are segregated into a different module to facilitate easy exclusion for
30// those people who wish to have a smaller library without this function.
31//
32// ------------------------------------------------------------------
33
34
35using System;
36using System.IO;
37using System.Collections.Generic;
38using OfficeOpenXml.Packaging.Ionic.Zip;
39using System.Globalization;
40
41namespace OfficeOpenXml.Packaging.Ionic.Zip
42{
43
44    partial class ZipFile
45    {
46        /// <summary>
47        ///   Adds to the ZipFile a set of files from the current working directory on
48        ///   disk, that conform to the specified criteria.
49        /// </summary>
50        ///
51        /// <remarks>
52        /// <para>
53        ///   This method selects files from the the current working directory matching
54        ///   the specified criteria, and adds them to the ZipFile.
55        /// </para>
56        ///
57        /// <para>
58        ///   Specify the criteria in statements of 3 elements: a noun, an operator, and
59        ///   a value.  Consider the string "name != *.doc" .  The noun is "name".  The
60        ///   operator is "!=", implying "Not Equal".  The value is "*.doc".  That
61        ///   criterion, in English, says "all files with a name that does not end in
62        ///   the .doc extension."
63        /// </para>
64        ///
65        /// <para>
66        ///   Supported nouns include "name" (or "filename") for the filename; "atime",
67        ///   "mtime", and "ctime" for last access time, last modfied time, and created
68        ///   time of the file, respectively; "attributes" (or "attrs") for the file
69        ///   attributes; "size" (or "length") for the file length (uncompressed), and
70        ///   "type" for the type of object, either a file or a directory.  The
71        ///   "attributes", "name" and "type" nouns both support = and != as operators.
72        ///   The "size", "atime", "mtime", and "ctime" nouns support = and !=, and
73        ///   &gt;, &gt;=, &lt;, &lt;= as well. The times are taken to be expressed in
74        ///   local time.
75        /// </para>
76        ///
77        /// <para>
78        /// Specify values for the file attributes as a string with one or more of the
79        /// characters H,R,S,A,I,L in any order, implying file attributes of Hidden,
80        /// ReadOnly, System, Archive, NotContextIndexed, and ReparsePoint (symbolic
81        /// link) respectively.
82        /// </para>
83        ///
84        /// <para>
85        /// To specify a time, use YYYY-MM-DD-HH:mm:ss or YYYY/MM/DD-HH:mm:ss as the
86        /// format.  If you omit the HH:mm:ss portion, it is assumed to be 00:00:00
87        /// (midnight).
88        /// </para>
89        ///
90        /// <para>
91        /// The value for a size criterion is expressed in integer quantities of bytes,
92        /// kilobytes (use k or kb after the number), megabytes (m or mb), or gigabytes
93        /// (g or gb).
94        /// </para>
95        ///
96        /// <para>
97        /// The value for a name is a pattern to match against the filename, potentially
98        /// including wildcards.  The pattern follows CMD.exe glob rules: * implies one
99        /// or more of any character, while ?  implies one character.  If the name
100        /// pattern contains any slashes, it is matched to the entire filename,
101        /// including the path; otherwise, it is matched against only the filename
102        /// without the path.  This means a pattern of "*\*.*" matches all files one
103        /// directory level deep, while a pattern of "*.*" matches all files in all
104        /// directories.
105        /// </para>
106        ///
107        /// <para>
108        /// To specify a name pattern that includes spaces, use single quotes around the
109        /// pattern.  A pattern of "'* *.*'" will match all files that have spaces in
110        /// the filename.  The full criteria string for that would be "name = '* *.*'" .
111        /// </para>
112        ///
113        /// <para>
114        /// The value for a type criterion is either F (implying a file) or D (implying
115        /// a directory).
116        /// </para>
117        ///
118        /// <para>
119        /// Some examples:
120        /// </para>
121        ///
122        /// <list type="table">
123        ///   <listheader>
124        ///     <term>criteria</term>
125        ///     <description>Files retrieved</description>
126        ///   </listheader>
127        ///
128        ///   <item>
129        ///     <term>name != *.xls </term>
130        ///     <description>any file with an extension that is not .xls
131        ///     </description>
132        ///   </item>
133        ///
134        ///   <item>
135        ///     <term>name = *.mp3 </term>
136        ///     <description>any file with a .mp3 extension.
137        ///     </description>
138        ///   </item>
139        ///
140        ///   <item>
141        ///     <term>*.mp3</term>
142        ///     <description>(same as above) any file with a .mp3 extension.
143        ///     </description>
144        ///   </item>
145        ///
146        ///   <item>
147        ///     <term>attributes = A </term>
148        ///     <description>all files whose attributes include the Archive bit.
149        ///     </description>
150        ///   </item>
151        ///
152        ///   <item>
153        ///     <term>attributes != H </term>
154        ///     <description>all files whose attributes do not include the Hidden bit.
155        ///     </description>
156        ///   </item>
157        ///
158        ///   <item>
159        ///     <term>mtime > 2009-01-01</term>
160        ///     <description>all files with a last modified time after January 1st, 2009.
161        ///     </description>
162        ///   </item>
163        ///
164        ///   <item>
165        ///     <term>size > 2gb</term>
166        ///     <description>all files whose uncompressed size is greater than 2gb.
167        ///     </description>
168        ///   </item>
169        ///
170        ///   <item>
171        ///     <term>type = D</term>
172        ///     <description>all directories in the filesystem. </description>
173        ///   </item>
174        ///
175        /// </list>
176        ///
177        /// <para>
178        /// You can combine criteria with the conjunctions AND or OR. Using a string
179        /// like "name = *.txt AND size &gt;= 100k" for the selectionCriteria retrieves
180        /// entries whose names end in .txt, and whose uncompressed size is greater than
181        /// or equal to 100 kilobytes.
182        /// </para>
183        ///
184        /// <para>
185        /// For more complex combinations of criteria, you can use parenthesis to group
186        /// clauses in the boolean logic.  Without parenthesis, the precedence of the
187        /// criterion atoms is determined by order of appearance.  Unlike the C#
188        /// language, the AND conjunction does not take precendence over the logical OR.
189        /// This is important only in strings that contain 3 or more criterion atoms.
190        /// In other words, "name = *.txt and size &gt; 1000 or attributes = H" implies
191        /// "((name = *.txt AND size &gt; 1000) OR attributes = H)" while "attributes =
192        /// H OR name = *.txt and size &gt; 1000" evaluates to "((attributes = H OR name
193        /// = *.txt) AND size &gt; 1000)".  When in doubt, use parenthesis.
194        /// </para>
195        ///
196        /// <para>
197        /// Using time properties requires some extra care. If you want to retrieve all
198        /// entries that were last updated on 2009 February 14, specify a time range
199        /// like so:"mtime &gt;= 2009-02-14 AND mtime &lt; 2009-02-15".  Read this to
200        /// say: all files updated after 12:00am on February 14th, until 12:00am on
201        /// February 15th.  You can use the same bracketing approach to specify any time
202        /// period - a year, a month, a week, and so on.
203        /// </para>
204        ///
205        /// <para>
206        /// The syntax allows one special case: if you provide a string with no spaces, it is
207        /// treated as a pattern to match for the filename.  Therefore a string like "*.xls"
208        /// will be equivalent to specifying "name = *.xls".
209        /// </para>
210        ///
211        /// <para>
212        /// There is no logic in this method that insures that the file inclusion
213        /// criteria are internally consistent.  For example, it's possible to specify
214        /// criteria that says the file must have a size of less than 100 bytes, as well
215        /// as a size that is greater than 1000 bytes. Obviously no file will ever
216        /// satisfy such criteria, but this method does not detect such logical
217        /// inconsistencies. The caller is responsible for insuring the criteria are
218        /// sensible.
219        /// </para>
220        ///
221        /// <para>
222        ///   Using this method, the file selection does not recurse into
223        ///   subdirectories, and the full path of the selected files is included in the
224        ///   entries added into the zip archive.  If you don't like these behaviors,
225        ///   see the other overloads of this method.
226        /// </para>
227        /// </remarks>
228        ///
229        /// <example>
230        /// This example zips up all *.csv files in the current working directory.
231        /// <code>
232        /// using (ZipFile zip = new ZipFile())
233        /// {
234        ///     // To just match on filename wildcards,
235        ///     // use the shorthand form of the selectionCriteria string.
236        ///     zip.AddSelectedFiles("*.csv");
237        ///     zip.Save(PathToZipArchive);
238        /// }
239        /// </code>
240        /// <code lang="VB">
241        /// Using zip As ZipFile = New ZipFile()
242        ///     zip.AddSelectedFiles("*.csv")
243        ///     zip.Save(PathToZipArchive)
244        /// End Using
245        /// </code>
246        /// </example>
247        ///
248        /// <param name="selectionCriteria">The criteria for file selection</param>
249        public void AddSelectedFiles(String selectionCriteria)
250        {
251            this.AddSelectedFiles(selectionCriteria, ".", null, false);
252        }
253
254        /// <summary>
255        ///   Adds to the ZipFile a set of files from the disk that conform to the
256        ///   specified criteria, optionally recursing into subdirectories.
257        /// </summary>
258        ///
259        /// <remarks>
260        /// <para>
261        ///   This method selects files from the the current working directory matching
262        ///   the specified criteria, and adds them to the ZipFile.  If
263        ///   <c>recurseDirectories</c> is true, files are also selected from
264        ///   subdirectories, and the directory structure in the filesystem is
265        ///   reproduced in the zip archive, rooted at the current working directory.
266        /// </para>
267        ///
268        /// <para>
269        ///   Using this method, the full path of the selected files is included in the
270        ///   entries added into the zip archive.  If you don't want this behavior, use
271        ///   one of the overloads of this method that allows the specification of a
272        ///   <c>directoryInArchive</c>.
273        /// </para>
274        ///
275        /// <para>
276        ///   For details on the syntax for the selectionCriteria parameter, see <see
277        ///   cref="AddSelectedFiles(String)"/>.
278        /// </para>
279        ///
280        /// </remarks>
281        ///
282        /// <example>
283        ///
284        ///   This example zips up all *.xml files in the current working directory, or any
285        ///   subdirectory, that are larger than 1mb.
286        ///
287        /// <code>
288        /// using (ZipFile zip = new ZipFile())
289        /// {
290        ///     // Use a compound expression in the selectionCriteria string.
291        ///     zip.AddSelectedFiles("name = *.xml  and  size > 1024kb", true);
292        ///     zip.Save(PathToZipArchive);
293        /// }
294        /// </code>
295        /// <code lang="VB">
296        /// Using zip As ZipFile = New ZipFile()
297        ///     ' Use a compound expression in the selectionCriteria string.
298        ///     zip.AddSelectedFiles("name = *.xml  and  size > 1024kb", true)
299        ///     zip.Save(PathToZipArchive)
300        /// End Using
301        /// </code>
302        /// </example>
303        ///
304        /// <param name="selectionCriteria">The criteria for file selection</param>
305        ///
306        /// <param name="recurseDirectories">
307        ///   If true, the file selection will recurse into subdirectories.
308        /// </param>
309        public void AddSelectedFiles(String selectionCriteria, bool recurseDirectories)
310        {
311            this.AddSelectedFiles(selectionCriteria, ".", null, recurseDirectories);
312        }
313
314        /// <summary>
315        ///   Adds to the ZipFile a set of files from a specified directory in the
316        ///   filesystem, that conform to the specified criteria.
317        /// </summary>
318        ///
319        /// <remarks>
320        /// <para>
321        ///   This method selects files that conform to the specified criteria, from the
322        ///   the specified directory on disk, and adds them to the ZipFile.  The search
323        ///   does not recurse into subdirectores.
324        /// </para>
325        ///
326        /// <para>
327        ///   Using this method, the full filesystem path of the files on disk is
328        ///   reproduced on the entries added to the zip file.  If you don't want this
329        ///   behavior, use one of the other overloads of this method.
330        /// </para>
331        ///
332        /// <para>
333        ///   For details on the syntax for the selectionCriteria parameter, see <see
334        ///   cref="AddSelectedFiles(String)"/>.
335        /// </para>
336        ///
337        /// </remarks>
338        ///
339        /// <example>
340        ///
341        ///   This example zips up all *.xml files larger than 1mb in the directory
342        ///   given by "d:\rawdata".
343        ///
344        /// <code>
345        /// using (ZipFile zip = new ZipFile())
346        /// {
347        ///     // Use a compound expression in the selectionCriteria string.
348        ///     zip.AddSelectedFiles("name = *.xml  and  size > 1024kb", "d:\\rawdata");
349        ///     zip.Save(PathToZipArchive);
350        /// }
351        /// </code>
352        ///
353        /// <code lang="VB">
354        /// Using zip As ZipFile = New ZipFile()
355        ///     ' Use a compound expression in the selectionCriteria string.
356        ///     zip.AddSelectedFiles("name = *.xml  and  size > 1024kb", "d:\rawdata)
357        ///     zip.Save(PathToZipArchive)
358        /// End Using
359        /// </code>
360        /// </example>
361        ///
362        /// <param name="selectionCriteria">The criteria for file selection</param>
363        ///
364        /// <param name="directoryOnDisk">
365        /// The name of the directory on the disk from which to select files.
366        /// </param>
367        public void AddSelectedFiles(String selectionCriteria, String directoryOnDisk)
368        {
369            this.AddSelectedFiles(selectionCriteria, directoryOnDisk, null, false);
370        }
371
372
373        /// <summary>
374        ///   Adds to the ZipFile a set of files from the specified directory on disk,
375        ///   that conform to the specified criteria.
376        /// </summary>
377        ///
378        /// <remarks>
379        ///
380        /// <para>
381        ///   This method selects files from the the specified disk directory matching
382        ///   the specified selection criteria, and adds them to the ZipFile.  If
383        ///   <c>recurseDirectories</c> is true, files are also selected from
384        ///   subdirectories.
385        /// </para>
386        ///
387        /// <para>
388        ///   The full directory structure in the filesystem is reproduced on the
389        ///   entries added to the zip archive.  If you don't want this behavior, use
390        ///   one of the overloads of this method that allows the specification of a
391        ///   <c>directoryInArchive</c>.
392        /// </para>
393        ///
394        /// <para>
395        ///   For details on the syntax for the selectionCriteria parameter, see <see
396        ///   cref="AddSelectedFiles(String)"/>.
397        /// </para>
398        /// </remarks>
399        ///
400        /// <example>
401        ///
402        ///   This example zips up all *.csv files in the "files" directory, or any
403        ///   subdirectory, that have been saved since 2009 February 14th.
404        ///
405        /// <code>
406        /// using (ZipFile zip = new ZipFile())
407        /// {
408        ///     // Use a compound expression in the selectionCriteria string.
409        ///     zip.AddSelectedFiles("name = *.csv  and  mtime > 2009-02-14", "files", true);
410        ///     zip.Save(PathToZipArchive);
411        /// }
412        /// </code>
413        /// <code lang="VB">
414        /// Using zip As ZipFile = New ZipFile()
415        ///     ' Use a compound expression in the selectionCriteria string.
416        ///     zip.AddSelectedFiles("name = *.csv  and  mtime > 2009-02-14", "files", true)
417        ///     zip.Save(PathToZipArchive)
418        /// End Using
419        /// </code>
420        /// </example>
421        ///
422        /// <example>
423        ///   This example zips up all files in the current working
424        ///   directory, and all its child directories, except those in
425        ///   the <c>excludethis</c> subdirectory.
426        /// <code lang="VB">
427        /// Using Zip As ZipFile = New ZipFile(zipfile)
428        ///   Zip.AddSelectedFfiles("name != 'excludethis\*.*'", datapath, True)
429        ///   Zip.Save()
430        /// End Using
431        /// </code>
432        /// </example>
433        ///
434        /// <param name="selectionCriteria">The criteria for file selection</param>
435        ///
436        /// <param name="directoryOnDisk">
437        ///   The filesystem path from which to select files.
438        /// </param>
439        ///
440        /// <param name="recurseDirectories">
441        ///   If true, the file selection will recurse into subdirectories.
442        /// </param>
443        public void AddSelectedFiles(String selectionCriteria, String directoryOnDisk, bool recurseDirectories)
444        {
445            this.AddSelectedFiles(selectionCriteria, directoryOnDisk, null, recurseDirectories);
446        }
447
448
449        /// <summary>
450        ///   Adds to the ZipFile a selection of files from the specified directory on
451        ///   disk, that conform to the specified criteria, and using a specified root
452        ///   path for entries added to the zip archive.
453        /// </summary>
454        ///
455        /// <remarks>
456        /// <para>
457        ///   This method selects files from the specified disk directory matching the
458        ///   specified selection criteria, and adds those files to the ZipFile, using
459        ///   the specified directory path in the archive.  The search does not recurse
460        ///   into subdirectories.  For details on the syntax for the selectionCriteria
461        ///   parameter, see <see cref="AddSelectedFiles(String)" />.
462        /// </para>
463        ///
464        /// </remarks>
465        ///
466        /// <example>
467        ///
468        ///   This example zips up all *.psd files in the "photos" directory that have
469        ///   been saved since 2009 February 14th, and puts them all in a zip file,
470        ///   using the directory name of "content" in the zip archive itself. When the
471        ///   zip archive is unzipped, the folder containing the .psd files will be
472        ///   named "content".
473        ///
474        /// <code>
475        /// using (ZipFile zip = new ZipFile())
476        /// {
477        ///     // Use a compound expression in the selectionCriteria string.
478        ///     zip.AddSelectedFiles("name = *.psd  and  mtime > 2009-02-14", "photos", "content");
479        ///     zip.Save(PathToZipArchive);
480        /// }
481        /// </code>
482        /// <code lang="VB">
483        /// Using zip As ZipFile = New ZipFile
484        ///     zip.AddSelectedFiles("name = *.psd  and  mtime > 2009-02-14", "photos", "content")
485        ///     zip.Save(PathToZipArchive)
486        /// End Using
487        /// </code>
488        /// </example>
489        ///
490        /// <param name="selectionCriteria">
491        ///   The criteria for selection of files to add to the <c>ZipFile</c>.
492        /// </param>
493        ///
494        /// <param name="directoryOnDisk">
495        ///   The path to the directory in the filesystem from which to select files.
496        /// </param>
497        ///
498        /// <param name="directoryPathInArchive">
499        ///   Specifies a directory path to use to in place of the
500        ///   <c>directoryOnDisk</c>.  This path may, or may not, correspond to a real
501        ///   directory in the current filesystem.  If the files within the zip are
502        ///   later extracted, this is the path used for the extracted file.  Passing
503        ///   null (nothing in VB) will use the path on the file name, if any; in other
504        ///   words it would use <c>directoryOnDisk</c>, plus any subdirectory.  Passing
505        ///   the empty string ("") will insert the item at the root path within the
506        ///   archive.
507        /// </param>
508        public void AddSelectedFiles(String selectionCriteria,
509                                     String directoryOnDisk,
510                                     String directoryPathInArchive)
511        {
512            this.AddSelectedFiles(selectionCriteria, directoryOnDisk, directoryPathInArchive, false);
513        }
514
515        /// <summary>
516        ///   Adds to the ZipFile a selection of files from the specified directory on
517        ///   disk, that conform to the specified criteria, optionally recursing through
518        ///   subdirectories, and using a specified root path for entries added to the
519        ///   zip archive.
520        /// </summary>
521        ///
522        /// <remarks>
523        ///   This method selects files from the specified disk directory that match the
524        ///   specified selection criteria, and adds those files to the ZipFile, using
525        ///   the specified directory path in the archive. If <c>recurseDirectories</c>
526        ///   is true, files are also selected from subdirectories, and the directory
527        ///   structure in the filesystem is reproduced in the zip archive, rooted at
528        ///   the directory specified by <c>directoryOnDisk</c>.  For details on the
529        ///   syntax for the selectionCriteria parameter, see <see
530        ///   cref="AddSelectedFiles(String)" />.
531        /// </remarks>
532        ///
533        /// <example>
534        ///
535        ///   This example zips up all files that are NOT *.pst files, in the current
536        ///   working directory and any subdirectories.
537        ///
538        /// <code>
539        /// using (ZipFile zip = new ZipFile())
540        /// {
541        ///     zip.AddSelectedFiles("name != *.pst", SourceDirectory, "backup", true);
542        ///     zip.Save(PathToZipArchive);
543        /// }
544        /// </code>
545        /// <code lang="VB">
546        /// Using zip As ZipFile = New ZipFile
547        ///     zip.AddSelectedFiles("name != *.pst", SourceDirectory, "backup", true)
548        ///     zip.Save(PathToZipArchive)
549        /// End Using
550        /// </code>
551        /// </example>
552        ///
553        /// <param name="selectionCriteria">
554        ///   The criteria for selection of files to add to the <c>ZipFile</c>.
555        /// </param>
556        ///
557        /// <param name="directoryOnDisk">
558        ///   The path to the directory in the filesystem from which to select files.
559        /// </param>
560        ///
561        /// <param name="directoryPathInArchive">
562        ///   Specifies a directory path to use to in place of the
563        ///   <c>directoryOnDisk</c>.  This path may, or may not, correspond to a real
564        ///   directory in the current filesystem.  If the files within the zip are
565        ///   later extracted, this is the path used for the extracted file.  Passing
566        ///   null (nothing in VB) will use the path on the file name, if any; in other
567        ///   words it would use <c>directoryOnDisk</c>, plus any subdirectory.  Passing
568        ///   the empty string ("") will insert the item at the root path within the
569        ///   archive.
570        /// </param>
571        ///
572        /// <param name="recurseDirectories">
573        ///   If true, the method also scans subdirectories for files matching the
574        ///   criteria.
575        /// </param>
576        public void AddSelectedFiles(String selectionCriteria,
577                                     String directoryOnDisk,
578                                     String directoryPathInArchive,
579                                     bool recurseDirectories)
580        {
581            _AddOrUpdateSelectedFiles(selectionCriteria,
582                                      directoryOnDisk,
583                                      directoryPathInArchive,
584                                      recurseDirectories,
585                                      false);
586        }
587
588        /// <summary>
589        ///   Updates the ZipFile with a selection of files from the disk that conform
590        ///   to the specified criteria.
591        /// </summary>
592        ///
593        /// <remarks>
594        ///   This method selects files from the specified disk directory that match the
595        ///   specified selection criteria, and Updates the <c>ZipFile</c> with those
596        ///   files, using the specified directory path in the archive. If
597        ///   <c>recurseDirectories</c> is true, files are also selected from
598        ///   subdirectories, and the directory structure in the filesystem is
599        ///   reproduced in the zip archive, rooted at the directory specified by
600        ///   <c>directoryOnDisk</c>.  For details on the syntax for the
601        ///   selectionCriteria parameter, see <see cref="AddSelectedFiles(String)" />.
602        /// </remarks>
603        ///
604        /// <param name="selectionCriteria">
605        ///   The criteria for selection of files to add to the <c>ZipFile</c>.
606        /// </param>
607        ///
608        /// <param name="directoryOnDisk">
609        ///   The path to the directory in the filesystem from which to select files.
610        /// </param>
611        ///
612        /// <param name="directoryPathInArchive">
613        ///   Specifies a directory path to use to in place of the
614        ///   <c>directoryOnDisk</c>. This path may, or may not, correspond to a
615        ///   real directory in the current filesystem. If the files within the zip
616        ///   are later extracted, this is the path used for the extracted file.
617        ///   Passing null (nothing in VB) will use the path on the file name, if
618        ///   any; in other words it would use <c>directoryOnDisk</c>, plus any
619        ///   subdirectory.  Passing the empty string ("") will insert the item at
620        ///   the root path within the archive.
621        /// </param>
622        ///
623        /// <param name="recurseDirectories">
624        ///   If true, the method also scans subdirectories for files matching the criteria.
625        /// </param>
626        ///
627        /// <seealso cref="AddSelectedFiles(String, String, String, bool)" />
628        public void UpdateSelectedFiles(String selectionCriteria,
629                                     String directoryOnDisk,
630                                     String directoryPathInArchive,
631                                     bool recurseDirectories)
632        {
633            _AddOrUpdateSelectedFiles(selectionCriteria,
634                                      directoryOnDisk,
635                                      directoryPathInArchive,
636                                      recurseDirectories,
637                                      true);
638        }
639
640
641        private string EnsureendInSlash(string s)
642        {
643            if (s.EndsWith("\\")) return s;
644            return s + "\\";
645        }
646
647        private void _AddOrUpdateSelectedFiles(String selectionCriteria,
648                                               String directoryOnDisk,
649                                               String directoryPathInArchive,
650                                               bool recurseDirectories,
651                                               bool wantUpdate)
652        {
653            if (directoryOnDisk == null && (Directory.Exists(selectionCriteria)))
654            {
655                directoryOnDisk = selectionCriteria;
656                selectionCriteria = "*.*";
657            }
658            else if (String.IsNullOrEmpty(directoryOnDisk))
659            {
660                directoryOnDisk = ".";
661            }
662
663            // workitem 9176
664            while (directoryOnDisk.EndsWith("\\")) directoryOnDisk = directoryOnDisk.Substring(0, directoryOnDisk.Length - 1);
665            if (Verbose) StatusMessageTextWriter.WriteLine("adding selection '{0}' from dir '{1}'...",
666                                                               selectionCriteria, directoryOnDisk);
667            Ionic.FileSelector ff = new Ionic.FileSelector(selectionCriteria,
668                                                           AddDirectoryWillTraverseReparsePoints);
669            var itemsToAdd = ff.SelectFiles(directoryOnDisk, recurseDirectories);
670
671            if (Verbose) StatusMessageTextWriter.WriteLine("found {0} files...", itemsToAdd.Count);
672
673            OnAddStarted();
674
675            AddOrUpdateAction action = (wantUpdate) ? AddOrUpdateAction.AddOrUpdate : AddOrUpdateAction.AddOnly;
676            foreach (var item in itemsToAdd)
677            {
678                // workitem 10153
679                string dirInArchive = (directoryPathInArchive == null)
680                    ? null
681                    // workitem 12260
682                    : ReplaceLeadingDirectory(Path.GetDirectoryName(item),
683                                              directoryOnDisk,
684                                              directoryPathInArchive);
685
686                if (File.Exists(item))
687                {
688                    if (wantUpdate)
689                        this.UpdateFile(item, dirInArchive);
690                    else
691                        this.AddFile(item, dirInArchive);
692                }
693                else
694                {
695                    // this adds "just" the directory, without recursing to the contained files
696                    AddOrUpdateDirectoryImpl(item, dirInArchive, action, false, 0);
697                }
698            }
699
700            OnAddCompleted();
701        }
702
703
704        // workitem 12260
705        private static string ReplaceLeadingDirectory(string original,
706                                                      string pattern,
707                                                      string replacement)
708        {
709            string upperString = original.ToUpper(CultureInfo.InvariantCulture);
710            string upperPattern = pattern.ToUpper(CultureInfo.InvariantCulture);
711            int p1 = upperString.IndexOf(upperPattern);
712            if (p1 != 0) return original;
713            return replacement + original.Substring(upperPattern.Length);
714        }
715
716#if NOT
717        private static string ReplaceEx(string original,
718                                                      string pattern,
719                                                      string replacement)
720        {
721            int count, position0, position1;
722            count = position0 = position1 = 0;
723            string upperString = original.ToUpper();
724            string upperPattern = pattern.ToUpper();
725            int inc = (original.Length/pattern.Length) *
726                (replacement.Length-pattern.Length);
727            char [] chars = new char[original.Length + Math.Max(0, inc)];
728            while( (position1 = upperString.IndexOf(upperPattern,
729                                                    position0)) != -1 )
730            {
731                for ( int i=position0 ; i < position1 ; ++i )
732                    chars[count++] = original[i];
733                for ( int i=0 ; i < replacement.Length ; ++i )
734                    chars[count++] = replacement[i];
735                position0 = position1+pattern.Length;
736            }
737            if ( position0 == 0 ) return original;
738            for ( int i=position0 ; i < original.Length ; ++i )
739                chars[count++] = original[i];
740            return new string(chars, 0, count);
741        }
742#endif
743
744        /// <summary>
745        /// Retrieve entries from the zipfile by specified criteria.
746        /// </summary>
747        ///
748        /// <remarks>
749        /// <para>
750        /// This method allows callers to retrieve the collection of entries from the zipfile
751        /// that fit the specified criteria.  The criteria are described in a string format, and
752        /// can include patterns for the filename; constraints on the size of the entry;
753        /// constraints on the last modified, created, or last accessed time for the file
754        /// described by the entry; or the attributes of the entry.
755        /// </para>
756        ///
757        /// <para>
758        /// For details on the syntax for the selectionCriteria parameter, see <see
759        /// cref="AddSelectedFiles(String)"/>.
760        /// </para>
761        ///
762        /// <para>
763        /// This method is intended for use with a ZipFile that has been read from storage.
764        /// When creating a new ZipFile, this method will work only after the ZipArchive has
765        /// been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip
766        /// archive from storage.)  Calling SelectEntries on a ZipFile that has not yet been
767        /// saved will deliver undefined results.
768        /// </para>
769        /// </remarks>
770        ///
771        /// <exception cref="System.Exception">
772        /// Thrown if selectionCriteria has an invalid syntax.
773        /// </exception>
774        ///
775        /// <example>
776        /// This example selects all the PhotoShop files from within an archive, and extracts them
777        /// to the current working directory.
778        /// <code>
779        /// using (ZipFile zip1 = ZipFile.Read(ZipFileName))
780        /// {
781        ///     var PhotoShopFiles = zip1.SelectEntries("*.psd");
782        ///     foreach (ZipEntry psd in PhotoShopFiles)
783        ///     {
784        ///         psd.Extract();
785        ///     }
786        /// }
787        /// </code>
788        /// <code lang="VB">
789        /// Using zip1 As ZipFile = ZipFile.Read(ZipFileName)
790        ///     Dim PhotoShopFiles as ICollection(Of ZipEntry)
791        ///     PhotoShopFiles = zip1.SelectEntries("*.psd")
792        ///     Dim psd As ZipEntry
793        ///     For Each psd In PhotoShopFiles
794        ///         psd.Extract
795        ///     Next
796        /// End Using
797        /// </code>
798        /// </example>
799        /// <param name="selectionCriteria">the string that specifies which entries to select</param>
800        /// <returns>a collection of ZipEntry objects that conform to the inclusion spec</returns>
801        public ICollection<ZipEntry> SelectEntries(String selectionCriteria)
802        {
803            Ionic.FileSelector ff = new Ionic.FileSelector(selectionCriteria,
804                                                           AddDirectoryWillTraverseReparsePoints);
805            return ff.SelectEntries(this);
806        }
807
808
809        /// <summary>
810        /// Retrieve entries from the zipfile by specified criteria.
811        /// </summary>
812        ///
813        /// <remarks>
814        /// <para>
815        /// This method allows callers to retrieve the collection of entries from the zipfile
816        /// that fit the specified criteria.  The criteria are described in a string format, and
817        /// can include patterns for the filename; constraints on the size of the entry;
818        /// constraints on the last modified, created, or last accessed time for the file
819        /// described by the entry; or the attributes of the entry.
820        /// </para>
821        ///
822        /// <para>
823        /// For details on the syntax for the selectionCriteria parameter, see <see
824        /// cref="AddSelectedFiles(String)"/>.
825        /// </para>
826        ///
827        /// <para>
828        /// This method is intended for use with a ZipFile that has been read from storage.
829        /// When creating a new ZipFile, this method will work only after the ZipArchive has
830        /// been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip
831        /// archive from storage.)  Calling SelectEntries on a ZipFile that has not yet been
832        /// saved will deliver undefined results.
833        /// </para>
834        /// </remarks>
835        ///
836        /// <exception cref="System.Exception">
837        /// Thrown if selectionCriteria has an invalid syntax.
838        /// </exception>
839        ///
840        /// <example>
841        /// <code>
842        /// using (ZipFile zip1 = ZipFile.Read(ZipFileName))
843        /// {
844        ///     var UpdatedPhotoShopFiles = zip1.SelectEntries("*.psd", "UpdatedFiles");
845        ///     foreach (ZipEntry e in UpdatedPhotoShopFiles)
846        ///     {
847        ///         // prompt for extract here
848        ///         if (WantExtract(e.FileName))
849        ///             e.Extract();
850        ///     }
851        /// }
852        /// </code>
853        /// <code lang="VB">
854        /// Using zip1 As ZipFile = ZipFile.Read(ZipFileName)
855        ///     Dim UpdatedPhotoShopFiles As ICollection(Of ZipEntry) = zip1.SelectEntries("*.psd", "UpdatedFiles")
856        ///     Dim e As ZipEntry
857        ///     For Each e In UpdatedPhotoShopFiles
858        ///         ' prompt for extract here
859        ///         If Me.WantExtract(e.FileName) Then
860        ///             e.Extract
861        ///         End If
862        ///     Next
863        /// End Using
864        /// </code>
865        /// </example>
866        /// <param name="selectionCriteria">the string that specifies which entries to select</param>
867        ///
868        /// <param name="directoryPathInArchive">
869        /// the directory in the archive from which to select entries. If null, then
870        /// all directories in the archive are used.
871        /// </param>
872        ///
873        /// <returns>a collection of ZipEntry objects that conform to the inclusion spec</returns>
874        public ICollection<ZipEntry> SelectEntries(String selectionCriteria, string directoryPathInArchive)
875        {
876            Ionic.FileSelector ff = new Ionic.FileSelector(selectionCriteria,
877                                                           AddDirectoryWillTraverseReparsePoints);
878            return ff.SelectEntries(this, directoryPathInArchive);
879        }
880
881
882
883        /// <summary>
884        /// Remove entries from the zipfile by specified criteria.
885        /// </summary>
886        ///
887        /// <remarks>
888        /// <para>
889        /// This method allows callers to remove the collection of entries from the zipfile
890        /// that fit the specified criteria.  The criteria are described in a string format, and
891        /// can include patterns for the filename; constraints on the size of the entry;
892        /// constraints on the last modified, created, or last accessed time for the file
893        /// described by the entry; or the attributes of the entry.
894        /// </para>
895        ///
896        /// <para>
897        /// For details on the syntax for the selectionCriteria parameter, see <see
898        /// cref="AddSelectedFiles(String)"/>.
899        /// </para>
900        ///
901        /// <para>
902        /// This method is intended for use with a ZipFile that has been read from storage.
903        /// When creating a new ZipFile, this method will work only after the ZipArchive has
904        /// been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip
905        /// archive from storage.)  Calling SelectEntries on a ZipFile that has not yet been
906        /// saved will deliver undefined results.
907        /// </para>
908        /// </remarks>
909        ///
910        /// <exception cref="System.Exception">
911        /// Thrown if selectionCriteria has an invalid syntax.
912        /// </exception>
913        ///
914        /// <example>
915        /// This example removes all entries in a zip file that were modified prior to January 1st, 2008.
916        /// <code>
917        /// using (ZipFile zip1 = ZipFile.Read(ZipFileName))
918        /// {
919        ///     // remove all entries from prior to Jan 1, 2008
920        ///     zip1.RemoveEntries("mtime &lt; 2008-01-01");
921        ///     // don't forget to save the archive!
922        ///     zip1.Save();
923        /// }
924        /// </code>
925        /// <code lang="VB">
926        /// Using zip As ZipFile = ZipFile.Read(ZipFileName)
927        ///     ' remove all entries from prior to Jan 1, 2008
928        ///     zip1.RemoveEntries("mtime &lt; 2008-01-01")
929        ///     ' do not forget to save the archive!
930        ///     zip1.Save
931        /// End Using
932        /// </code>
933        /// </example>
934        /// <param name="selectionCriteria">the string that specifies which entries to select</param>
935        /// <returns>the number of entries removed</returns>
936        public int RemoveSelectedEntries(String selectionCriteria)
937        {
938            var selection = this.SelectEntries(selectionCriteria);
939            this.RemoveEntries(selection);
940            return selection.Count;
941        }
942
943
944        /// <summary>
945        /// Remove entries from the zipfile by specified criteria, and within the specified
946        /// path in the archive.
947        /// </summary>
948        ///
949        /// <remarks>
950        /// <para>
951        /// This method allows callers to remove the collection of entries from the zipfile
952        /// that fit the specified criteria.  The criteria are described in a string format, and
953        /// can include patterns for the filename; constraints on the size of the entry;
954        /// constraints on the last modified, created, or last accessed time for the file
955        /// described by the entry; or the attributes of the entry.
956        /// </para>
957        ///
958        /// <para>
959        /// For details on the syntax for the selectionCriteria parameter, see <see
960        /// cref="AddSelectedFiles(String)"/>.
961        /// </para>
962        ///
963        /// <para>
964        /// This method is intended for use with a ZipFile that has been read from storage.
965        /// When creating a new ZipFile, this method will work only after the ZipArchive has
966        /// been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip
967        /// archive from storage.)  Calling SelectEntries on a ZipFile that has not yet been
968        /// saved will deliver undefined results.
969        /// </para>
970        /// </remarks>
971        ///
972        /// <exception cref="System.Exception">
973        /// Thrown if selectionCriteria has an invalid syntax.
974        /// </exception>
975        ///
976        /// <example>
977        /// <code>
978        /// using (ZipFile zip1 = ZipFile.Read(ZipFileName))
979        /// {
980        ///     // remove all entries from prior to Jan 1, 2008
981        ///     zip1.RemoveEntries("mtime &lt; 2008-01-01", "documents");
982        ///     // a call to ZipFile.Save will make the modifications permanent
983        ///     zip1.Save();
984        /// }
985        /// </code>
986        /// <code lang="VB">
987        /// Using zip As ZipFile = ZipFile.Read(ZipFileName)
988        ///     ' remove all entries from prior to Jan 1, 2008
989        ///     zip1.RemoveEntries("mtime &lt; 2008-01-01", "documents")
990        ///     ' a call to ZipFile.Save will make the modifications permanent
991        ///     zip1.Save
992        /// End Using
993        /// </code>
994        /// </example>
995        ///
996        /// <param name="selectionCriteria">the string that specifies which entries to select</param>
997        /// <param name="directoryPathInArchive">
998        /// the directory in the archive from which to select entries. If null, then
999        /// all directories in the archive are used.
1000        /// </param>
1001        /// <returns>the number of entries removed</returns>
1002        public int RemoveSelectedEntries(String selectionCriteria, string directoryPathInArchive)
1003        {
1004            var selection = this.SelectEntries(selectionCriteria, directoryPathInArchive);
1005            this.RemoveEntries(selection);
1006            return selection.Count;
1007        }
1008
1009
1010        /// <summary>
1011        /// Selects and Extracts a set of Entries from the ZipFile.
1012        /// </summary>
1013        ///
1014        /// <remarks>
1015        /// <para>
1016        /// The entries are extracted into the current working directory.
1017        /// </para>
1018        ///
1019        /// <para>
1020        /// If any of the files to be extracted already exist, then the action taken is as
1021        /// specified in the <see cref="ZipEntry.ExtractExistingFile"/> property on the
1022        /// corresponding ZipEntry instance.  By default, the action taken in this case is to
1023        /// throw an exception.
1024        /// </para>
1025        ///
1026        /// <para>
1027        /// For information on the syntax of the selectionCriteria string,
1028        /// see <see cref="AddSelectedFiles(String)" />.
1029        /// </para>
1030        /// </remarks>
1031        ///
1032        /// <example>
1033        /// This example shows how extract all XML files modified after 15 January 2009.
1034        /// <code>
1035        /// using (ZipFile zip = ZipFile.Read(zipArchiveName))
1036        /// {
1037        ///   zip.ExtractSelectedEntries("name = *.xml  and  mtime &gt; 2009-01-15");
1038        /// }
1039        /// </code>
1040        /// </example>
1041        /// <param name="selectionCriteria">the selection criteria for entries to extract.</param>
1042        ///
1043        /// <seealso cref="ExtractSelectedEntries(String,ExtractExistingFileAction)"/>
1044        public void ExtractSelectedEntries(String selectionCriteria)
1045        {
1046            foreach (ZipEntry e in SelectEntries(selectionCriteria))
1047            {
1048                e.Password = _Password; // possibly null
1049                e.Extract();
1050            }
1051        }
1052
1053
1054        /// <summary>
1055        /// Selects and Extracts a set of Entries from the ZipFile.
1056        /// </summary>
1057        ///
1058        /// <remarks>
1059        /// <para>
1060        /// The entries are extracted into the current working directory. When extraction would would
1061        /// overwrite an existing filesystem file, the action taken is as specified in the
1062        /// <paramref name="extractExistingFile"/> parameter.
1063        /// </para>
1064        ///
1065        /// <para>
1066        /// For information on the syntax of the string describing the entry selection criteria,
1067        /// see <see cref="AddSelectedFiles(String)" />.
1068        /// </para>
1069        /// </remarks>
1070        ///
1071        /// <example>
1072        /// This example shows how extract all XML files modified after 15 January 2009,
1073        /// overwriting any existing files.
1074        /// <code>
1075        /// using (ZipFile zip = ZipFile.Read(zipArchiveName))
1076        /// {
1077        ///   zip.ExtractSelectedEntries("name = *.xml  and  mtime &gt; 2009-01-15",
1078        ///                              ExtractExistingFileAction.OverwriteSilently);
1079        /// }
1080        /// </code>
1081        /// </example>
1082        ///
1083        /// <param name="selectionCriteria">the selection criteria for entries to extract.</param>
1084        ///
1085        /// <param name="extractExistingFile">
1086        /// The action to take if extraction would overwrite an existing file.
1087        /// </param>
1088        internal void ExtractSelectedEntries(String selectionCriteria, ExtractExistingFileAction extractExistingFile)
1089        {
1090            foreach (ZipEntry e in SelectEntries(selectionCriteria))
1091            {
1092                e.Password = _Password; // possibly null
1093                e.Extract(extractExistingFile);
1094            }
1095        }
1096
1097
1098        /// <summary>
1099        /// Selects and Extracts a set of Entries from the ZipFile.
1100        /// </summary>
1101        ///
1102        /// <remarks>
1103        /// <para>
1104        /// The entries are selected from the specified directory within the archive, and then
1105        /// extracted into the current working directory.
1106        /// </para>
1107        ///
1108        /// <para>
1109        /// If any of the files to be extracted already exist, then the action taken is as
1110        /// specified in the <see cref="ZipEntry.ExtractExistingFile"/> property on the
1111        /// corresponding ZipEntry instance.  By default, the action taken in this case is to
1112        /// throw an exception.
1113        /// </para>
1114        ///
1115        /// <para>
1116        /// For information on the syntax of the string describing the entry selection criteria,
1117        /// see <see cref="AddSelectedFiles(String)" />.
1118        /// </para>
1119        /// </remarks>
1120        ///
1121        /// <example>
1122        /// This example shows how extract all XML files modified after 15 January 2009,
1123        /// and writes them to the "unpack" directory.
1124        /// <code>
1125        /// using (ZipFile zip = ZipFile.Read(zipArchiveName))
1126        /// {
1127        ///   zip.ExtractSelectedEntries("name = *.xml  and  mtime &gt; 2009-01-15","unpack");
1128        /// }
1129        /// </code>
1130        /// </example>
1131        ///
1132        /// <param name="selectionCriteria">the selection criteria for entries to extract.</param>
1133        ///
1134        /// <param name="directoryPathInArchive">
1135        /// the directory in the archive from which to select entries. If null, then
1136        /// all directories in the archive are used.
1137        /// </param>
1138        ///
1139        /// <seealso cref="ExtractSelectedEntries(String,String,String,ExtractExistingFileAction)"/>
1140        public void ExtractSelectedEntries(String selectionCriteria, String directoryPathInArchive)
1141        {
1142            foreach (ZipEntry e in SelectEntries(selectionCriteria, directoryPathInArchive))
1143            {
1144                e.Password = _Password; // possibly null
1145                e.Extract();
1146            }
1147        }
1148
1149
1150        /// <summary>
1151        /// Selects and Extracts a set of Entries from the ZipFile.
1152        /// </summary>
1153        ///
1154        /// <remarks>
1155        /// <para>
1156        /// The entries are extracted into the specified directory. If any of the files to be
1157        /// extracted already exist, an exception will be thrown.
1158        /// </para>
1159        /// <para>
1160        /// For information on the syntax of the string describing the entry selection criteria,
1161        /// see <see cref="AddSelectedFiles(String)" />.
1162        /// </para>
1163        /// </remarks>
1164        ///
1165        /// <param name="selectionCriteria">the selection criteria for entries to extract.</param>
1166        ///
1167        /// <param name="directoryInArchive">
1168        /// the directory in the archive from which to select entries. If null, then
1169        /// all directories in the archive are used.
1170        /// </param>
1171        ///
1172        /// <param name="extractDirectory">
1173        /// the directory on the disk into which to extract. It will be created
1174        /// if it does not exist.
1175        /// </param>
1176        public void ExtractSelectedEntries(String selectionCriteria, string directoryInArchive, string extractDirectory)
1177        {
1178            foreach (ZipEntry e in SelectEntries(selectionCriteria, directoryInArchive))
1179            {
1180                e.Password = _Password; // possibly null
1181                e.Extract(extractDirectory);
1182            }
1183        }
1184
1185
1186        /// <summary>
1187        /// Selects and Extracts a set of Entries from the ZipFile.
1188        /// </summary>
1189        ///
1190        /// <remarks>
1191        /// <para>
1192        /// The entries are extracted into the specified directory. When extraction would would
1193        /// overwrite an existing filesystem file, the action taken is as specified in the
1194        /// <paramref name="extractExistingFile"/> parameter.
1195        /// </para>
1196        ///
1197        /// <para>
1198        /// For information on the syntax of the string describing the entry selection criteria,
1199        /// see <see cref="AddSelectedFiles(String)" />.
1200        /// </para>
1201        /// </remarks>
1202        ///
1203        /// <example>
1204        /// This example shows how extract all files  with an XML extension or with  a size larger than 100,000 bytes,
1205        /// and puts them in the unpack directory.  For any files that already exist in
1206        /// that destination directory, they will not be overwritten.
1207        /// <code>
1208        /// using (ZipFile zip = ZipFile.Read(zipArchiveName))
1209        /// {
1210        ///   zip.ExtractSelectedEntries("name = *.xml  or  size &gt; 100000",
1211        ///                              null,
1212        ///                              "unpack",
1213        ///                              ExtractExistingFileAction.DontOverwrite);
1214        /// }
1215        /// </code>
1216        /// </example>
1217        ///
1218        /// <param name="selectionCriteria">the selection criteria for entries to extract.</param>
1219        ///
1220        /// <param name="extractDirectory">
1221        /// The directory on the disk into which to extract. It will be created if it does not exist.
1222        /// </param>
1223        ///
1224        /// <param name="directoryPathInArchive">
1225        /// The directory in the archive from which to select entries. If null, then
1226        /// all directories in the archive are used.
1227        /// </param>
1228        ///
1229        /// <param name="extractExistingFile">
1230        /// The action to take if extraction would overwrite an existing file.
1231        /// </param>
1232        ///
1233        internal void ExtractSelectedEntries(String selectionCriteria, string directoryPathInArchive, string extractDirectory, ExtractExistingFileAction extractExistingFile)
1234        {
1235            foreach (ZipEntry e in SelectEntries(selectionCriteria, directoryPathInArchive))
1236            {
1237                e.Password = _Password; // possibly null
1238                e.Extract(extractDirectory, extractExistingFile);
1239            }
1240        }
1241
1242    }
1243
1244}
1245
1246
1247
1248namespace OfficeOpenXml.Packaging.Ionic
1249{
1250    internal abstract partial class SelectionCriterion
1251    {
1252        internal abstract bool Evaluate(ZipEntry entry);
1253    }
1254
1255
1256    internal partial class NameCriterion : SelectionCriterion
1257    {
1258        internal override bool Evaluate(ZipEntry entry)
1259        {
1260            // swap forward slashes in the entry.FileName for backslashes
1261            string transformedFileName = entry.FileName.Replace("/", "\\");
1262
1263            return _Evaluate(transformedFileName);
1264        }
1265    }
1266
1267
1268    internal partial class SizeCriterion : SelectionCriterion
1269    {
1270        internal override bool Evaluate(ZipEntry entry)
1271        {
1272            return _Evaluate(entry.UncompressedSize);
1273        }
1274    }
1275
1276    internal partial class TimeCriterion : SelectionCriterion
1277    {
1278        internal override bool Evaluate(ZipEntry entry)
1279        {
1280            DateTime x;
1281            switch (Which)
1282            {
1283                case WhichTime.atime:
1284                    x = entry.AccessedTime;
1285                    break;
1286                case WhichTime.mtime:
1287                    x = entry.ModifiedTime;
1288                    break;
1289                case WhichTime.ctime:
1290                    x = entry.CreationTime;
1291                    break;
1292                default: throw new ArgumentException("??time");
1293            }
1294            return _Evaluate(x);
1295        }
1296    }
1297
1298
1299    internal partial class TypeCriterion : SelectionCriterion
1300    {
1301        internal override bool Evaluate(ZipEntry entry)
1302        {
1303            bool result = (ObjectType == 'D')
1304                ? entry.IsDirectory
1305                : !entry.IsDirectory;
1306
1307            if (Operator != ComparisonOperator.EqualTo)
1308                result = !result;
1309            return result;
1310        }
1311    }
1312
1313#if !SILVERLIGHT
1314    internal partial class AttributesCriterion : SelectionCriterion
1315    {
1316        internal override bool Evaluate(ZipEntry entry)
1317        {
1318            FileAttributes fileAttrs = entry.Attributes;
1319            return _Evaluate(fileAttrs);
1320        }
1321    }
1322#endif
1323
1324    internal partial class CompoundCriterion : SelectionCriterion
1325    {
1326        internal override bool Evaluate(ZipEntry entry)
1327        {
1328            bool result = Left.Evaluate(entry);
1329            switch (Conjunction)
1330            {
1331                case LogicalConjunction.AND:
1332                    if (result)
1333                        result = Right.Evaluate(entry);
1334                    break;
1335                case LogicalConjunction.OR:
1336                    if (!result)
1337                        result = Right.Evaluate(entry);
1338                    break;
1339                case LogicalConjunction.XOR:
1340                    result ^= Right.Evaluate(entry);
1341                    break;
1342            }
1343            return result;
1344        }
1345    }
1346
1347
1348
1349    internal partial class FileSelector
1350    {
1351        private bool Evaluate(ZipEntry entry)
1352        {
1353            bool result = _Criterion.Evaluate(entry);
1354            return result;
1355        }
1356
1357        /// <summary>
1358        /// Retrieve the ZipEntry items in the ZipFile that conform to the specified criteria.
1359        /// </summary>
1360        /// <remarks>
1361        ///
1362        /// <para>
1363        /// This method applies the criteria set in the FileSelector instance (as described in
1364        /// the <see cref="FileSelector.SelectionCriteria"/>) to the specified ZipFile.  Using this
1365        /// method, for example, you can retrieve all entries from the given ZipFile that
1366        /// have filenames ending in .txt.
1367        /// </para>
1368        ///
1369        /// <para>
1370        /// Normally, applications would not call this method directly.  This method is used
1371        /// by the ZipFile class.
1372        /// </para>
1373        ///
1374        /// <para>
1375        /// Using the appropriate SelectionCriteria, you can retrieve entries based on size,
1376        /// time, and attributes. See <see cref="FileSelector.SelectionCriteria"/> for a
1377        /// description of the syntax of the SelectionCriteria string.
1378        /// </para>
1379        ///
1380        /// </remarks>
1381        ///
1382        /// <param name="zip">The ZipFile from which to retrieve entries.</param>
1383        ///
1384        /// <returns>a collection of ZipEntry objects that conform to the criteria.</returns>
1385        public ICollection<ZipEntry> SelectEntries(ZipFile zip)
1386        {
1387            if (zip == null)
1388                throw new ArgumentNullException("zip");
1389
1390            var list = new List<ZipEntry>();
1391
1392            foreach (ZipEntry e in zip)
1393            {
1394                if (this.Evaluate(e))
1395                    list.Add(e);
1396            }
1397
1398            return list;
1399        }
1400
1401
1402        /// <summary>
1403        /// Retrieve the ZipEntry items in the ZipFile that conform to the specified criteria.
1404        /// </summary>
1405        /// <remarks>
1406        ///
1407        /// <para>
1408        /// This method applies the criteria set in the FileSelector instance (as described in
1409        /// the <see cref="FileSelector.SelectionCriteria"/>) to the specified ZipFile.  Using this
1410        /// method, for example, you can retrieve all entries from the given ZipFile that
1411        /// have filenames ending in .txt.
1412        /// </para>
1413        ///
1414        /// <para>
1415        /// Normally, applications would not call this method directly.  This method is used
1416        /// by the ZipFile class.
1417        /// </para>
1418        ///
1419        /// <para>
1420        /// This overload allows the selection of ZipEntry instances from the ZipFile to be restricted
1421        /// to entries contained within a particular directory in the ZipFile.
1422        /// </para>
1423        ///
1424        /// <para>
1425        /// Using the appropriate SelectionCriteria, you can retrieve entries based on size,
1426        /// time, and attributes. See <see cref="FileSelector.SelectionCriteria"/> for a
1427        /// description of the syntax of the SelectionCriteria string.
1428        /// </para>
1429        ///
1430        /// </remarks>
1431        ///
1432        /// <param name="zip">The ZipFile from which to retrieve entries.</param>
1433        ///
1434        /// <param name="directoryPathInArchive">
1435        /// the directory in the archive from which to select entries. If null, then
1436        /// all directories in the archive are used.
1437        /// </param>
1438        ///
1439        /// <returns>a collection of ZipEntry objects that conform to the criteria.</returns>
1440        public ICollection<ZipEntry> SelectEntries(ZipFile zip, string directoryPathInArchive)
1441        {
1442            if (zip == null)
1443                throw new ArgumentNullException("zip");
1444
1445            var list = new List<ZipEntry>();
1446            // workitem 8559
1447            string slashSwapped = (directoryPathInArchive == null) ? null : directoryPathInArchive.Replace("/", "\\");
1448            // workitem 9174
1449            if (slashSwapped != null)
1450            {
1451                while (slashSwapped.EndsWith("\\"))
1452                    slashSwapped = slashSwapped.Substring(0, slashSwapped.Length - 1);
1453            }
1454            foreach (ZipEntry e in zip)
1455            {
1456                if (directoryPathInArchive == null || (Path.GetDirectoryName(e.FileName) == directoryPathInArchive)
1457                    || (Path.GetDirectoryName(e.FileName) == slashSwapped)) // workitem 8559
1458                    if (this.Evaluate(e))
1459                        list.Add(e);
1460            }
1461
1462            return list;
1463        }
1464
1465    }
1466}
Note: See TracBrowser for help on using the repository browser.